从Spring 3.0开始,Spring对Java校验API(Java Validation API,又称JSR-303)提供了支持。在Spring MVC中要使用Java校验API的话,并不需要什么额外的配置。只要保证在类路径下包含这个Java API的实现即可,比如Hibernate Validator。
引入hibernate-validator:
1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
校验注解
所有的注解都位于javax.validation.constraints和org.hibernate.validator.constraints包中。下表列出了这些校验注解。
使用校验注解配置实体类
新建一个表单实体类,并加上注解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
public class Form {
@NotNull
@Size(min = 5, max = 16, message = "{name.msg}")
private String name;
@NotNull()
@Email(message = "{email.msg}")
private String email;
@NotNull
@Size(min = 5, max = 16, message = "{password.msg}")
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
message属性用于添加国际化支持,接下来需要做的就是创建一个名为ValidationMessages.properties的文件(默认叫这个,不区分大小写,放在src/main/resources路径下):
1
2
3
name.msg=\u7528\u6237\u540D\u957F\u5EA6\u4E3A{min}\u5230{max}\u4E2A\u5B57\u7B26
password.msg=\u5BC6\u7801\u957F\u5EA6\u4E3A{min}\u5230{max}\u4E2A\u5B57\u7B26
email.msg=\u90AE\u7BB1\u683C\u5F0F\u4E0D\u5408\u6CD5
ValidationMessages.properties文件中每条信息的key值对应于注解中message属性占位符的 值。同时,最小和最大长度在ValidationMessages.properties文件中有自己的占位符——{min}和{max}——它们会引用@Size注解上所设置的min和max属性。
自定义校验规则
上面的注解都是较为简单的注解,实际编程中校验的规则可能五花八门。当自带的这些注解无法满足我们的需求时,我们也可以自定义校验注解。下面是一个自定义校验注解的基本格式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import javax.validation.Constraint;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MyConstraintValidator.class)
public @interface MyConstraint {
String message();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
其中@Constraint注解表明这个注解是用于规则校验的,validatedBy属性表明用什么去校验,这里我们指定的类为MyConstraintValidator。注解还包含了三个书属性,属性message指定当校验不通过的时候提示什么信息。
接下来编写MyConstraintValidator,代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, Object> {
@Override
public void initialize(MyConstraint myConstraint) {
System.out.println("my validator init");
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
System.out.println(o);
return false;
}
}
MyConstraintValidator实现了ConstraintValidator接口,该接口必须指定两个泛型,第一个泛型指的是上面定义的注解类型,第二个泛型表示校验对象的类型。MyConstraintValidator实现了ConstraintValidator接口的initialize方法和isValid方法。
initialize方法用于该校验初始化的时候进行一些操作;isValid方法用于编写校验逻辑,第一个参数为需要校验的值,第二个参数为校验上下文。
Spring JSP库
为了使用Spring JSP库,需要在JSP页首加入:
1
2
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
引入依赖:
1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/jstl/jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
相关标签如下表所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;chartset=utf-8">
<title>leanote 蚂蚁笔记</title>
</head>
<style>
input{margin-top:5px;}
label.error{color:red;}
span.error{color:red;}
input.error{border:1px solid red;}
</style>
<body>
<sf:form method="post" commanName="form"
action="${pageContext.request.contextPath}/register">
<sf:label path="name" cssErrorClass="error">用户名:</sf:label>
<sf:input path="name" cssErrorClass="error"/>
<sf:errors path="name" cssClass="error"/><br/>
邮箱:<sf:input path="email"/><sf:errors path="email" cssClass="error"/><br/>
密码:<sf:password path="password"/><sf:errors path="password" cssClass="error"/><br/>
<input type="submit" value="注册"/>
</sf:form>
</body>
</html>
<sf:form>会渲染为一个HTML<form>标签,也可以通过commandName属性构建针对某个模型对象的上下文信息。这里设为form(待会在controller中传递到此页面)。
cssClass属性可以给标签加上样式Class,用于在CSS中对其选中并修改样式。
path属性指向实体类form对应的属性名称。如果将<sf:errors/>标签的path属性设置为*的话,其将显示所有不满足校验的提示信息。
cssErrorClass属性指定校验不通过时候除了<sf:errors/>标签外的标签样式。
编写controller
Regester控制器如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import javax.validation.Valid;
import mrbird.mvc.entity.Form;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class LeanoteController {
@RequestMapping(value = "/registerindex", method = RequestMethod.GET)
public String register(Model model) {
//对应<sf:form/>标签的commandName属性值
model.addAttribute(new Form());
return "register";
}
@RequestMapping(value = "/register", method = RequestMethod.POST)
//form参数添加了@Valid注解,这会告知Spring,需要确保这个对象满足校验限制。
//Errors参数要紧跟在带有@Valid注解的参数后面
public String submit(@Valid Form form, BindingResult result) {
if (result.hasErrors()) {
// 输出校验失败信息
result.getAllErrors().stream().forEach(e -> {
FieldError fieldError = (FieldError) e;
System.out.println(((FieldError) e).getField() + " " + e.getDefaultMessage());
}
);
//出错时回到注册页面,这里不能够用重定向,不然看不到错误提示信息
return "register";
}
//校验通过,重定向到/success/{name}
return "redirect:/success/" + form.getName();
}
@RequestMapping(value = "/success/{name}", method = RequestMethod.GET)
public String success(@PathVariable String name, Model model) {
model.addAttribute(name);
return "success";
}
}
部署项目,访问:http://localhost:8080/spring/registerindex:
65384397-file_1487996138511_af03.gif