Spring Boot系列JSR-303基于由Hibernate-Validitor实现的后端服务器数据校验

Posted 一宿君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot系列JSR-303基于由Hibernate-Validitor实现的后端服务器数据校验相关的知识,希望对你有一定的参考价值。

1、JSR-303简介

JSR是Java Specification Requests的缩写,意思是Java 规范提案,JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。

此实现与 Hibernate ORM 没有任何关系。 JSR 303 用于对 Java Bean 中的字段的值进行验证。 Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中对表单提交的数据方便地验证。

即,JSR 303,Bean Validation规范 ,为Bean验证定义了元数据模型API。默认的元数据模型是通过Annotations来描述的,但是也可以使用XML来重载或者扩展, 推荐使用注解的方式进行验证。

2、JSR-303常用校验注解规则

空检查:

注解说明
@Null元素必须为null
@NotNull元素必须不为null
@NotBlank(message)字符串不能为null,且trim后不能为空字符串(长度非0),message加以说明
@NotEmpty(message)被注释的字符串、集合、数组不能为空(长度非0)

Boolean检查 :

注解说明
@AsserrtFalse验证Boolean对象是否为false
@AssertTrue验证Boolean对象是否为true

长度检查 :

注解说明
@Size(min,max,message)元素大小必须在指定范围内,message加以说明
@Length(min,max,message)必须是字符串,其值在指定范围内,message加以说明

日期检查 :

注解说明
@Past元素必须是一个过去的日期
@Furture元素必须是一个将来的日期
@Pattern元素符合指定的正则表达式

数值检查 (建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为 “”,Integer为null ):

注解说明
@Min(value)元素必须为数字,其值大于等于指定value
@Max(value)元素必须为数字,其值小于等于指定value
@DecimalMax(value)元素必须为数字,最大值为指定value
@DecimalMin(value)元素必须为数字,最小值为指定value
@Digits(integer,fraction)元素必须为数字,其值必须在可接受的范围内

以上是Bean Validation 中内置的 constraint。

Hibernate Validator 附加的 constraint

注解说明
@Email元素必须为电子邮箱格式
@Range元素在合适的范围内
@Safehtml元素必须是安全Html
@URL元素必须是有效URL

3、JSR-303如何使用?

