原文地址:http://www.work100.net/training/monolithic-project-iot-cloud-admin-manager-spring-validation.html
更多教程:光束云 - 免费课程
Spring Validation
序号 | 文内章节 | 视频 |
---|---|---|
1 | 概述 | - |
2 | 使用Spring-Validation验证 | - |
3 | 实例源码 | - |
请参照如上章节导航
进行阅读
1.概述
1.1.JSR-303简介
JSR-303 是 JavaEE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是 Hibernate Validator
。
此实现与 Hibernate ORM 没有任何关系。JSR-303 用于对 Java Bean 中的字段的值进行验证。 Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中使用注解的方式对表单提交的数据方便地验证。
Spring 4.0 开始支持 Bean Validation 功能。
1.2.JSR-303 基本的校验规则
空检查
@Null
验证对象是否为null
@NotNull
验证对象是否不为null
, 无法查检长度为0
的字符串@NotBlank
检查约束字符串是不是Null
还有被Trim
的长度是否大于0
,只对字符串,且会去掉前后空格@NotEmpty
检查约束元素是否为NULL
或者是EMPTY
布尔检查
@AssertTrue
验证Boolean
对象是否为true
@AssertFalse
验证Boolean
对象是否为false
长度检查
@Size(min=, max=)
验证对象(Array, Collection , Map, String)
长度是否在给定的范围之内@Length(min=, max=)
验证字符串长度介于min
和max
之间
日期检查
@Past
验证Date
和Calendar
对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期@Future
验证Date
和Calendar
对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
正则检查
@Pattern
验证String
对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式regexp
:正则表达式flags
:指定Pattern.Flag
的数组,表示正则表达式的相关选项
数值检查
注意: 建议使用在 String
,Integer
类型,不建议使用在 int
类型上,因为表单值为 “”
时无法转换为 int
,但可以转换为 String
为 “”
,Integer
为 null
@Min
验证Number
和String
对象是否大等于指定的值@Max
验证Number
和String
对象是否小等于指定的值@DecimalMax
被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal
定义的最大值的字符串表示.小数
存在精度@DecimalMin
被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal
定义的最小值的字符串表示.小数
存在精度@Digits
验证Number
和String
的构成是否合法@Digits(integer=,fraction=)
验证字符串是否是符合指定格式的数字,integer
指定整数精度,fraction
指定小数精度@Range(min=, max=)
被指定的元素必须在合适的范围内@Range(min=10000,max=50000,message=”range.bean.wage”)
@Valid
递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map
,则对其中的值部分进行校验.(是否进行递归验证)@CreditCardNumber
信用卡验证@Email
验证是否是邮件地址,如果为null
,不进行验证,算通过验证@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
2.使用Spring-Validation验证
服务器端验证是确保输入数据安全的最终屏障,所以服务端的验证永远不能缺少,接下来修改为使用 BeanValidator
进行验证。
2.1.引入依赖
需要引入如下依赖:
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
</dependency>
我们在 iot-cloud-dependencies
及 iot-cloud-commons
项目中添加上面的依赖。
其中
org.glassfish:javax.el
依赖一定要引入,否则进行单元测试时会报错
2.2.定义验证工具类
在 iot-cloud-commons
项目中添加 BeanValidator
的工具类,代码如下:
package net.work100.training.stage2.iot.cloud.commons.validator;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.*;
/**
* <p>Title: BeanValidator</p>
* <p>Description: JSR303 Validator(Hibernate Validator)工具类.</p>
*
* @author liuxiaojun
* @date 2020-03-17 16:17
* ------------------- History -------------------
* <date> <author> <desc>
* 2020-03-17 liuxiaojun 初始创建
* -----------------------------------------------
*/
@Component
public class BeanValidator {
private Validator validator;
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* 调用 JSR303 的 validate 方法, 验证失败时抛出 ConstraintViolationException.
*/
private static void validateWithException(Validator validator, Object object, Class<?>... groups) throws ConstraintViolationException {
Set constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
throw new ConstraintViolationException(constraintViolations);
}
}
/**
* 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 中为 List<message>.
*/
private static List<String> extractMessage(ConstraintViolationException e) {
return extractMessage(e.getConstraintViolations());
}
/**
* 辅助方法, 转换 Set<ConstraintViolation> 为 List<message>
*/
private static List<String> extractMessage(Set<? extends ConstraintViolation> constraintViolations) {
List<String> errorMessages = new ArrayList<>();
for (ConstraintViolation violation : constraintViolations) {
errorMessages.add(violation.getMessage());
}
return errorMessages;
}
/**
* 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 Map<property, message>.
*/
private static Map<String, String> extractPropertyAndMessage(ConstraintViolationException e) {
return extractPropertyAndMessage(e.getConstraintViolations());
}
/**
* 辅助方法, 转换 Set<ConstraintViolation> 为 Map<property, message>.
*/
private static Map<String, String> extractPropertyAndMessage(Set<? extends ConstraintViolation> constraintViolations) {
Map<String, String> errorMessages = new HashMap<>();
for (ConstraintViolation violation : constraintViolations) {
errorMessages.put(violation.getPropertyPath().toString(), violation.getMessage());
}
return errorMessages;
}
/**
* 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 List<propertyPath message>.
*/
private static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e) {
return extractPropertyAndMessageAsList(e.getConstraintViolations(), " ");
}
/**
* 辅助方法, 转换 Set<ConstraintViolations> 为 List<propertyPath message>.
*/
private static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations) {
return extractPropertyAndMessageAsList(constraintViolations, " ");
}
/**
* 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 List<propertyPath + separator + message>.
*/
private static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e, String separator) {
return extractPropertyAndMessageAsList(e.getConstraintViolations(), separator);
}
/**
* 辅助方法, 转换 Set<ConstraintViolation> 为 List<propertyPath + separator + message>.
*/
private static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations, String separator) {
List<String> errorMessages = new ArrayList<>();
for (ConstraintViolation violation : constraintViolations) {
errorMessages.add(violation.getPropertyPath() + separator + violation.getMessage());
}
return errorMessages;
}
/**
* 服务端参数有效性验证
*
* @param object 验证的实体对象
* @param groups 验证组
* @return 验证成功:返回 null;验证失败:返回错误信息
*/
public String validator(Object object, Class<?>... groups) {
try {
validateWithException(this.validator, object, groups);
} catch (ConstraintViolationException ex) {
List<String> list = extractMessage(ex);
list.add(0, "数据验证失败:");
// 封装错误消息为字符串
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
String exMsg = list.get(i);
if (i != 0) {
sb.append(String.format("%s. %s", i, exMsg)).append(list.size() > 1 ? "<br/>" : "");
} else {
sb.append(exMsg).append(list.size() > 1 ? "<br/>" : "");
}
}
return sb.toString();
}
return null;
}
}
2.3.修改实体类
修改 AuthManager
类,代码如下:
package net.work100.training.stage2.iot.cloud.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import net.work100.training.stage2.iot.cloud.commons.dto.AbstractBaseDomain;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import java.util.Date;
/**
* <p>Title: AuthManager</p>
* <p>Description: 管理员账户表</p>
* <p>Url: http://www.work100.net/training/monolithic-project-iot-cloud-admin.html</p>
*
* @author liuxiaojun
* @date 2020-02-23 22:42
* ------------------- History -------------------
* <date> <author> <desc>
* 2020-02-23 liuxiaojun 初始创建
* -----------------------------------------------
*/
@Data
public class AuthManager extends AbstractBaseDomain {
private String userKey;
@Length(min = 4, max = 20, message = "用户名必须介于 4~20 位之间")
private String userName;
@JsonIgnore
@Length(min = 6, max = 20, message = "密码必须介于 6~20 位之间")
private String password;
/**
* 状态:0=inactive, 1=active, 2=locked, 3=deleted
*/
private int status;
private boolean superuser;
/**
* 角色:admin, editor
*/
@NotEmpty(message = "角色不能空")
private String roles;
private Date modifyPasswordTime;
}
2.4.修改ManagerController验证逻辑
增加自动注入:
@Autowired
private BeanValidator beanValidator;
以 add
方法为例演示,代码如下:
@RequestMapping(value = "add", method = RequestMethod.POST)
public String add(AuthManager authManager, Model model, RedirectAttributes redirectAttributes) {
String validator = beanValidator.validator(authManager);
if (validator != null) {
model.addAttribute("baseResult", BaseResult.fail(validator));
model.addAttribute("authManager", authManager);
return "auth/manager_add";
}
// 新增处理
BaseResult baseResult = authManagerService.insert(authManager);
if (baseResult.getStatus() == HttpUtils.HTTP_STATUS_CODE_OK) {
redirectAttributes.addFlashAttribute("baseResult", baseResult);
return "redirect:/auth/manager/list";
} else {
model.addAttribute("baseResult", baseResult);
return "auth/manager_add";
}
}
2.5.注入工具类
修改 spring-context.xml
文件,注入 Validator
工具类,配置如下:
<!-- 配置 Bean Validator 定义 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean id="beanValidator" class="net.work100.training.stage2.iot.cloud.commons.validator.BeanValidator">
<property name="validator" ref="validator" />
</bean>
2.6.测试验证
注释掉 manager_add.jsp
视图中的 JS
验证,运行效果如下:
![](http://contents.work100.net/images/training/monolithic/project-iot-cloud-admin/iot-cloud-admin-auth-manager-spring-validation.jpg)
3.实例源码
实例源码已经托管到如下地址:
-
https://github.com/work100-net/training-stage2/tree/master/iot-cloud3
-
https://gitee.com/work100-net/training-stage2/tree/master/iot-cloud3
上一篇:使用Lombok
下一篇:重构Dao层
如果对课程内容感兴趣,可以扫码关注我们的
公众号
或QQ群
,及时关注我们的课程更新
![](http://contents.work100.net/images/about/contact/wechat_dingyuehao.jpg)
![](http://contents.work100.net/images/about/contact/qq_group_qrcode.jpg)