This Thymeleaf dialect reads JSR-380 annotations and modifies HTML code introducing HTML5 form validation code matching the annotations.
JSR-380 provides server-side validation for Java web applications, but client side validation
has usually been achieved using Javascript.
Fortunately, HTML5 has brought new attributes for simple browser validation.
Although HTML5 validation is not supported by all browsers, nowadays the
form validation support is quite good,
so we prefer favoring users with modern browsers and rely on server validation for users with
older browsers.
ext['thymeleaf.version'] = '3.0.7.RELEASE'
ext['thymeleaf-layout-dialect.version'] = '2.2.2'
repositories {
mavenCentral()
maven { url 'https://masa-kunikata.github.io/maven/' }
}
dependencies {
compile(group: 'javax.validation', name: 'validation-api', version:'2.0.0.Final')
compile(group: 'com.github.masa-kunikata.html5valdialect', name: 'html5valdialect', version:'3.0.3')
}
Note that 3.0.x versions are compatible with Thymeleaf 3.0.x versions.
- Spring Boot xml configuration example
<bean id="html5ValDialect" class="com.github.masa_kunikata.html5val.Html5ValDialect"/>
- Spring java configuration example
@Bean
Html5ValDialect html5ValDialect() {
return new Html5ValDialect();
}
In order to add a custom validation rule you have to implement the IValidationPerformer interface and add it to the configuration:
- Spring Boot xml configuration example
<bean id="html5ValDialect" class="com.github.masa_kunikata.html5val.Html5ValDialect">
<property name="additionalPerformers">
<set>
<bean class="fqcn.to.MyCustomPerformer" />
</set>
</property>
</bean>
- Spring java configuration example
@Bean
Html5ValDialect html5ValDialect() {
IValidationPerformer myCustomPerformer = new fqcn.to.MyCustomPerformer();
final Set<IValidationPerformer> performers = new HashSet<>();
performers.add(myCustomPerformer);
final Html5ValDialect html5ValDialect = new Html5ValDialect();
html5ValDialect.setAdditionalPerformers(performers);
return html5ValDialect;
}
Constraint | Usage | Before | After |
---|---|---|---|
javax.validation.constraints.Size | @Size(min = 5, max = 10) | <input type="text" name="code" /> | <input type="text" name="code" pattern=".{5,10}" required="required" /> |
javax.validation.constraints.Min | @Min(value = 18) | <input type="text" name="age" /> | <input type="number" name="age" min="18" /> |
javax.validation.constraints.Max | @Max(value = 65) | <input type="text" name="age" /> | <input type="number" name="age" max="65" /> |
javax.validation.constraints.Digits | @Digits(integer = 3, fraction = 2) | <input type="text" name="price" /> | <input type="text" name="price" pattern="([0-9]{1,3}\.?|\.[0-9]{1,2}|[0-9]{1,3}\.[0-9]{1,2}){1}" /> |
javax.validation.constraints.NotNull | @NotNull | <input type="text" name="code" /> | <input type="text" name="code" required="required" /> |
javax.validation.constraints.NotEmpty | @NotEmpty | <input type="text" name="code" /> | <input type="text" name="code" required="required" /> |
javax.validation.constraints.NotBlank | @NotBlank | <input type="text" name="code" /> | <input type="text" name="code" required="required" /> |
org.hibernate.validator.constraints.Range | @Range(min = 0, max = 10) | <input type="text" name="rank" /> | <input type="range" name="rank" min="0" max="10" /> |
org.hibernate.validator.constraints.Length | @Length(min = 1, max = 10) | <input type="text" name="rank" /> | <input type="text" name="rank" pattern=".{1,10}" required="required" /> |
javax.validation.constraints.Email | <input type="text" name="userEmail" /> | <input type="email" name="userEmail" /> | |
org.hibernate.validator.constraints.URL | @URL(protocol = "https") | <input type="text" name="website" /> | <input type="text" name="website" pattern="^https://.+(:[0-9]+)?(/.*)?" /> |
class UserFormBean {
@Email
@NotEmpty
private String username;
@Size(min = 5, max = 10)
private String code;
@Min(value = 18)
@Max(value = 100)
@NotNull
private Integer age;
@Range(min = 0, max = 10)
private Integer highSchoolMark;
@URL(regexp = URLPerformer.URL_REGEXP)
private String personalWebPage;
@URL(protocol = "http", host = "localhost", port = 8080)
private String applicationWebPage;
...
}
@RequestMapping("/userCreate.html")
public String userCreate(Model model) {
model.addAttribute("userFormBean", new UserFormBean());
return "userCreate.html";
}
<form action="userSave.do" val:validate="${userFormBean}" method="post">
<p>
<label for="username">E-mail</label>
<input type="text" name="username" id="username" />
</p>
<p>
<label for="code">Code</label>
<input type="text" name="code" id="code" />
</p>
<p>
<label for="age">Age</label>
<input type="text" name="age" id="age" />
</p>
<p>
<label for="highSchoolMark">Mark</label>
<input type="text" name="highSchoolMark" id="highSchoolMark" />
</p>
<p>
<label for="personalWebPage">Personal Web Page</label>
<input type="text" name="personalWebPage" id="personalWebPage" />
</p>
<p>
<label for="applicationWebPage">Demo application Web Page</label>
<input type="text" name="applicationWebPage" id="applicationWebPage" />
</p>
<input type="submit" />
</form>
@RequestMapping(value = "/userSave.do", method = RequestMethod.POST)
public String userSave(@Valid UserFormBean userForm) {
userDAO.save(userForm.buildUser());
return "redirect:/userList.html";
}
In order to make the example simpler, th:field is not used, but you usually would combine val:validate with th:object and th:errors.
- Install JDK and Gradle.
- Download source code
- At the command prompt, execute
cd html5valdialect-example-webapp
and make it current directory. - Run
gradle bootRun
- Open http://localhost:8080/ (User:
user
Password:password
)
This software is licensed under the [Apache License 2.0] (http://www.apache.org/licenses/LICENSE-2.0.html).