九、Spring Boot数据校验
9.1 什么是数据校验?
-
数据校验? 数据校验就是在应用程序中,对输入进来的数据做语义分析判断,阻挡不符合规则的数据,放行符合规则的数据,以确保被保存的数据符合我们的数据存储规则。 -
数据校验的方式? 在Spring MVC中做数据校验有两种方式:一种是 Spring 自带的验证框架,另外一种就是是利用 JSR 实现数据校验。 -
初识JSR JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。 也就是说,JSR只是一个规范,它提供了完整的一套API,通过标注给对象属性来添加约束。Hibernate Validator就是对JSR 规范所有注解的具体实现,除此之外还有一些附加的约束注解。当然,用户还可以自定义约束注解。
9.2 JSR-303校验标准
JSR-303 是JAVAEE6中的一项子规范,叫做Bean Validation规范,为Bean验证定义了元数据模型和API。默认的元数据模型是通过Annotations来描述的,但是也可以使用XML来重载或者扩展, 我们一般推荐使用注解的方式来进行验证。
Hibernate Validator 是 Bean Validation 的参考实现 。 Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint的实现,除此之外还有一些附加的constraint。
此实现与Hibernate ORM没有任何关系。 JSR 303 用于对 Java Bean 中的字段的值进行验证。 Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中对表单提交的数据直接进行验证。
9.3 JSR-303常用校验注解
Bean Validation 中内置的 constraint:
constraint | 描述 |
---|
@Null | 被注释的元素必须为null | @NotNull | 被注释的元素必须不为null | @AssertTrue | 被注释的元素必须为true | @AssertFalse | 被注释的元素必须为false | @Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 | @Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 | @DecimalMin(value) | 被注释的必须是一个数字,其值必须大于等于指定的最小值 | @DecimalMax(value) | 被注释的必须是一个数字,其值必须小于等于指定的最大值 | @Size(max,min) | 被注释的元素的大小必须在指定的范围内 | @Digits(integer,fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 | @Past | 被注释的元素必须是一个过去的日期 | @Future | 被注释的元素必须是一个将来的日期 | @Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
Hibernate Validator 附加的 constraint:
constraint | 描述 |
---|
@Email | 被注释的元素必须是电子邮箱地址 | @Length | 被注释的字符串的大小必须在指定的范围内 | @NotEmpty | 被注释的字符串必须非空 | @Range | 被注释的元素必须在合适的范围内 |
9.4 基于Hibernate-validator校验框架实现的服务器端数据校验
在实际的开发过程中,总是会遇到这样的情况,用户在登录时忘记输入了用户名或者是忘记输入了密码,这个时候我们的后台是不允许用户直接登录的。鉴于这些“马马虎虎”的用户,我们必须给予他们一些提醒或者警告,也就是说,提醒他们只有在完完全全正确的输入用户名和密码后,才可以登录成功!
那么,如何实现这样的数据校验呢?下面上代码…
-
导入相关依赖 这里是基于JSR-303实现数据校验的,所以这两个依赖决不能少!否则校验不会生效!!
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.22.Final</version>
</dependency>
-
对实体类SystemUserInfo上的部分属性添加注解 因为在验证的过程中,可能会用到的属性是不确定的,所以我一般习惯于将所有的字段全部添加注解,以防以后还需要多次修改(小声逼逼:如果你也懒,那就跟小编一样吧哈哈哈)。 package cn.boot.pojo;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;
public class SystemUserinfo implements Serializable {
private String userinfoUid;
@NotEmpty(message = "用户名不能为空")
private String userinfoLoginid;
@NotEmpty(message = "姓名不能为空")
private String userinfoName;
@NotEmpty(message = "密码不能为空")
private String userinfoPassword;
@NotEmpty(message = "性别不能为空")
private String userinfoSex;
@NotEmpty(message = "邮箱不能为空")
private String userinfoEmail;
@NotEmpty(message = "手机号不能为空")
private String userinfoMobile;
@NotEmpty(message = "状态不能为空")
private Short userinfoStatus;
@NotEmpty(message = "角色不能为空")
private String userinfoRole;
private SystemRole systemRole;
}
-
对控制层SystemUserinfoController类中校验信息进行绑定
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/doLogin")
public String doLogin(@Valid SystemUserinfo systemUserinfo, BindingResult bindingResult, HttpServletRequest request){
if(bindingResult.hasErrors()) {
List<ObjectError> listError = bindingResult.getAllErrors();
for (ObjectError objectError : listError) {
FieldError fieldError = (FieldError) objectError;
request.setAttribute(fieldError.getField(),objectError.getDefaultMessage());
}
return "login";
}else {
SystemUserinfo systemUserinfo1 = systemUserinfoService.login(systemUserinfo.getUserinfoLoginid(),systemUserinfo.getUserinfoPassword());
if (systemUserinfo1 == null) {
request.setAttribute("MSG", "用户名或密码错误!");
return "login";
}
return "redirect:/selectAllByJS";
}
}
-
在登录页login.html视图中显示 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>易买网 - 首页</title>
<link type="text/css" rel="stylesheet" href="css/style.css" />
<script type="text/javascript" src="scripts/function.js"></script>
</head>
<body>
<div id="register" class="wrap">
<div class="shadow">
<em class="corner lb"></em>
<em class="corner rt"></em>
<div class="box">
<form id="loginForm" method="post" action="doLogin" onsubmit="return checkValidate()">
<table>
<tr>
<td class="field">用户名:</td>
<td><input class="text" type="text" id="userinfoLoginid" name="userinfoLoginid" onfocus="FocusItem(this)" onblur="CheckItem(this);" /><span style="display: inline-block" th:text="${userinfoLoginid}"></span></td>
</tr>
<tr>
<td class="field">登录密码:</td>
<td><input class="text" type="password" id="userinfoPassword" name="userinfoPassword" onfocus="FocusItem(this)" onblur="CheckItem(this);" /><span style="display: inline-block" th:text="${userinfoPassword}"></span></td>
</tr>
<tr>
<td></td>
<td><label class="ui-green"><input type="submit" name="submit" value="立即登录" />
</label>
<label th:text="${MSG}" style="color: red"></label>
</td>
</tr>
</table>
</form>
</div>
</div>
<div class="clear"></div>
</div>
</body>
</html>
9.5 分组数据校验
前面我们校验了用户名和密码,在实际开发的过程中,难免会遇到对一个实体类的属性,不同的请求会有不同的校验规则的场景。
就比如说,当用户注册时,用户的id需要校验是否为空,因为这个唯一的id往往是由系统自己生成的。但是当用户在修改密码时,又需要我们传入一个id来作为where语句的条件去判断更新,这个时候我们就要使用分组校验了。
在遇到需要分组校验的时候,我们通过注解中groups属性来设置该校验注解的分组,groups的值要求必须是一个类对象,一般我们采取创建多个空接口的方法来进行分组。当然,如果分组较多的话就可以将这个用以校验分组的接口放在同一个类下进行管理。
-
用以登录的接口: package cn.boot.util;
public interface LoginGroup {
}
-
用以更新用户的接口 package cn.boot.util;
public interface UpdateGroup {
}
-
用以添加用户的接口 package cn.boot.util;
public interface AddGroup {
}
-
在实体类SystemUserInfo中的注解 分组的原则就是,用到哪几个属性,就给哪几个属性归为一类。 package cn.boot.pojo;
import cn.boot.util.AddGroup;
import cn.boot.util.LoginGroup;
import cn.boot.util.UpdateGroup;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;
public class SystemUserinfo implements Serializable {
private String userinfoUid;
@NotEmpty(message = "用户名不能为空",groups = {LoginGroup.class, UpdateGroup.class, AddGroup.class})
private String userinfoLoginid;
@NotEmpty(message = "姓名不能为空",groups = {UpdateGroup.class,AddGroup.class})
private String userinfoName;
@NotEmpty(message = "密码不能为空",groups = {LoginGroup.class,UpdateGroup.class,AddGroup.class})
private String userinfoPassword;
@NotEmpty(message = "性别不能为空",groups = {UpdateGroup.class,AddGroup.class})
private String userinfoSex;
@NotEmpty(message = "邮箱不能为空",groups = {UpdateGroup.class,AddGroup.class})
private String userinfoEmail;
@NotEmpty(message = "手机号不能为空",groups = {UpdateGroup.class,AddGroup.class})
private String userinfoMobile;
@NotEmpty(message = "状态不能为空",groups = {UpdateGroup.class})
private Short userinfoStatus;
@NotEmpty(message = "角色不能为空",groups = {UpdateGroup.class,AddGroup.class})
private String userinfoRole;
private SystemRole systemRole;
}
-
对控制层SystemUserinfoController类中校验信息进行绑定
-
添加用户
@RequestMapping(method = RequestMethod.GET,value = "/toAddUserInfo")
public String toAddUserInfo(HttpServletRequest request){
List<SystemRole> listRole = systemRoleService.selectAll();
request.setAttribute("listRole",listRole);
return "ebuy/addUserinfo";
}
@RequestMapping(method = RequestMethod.POST,value = "/doAddUserInfo")
public String doAddUserInfo(@Validated(value = {AddGroup.class}) SystemUserinfo systemUserinfo, BindingResult bindingResult, HttpServletRequest request, ModelAndView modelAndView){
if (bindingResult.hasErrors()){
List<SystemRole> listRole = systemRoleService.selectAll();
request.setAttribute("listRole",listRole);
List<ObjectError> listError = bindingResult.getAllErrors();
for (ObjectError objectError:listError){
FieldError fieldError = (FieldError) objectError;
request.setAttribute(fieldError.getField(),objectError.getDefaultMessage());
}
return "ebuy/addUserinfo";
}else{
int r = systemUserinfoService.insert(systemUserinfo);
if (r == 1){
return "redirect:/selectAllByJS";
}
request.setAttribute("msg","添加用户失败,请重新添加!");
return "ebuy/addUserinfo";
}
}
-
修改用户信息
@RequestMapping(method = RequestMethod.GET,value = "/toUpdateUserInfo")
public String toUpdateUserInfo(String userinfoUid,HttpServletRequest request){
SystemUserinfo systemUserinfo = systemUserinfoService.selectByPrimaryKey(userinfoUid);
List<SystemRole> listRole = systemRoleService.selectAll();
request.setAttribute("listRole",listRole);
request.setAttribute("systemUserinfo",systemUserinfo);
return "ebuy/updateUserInfo";
}
@RequestMapping(method = RequestMethod.POST,value = "/doUpdateUserInfo")
public String doUpdateUserInfo(@Validated(value = {UpdateGroup.class}) SystemUserinfo systemUserinfo,BindingResult bindingResult, HttpServletRequest request) {
if (bindingResult.hasErrors()) {
List<SystemRole> listRole = systemRoleService.selectAll();
request.setAttribute("listRole", listRole);
List<ObjectError> listError = bindingResult.getAllErrors();
for (ObjectError objectError:listError){
FieldError fieldError = (FieldError) objectError;
request.setAttribute(fieldError.getField(),objectError.getDefaultMessage());
}
return "ebuy/updateUserInfo";
} else {
int r = systemUserinfoService.updateByPrimaryKey(systemUserinfo);
if (r > 0) {
return "redirect:/selectAllByJS";
}
request.setAttribute("msg", "更新用户信息失败!");
return "ebuy/updateUserInfo";
}
}
-
添加用户addUserinfo.html <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加用户信息</title>
</head>
<body>
<div style="color: red" th:text="${msg}"></div>
<div style="width: 700px;margin: 50px auto;">
<form method="post" action="doAddUserInfo">
登录名:<input type="text" name="userinfoLoginid" />
<span style="color: red" th:text="${userinfoLoginid}"></span>
<br/><br/>
姓名:<input type="text" name="userinfoName" />
<span style="color: red" th:text="${userinfoName}"></span>
<br/><br/>
密码:<input type="password" name="userinfoPassword" />
<span style="color: red" th:text="${userinfoPassword}"></span>
<br/><br/>
性别:
<input type="radio" name="userinfoSex" value="男" />男
<input type="radio" name="userinfoSex" value="女"/> 女
<span style="color: red" th:text="${userinfoSex}"></span>
<br/><br/>
邮箱:<input type="text" name="userinfoEmail" />
<span style="color: red" th:text="${userinfoEmail}"></span>
<br/><br/>
电话:<input type="text" name="userinfoMobile" />
<span style="color: red" th:text="${userinfoMobile}"></span>
<br/><br/>
角色:
<select name="userinfoRole" >
<option value="">--请选择--</option>
<option th:each="role:${listRole}" th:value="${role.roleId}" th:text="${role.roleName}"></option>
</select>
<span style="color: red" th:text="${userinfoRole}"></span>
<br/><br/>
<input type="submit" value="保存"/>
</form>
</div>
</body>
</html>
-
更新用户信息updateUserinfo.html <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>更新用户信息</title>
</head>
<body>
<div style="color: red" th:text="${msg}"></div>
<div style="width: 700px;margin: 50px auto;">
<form method="post" action="doUpdateUserInfo">
<input type="hidden" id="userinfoUid" name="userinfoUid" th:value="${systemUserinfo.userinfoUid}"/>
登录名:<input type="text" id="userinfoLoginid" name="userinfoLoginid" th:value="${systemUserinfo.userinfoLoginid}"/>
<span style="color: red" th:text="${userinfoLoginid}"></span>
<br/><br/>
姓名:<input type="text" id="userinfoName" name="userinfoName" th:value="${systemUserinfo.userinfoName}"/>
<span style="color: red" th:text="${userinfoName}"></span>
<br/><br/>
密码:<input type="password" id="userinfoPassword" name="userinfoPassword" th:value="${systemUserinfo.userinfoPassword}"/>
<span style="color: red" th:text="${userinfoPassword}"></span>
<br/><br/>
性别:
<input type="radio" name="userinfoSex" value="男" th:checked="${systemUserinfo.userinfoSex}==男"/>男
<input type="radio" name="userinfoSex" value="女" th:checked="${systemUserinfo.userinfoSex}==女"/>女
<span style="color: red" th:text="${userinfoSex}"></span>
<br/><br/>
邮箱:<input type="text" name="userinfoEmail" th:value="${systemUserinfo.userinfoEmail}"/>
<span style="color: red" th:text="${userinfoEmail}"></span>
<br/><br/>
电话:<input type="text" name="userinfoMobile" th:value="${systemUserinfo.userinfoMobile}"/>
<span style="color: red" th:text="${userinfoMobile}"></span>
<br/><br/>
角色:
<select name="userinfoRole" >
<option th:each="role:${listRole}" th:value="${role.roleId}" th:text="${role.roleName}"></option>
</select>
<span style="color: red" th:text="${userinfoRole}"></span>
<br/><br/>
<input type="submit" value="更新"/>
</form>
</div>
</body>
</html>
|