3.1、首先导入相关依赖(规范实现

JSR 303 是Bean验证的规范 ,Hibernate Validator 是该规范的参考实现,如果只有规范没有实现,则校验规范不会生效。

pom.xml

		<!--JSR-303校验规范-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>

        <!--JSR-303基于由Hibernate-validator规范实现-->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.22.Final</version>
        </dependency>

3.2、对实体类SystemUserinfo部分字段进行校验注解

package com.kdcrm.pojo;

import javax.validation.constraints.NotEmpty;
import java.io.Serializable;

public class SystemUserinfo implements Serializable {

    private String userinfoUid;

    @NotEmpty(message = "用户名不能为空")
    private String userinfoLoginid;

    private String userinfoName;

    @NotEmpty(message = "登录密码不能为空")
    private String userinfoPassword;

    private String userinfoSex;

    private String userinfoEmail;

    private String userinfoMobile;

    private Short userinfoStatus;

    private String userinfoRoleid;

    private SystemRole systemRole;
    
    //setter和getter方法省略
}

我们暂时先对用户名(登录id)和登录密码两个字段进行@NotEmpty注解,用于登录界面用户名和密码的非可校验注解。

3.3、编写登录界面视图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="login" class="wrap">
	<div class="shadow">
		<em class="corner lb"></em>
		<em class="corner rt"></em>
		<div class="box">
			<h1>欢迎回到易买网</h1>
			<form id="loginForm" method="post" action="doLogin" onsubmit="return checkForm(this)">
				<table>
					<tr>
						<td class="field">用户名:</td>
						<td><input class="text" type="text" 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"  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>
</body>
</html>


登录界面:

3.4、编写控制层SystemUserinfoController(登录控制方法)

    //跳转至登录界面
	@GetMapping("/toLogin")
    public String toLogin(){
        return "login";
    }
    
    //对登录信息进行处理
    @RequestMapping("/doLogin")
    public ModelAndView doLogin(@Valid SystemUserinfo systemUserinfo, BindingResult bindingResult, HttpServletRequest request, ModelAndView mav){

        //当前是否是错误
        if(bindingResult.hasErrors()) {
            //获取所有错误信息
            List<ObjectError> listError = bindingResult.getAllErrors();
            //创建存储错误信息的map
            Map<String, String> mapError = new HashMap<>();
            //遍历错误信息集合
            for (ObjectError objectError : listError) {
                //强转为FieldError类型(用于获取错误字段名)
                FieldError fieldError = (FieldError) objectError;
                //校验字段 : 校验信息
                System.out.println(fieldError.getField() + "\\t" + objectError.getDefaultMessage());
                //将要校验的字段和校验信息存入到map集合中
                mapError.put(fieldError.getField(), objectError.getDefaultMessage());
                //将map集合存入到ModelAndView中(其实内部机制也是将其存入到request作用域中)
                mav.addAllObjects(mapError);
            }
            mav.setViewName("login");
            return mav;
        }else {
            SystemUserinfo systemUserinfo1 = systemUserinfoService.login(systemUserinfo);
            if(systemUserinfo1 != null){
                System.out.println("登录成功!");
                mav.addObject("USERS",systemUserinfo1);
                mav.setViewName("redirect:/selectAll");
            }else {
                System.out.println("输入了,但是用户名或密码错误!");
                mav.addObject("MSG","用户名或密码错误!");
                mav.setViewName("login");
            }
            return mav;
        }
    }



实际上此处将出现错误信息的字段名和校验信息存入到request作用中还有一种简单的做法,就是将字段名和错误信息直接存入到request作用域中,如下:

			//获取所有错误信息
            List<ObjectError> listError = bindingResult.getAllErrors();
          
            //遍历错误信息集合
            for (ObjectError objectError : listError) {
                //强转为FieldError类型(用于获取错误字段名)
                FieldError fieldError = (FieldError) objectError;
                //校验字段 : 校验信息
                System.out.println(fieldError.getField() + "\\t" + objectError.getDefaultMessage());
               //直接存入request作用域中
               request.setAttribute(fieldError.getField(),objectError.getDefaultMessage());
            }

3.5、登录校验测试


查看控制台:

3.6、对实体类SystemUserinfo全部字段进行校验注解

上述登录演示说明我们的在后端的校验生效了,但是我们要考虑全面,对于实体类SystemUserinfo中的字段我们不可能只针对登录需要的两个字段进行校验,在添加、修改用户信息时,基本就需要用到全部字段的校验了,所有我们要对SystemUserinfo实体类中的所有字段进行非空注解信息,如下:

package com.kdcrm.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;

    //状态暂时不考虑
    private Short userinfoStatus;

    @NotEmpty(message = "角色id不能为空")
    private String userinfoRoleid;

    private SystemRole systemRole;
    
    //setter和getters方法省略
}

3.7、编写修改用户信息界面updateUser.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en" >
<head>
    <meta charset="UTF-8">
    <title>updateUser</title>
</head>
<body>
    <form method="post" action="/doUpdateUser" id="userForm" style="margin: 100px auto;margin-left: 400px">
        <input type="hidden" name="userinfoUid" th:value="${systemUserinfo.userinfoUid}"/>
        登录名:<input type="text" id="userinfoLoginid" name="userinfoLoginid" th:value="${systemUserinfo.userinfoLoginid}" /><span th:text="${userinfoLoginid}"/><br/>
        姓名:<input type="text" id="userinfoName" name="userinfoName" th:value="${systemUserinfo.userinfoName}" /><span th:text="${userinfoName}"/><br/>
        密码:<input type="password" id="userinfoPassword" name="userinfoPassword" th:value="${systemUserinfo.userinfoPassword}"/><span th:text="${userinfoPassword}"/><br/>
        性别:<input type="radio" name="userinfoSex" th:checked="${systemUserinfo.userinfoSex == ''}"  value=""/><input type="radio" name="userinfoSex" th:checked="${systemUserinfo.userinfoSex == ''}" value=""/><span th:text="${userinfoSex}"/><br/>
        邮箱:Spring Boot 使用 JSR303 实现参数验证

手把手写一个基于Spring Boot框架下的参数校验组件(JSR-303)

Spring/Spring boot JSR-303验证框架 之 hibernate-validator

Spring/Spring boot JSR-303验证框架 之 hibernate-validator

spring-boot学习三:运用@configurationProperties与@Validated进行JSR303数据格式校验

在使用 JSR-303 验证表单时使用 I18n 消息