0%

6.4 数据校验 6.4.1 Spring的Validation校验框架

6.4 数据校验

输入校验

遇到非法输入时应用程序直接返回,提用户必须重新输入,也就是将那些非法输入过滤掉。这种对非法输入的过滤,就是输入校验,也称为数据校验”
输入校验分为客户端校验服务器端校验,

  • 客户端校验主要是过滤正常用户的误操作通常通过 JavaScript代码完成;
  • 服务器端校验是整个应用阻止非法数据的最后防线,主要通过在应用中编程实现

Spring MVC提供了强大的数据校验功能,其中有两种方法可以验证输入:

  • 一种是利用 Spring自带的 Validation校验框架;
  • 另一种是利用JSR303(Java验证规范)实现校验功能。

6.4.1 Spring的Validation校验框架

Spring拥有自己独立的数据校验框架。Spring在进行数据绑定时,可同时调用校验框架来完成数据校验工作。
Spring的校验框架在org.springframework.validation包中,其中重要的接口和类如下

Validator接口

Validator。最重要的接口。该接口有两个方法:

方法 描述
boolean supports(Class<?> clazz) 该校验器能够对clazz类型的对象进行校验
void validate(Object target,Errors errors) 对目标类target进行校验,并将校验错误记录在errors当中。
## Errors接口 ##
ErrorsSpring用来存放错误信息的接口。Spring MVC框架在将请求数据绑定到入参对象后,就会调用校验框架实施校验,而校验结果保存在处理方法的入参对象之后的参数对象当中。这个保存校验结果的参数对象必须是Errors或者BindingResult类型。一个Errors对象中包含了一系列的FieldErrorObjectError对象。FieldError表示与被校验的对象中的某个属性相关的一个错误。BindingResult扩展了Errors接口,同时可以获取数据绑定结果对象的信息.
## ValidationUtils工具类 ##
ValidationUtilsSpring提供的一个关于校验的工具类。它提供了多个为 Errors对象保存错误的方法。
## LocalValidatorFactoryBean类 ##
LocalValidatorFactoryBean位于org.springframework.validation.beanvalidation包中,该类既实现了SpringValidator接口,也实现了JSR303Validator接口。只要在Spring容器中定义一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的Bean中。定义一个LocalValidatorFactoryBeanBean非常简单,如下代码所示:

<mvc:annotation-driven/>会默认装配好一个LocalValidatorFactoryBean,所以在实际开发中不需要手动配置LocalValidatorFactoryBean。需要注意的是,Spring本身没有提供JSR303的实现,如果要使用JSR303完成验证,则必须将JSR303的实现(注入Hibernate Validator)jar文件加入到应用程序的类路径下,这样Spring会自动加载并配好JSR303的实现.

实例 表单输入校验

loginForm.jsp

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
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试Validator接口验证</title>
</head>
<body>
<h3>登录页面</h3>
<!-- 绑定到user对象 -->
<form:form modelAttribute="user" method="post" action="login">
<table>
<tr>
<td>登录名:</td>
<!-- 绑定user对象的loginname属性 -->
<td><form:input path="loginname" /></td>
<!-- 显示loginname属性的错误信息 -->
<td><form:errors path="loginname" cssStyle="color:red" /></td>
</tr>
<tr>
<td>密码:</td>
<!-- 绑定user对象的password属性 -->
<td><form:input path="password" /></td>
<!-- 显示password属性的错误信息 -->
<td><form:errors path="password" cssStyle="color:red" /></td>
</tr>
<tr>
<td><input type="submit" value="提交" /></td>
</tr>
</table>
</form:form>
</body>
</html>

页面使用<form: errors>标签显示属性的错误信息。

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 域对象,实现序列化接口
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
private String loginname;
private String password;
public User()
{
super();
// TODO Auto-generated constructor stub
}
// 此处省略getter和setter方法,请自己补上
@Override
public String toString()
{
return "User [loginname=" + loginname + ", password=" + password + "]";
}
}

UserValidator.java

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
// 实现Spring的Validator接口
@Repository("userValidator")
public class UserValidator
implements Validator
{
// 该校验器能够对clazz类型的对象进行校验。
@Override
public boolean supports(Class<?> clazz)
{
// User指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。
return User.class.isAssignableFrom(clazz);
}
// 对目标类target进行校验,并将校验错误记录在errors当中
@Override
public void validate(Object target, Errors errors)
{
/**
* 使用ValidationUtils中的一个静态方法rejectIfEmpty()来对loginname属性进行校验,
* 假若'loginname'属性是 null 或者空字符串的话,就拒绝验证通过 。
*/
ValidationUtils.rejectIfEmpty(errors, "loginname", null, "登录名不能为空");
ValidationUtils.rejectIfEmpty(errors, "password", null, "密码不能为空");
User user = (User) target;
if (user.getLoginname().length() > 10)
{
// 使用Errors的rejectValue方法验证
errors.rejectValue("loginname", null, "用户名不能超过10个字符");
}
if (user.getPassword() != null && !user.getPassword().equals("")
&& user.getPassword().length() < 6)
{
errors.rejectValue("password", null, "密码不能小于6位");
}
}
}

UserValidator实现了SpringValidator接口,其可以对User对象进行数据校验,并分别使用ValidationUtilsrejectIfEmpty方法和ErrorsrejectValue方法对User进行数据校验。
写在类定义上面的@Repository("userValidator")注解将该对象声明为Spring容器中的一个Bean,名字为”userValidator“。

UserController.java

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
@Controller
public class UserController {
// 注入UserValidator对象
@Autowired
@Qualifier("userValidator")
private UserValidator userValidator;
@GetMapping(value = "/loginForm")
public String loginForm(Model model)
{
// 创建一个user对象给登录表单使用
User user = new User();
// 添加到模型中,登陆表单会绑定这个对象
model.addAttribute("user", user);
// 跳转到登录页面
return "loginForm";
}
@PostMapping(value = "/login")
// @ModelAttribute User user表示使用user来绑定表单提交的数据
public String login(@ModelAttribute
User user, Model model, Errors errors)
{
System.out.println(user);
// 更新模型中的数据
model.addAttribute("user", user);
// 调用userValidator的验证方法
userValidator.validate(user, errors);
// 如果验证不通过跳转到loginForm视图
if (errors.hasErrors())
{
// 重新登录
return "loginForm";
}
return "success";
}
}

login方法对传进来的参数进行校验,注意方法的最后一个参数errors,该参数是个Spring校验框架的Errors对象。在该方法中调用了之前写的userValidator类进行数据校验,如果校验失败,则跳转到”loginForm“视图.

测试

错误填写

这里有一张图片

显示效果

这里有一张图片

最后说一句

由于早期Spring就提供了Validation框架,所以之前的很多应用都使用Validation框架进行数据校验。由于Validation框架通过硬编码完成数据校验,在实际开发中会显得比较麻烦,因此现代开发更加推荐使用JSR 303完成数据校验

原文链接: 6.4 数据校验 6.4.1 Spring的Validation校验框架