SpringMvc数据校验@Valid等注解的使用与工具类抽取
最近在重构老项目的代码,发现校验入参占用了很多代码,之前我对这一块的认识局限于使用StringUtils等工具来多个if块进行判断,代码是没什么问题,但是总写这些令人生烦,毕竟写代码也要讲究优雅的嘛,于是呢我就研究了一下JavaEE Api 上的校验类,基本上推翻了我之前对校验注解之类的认识,在这里记录一下所得。
@NotNull@NotBlank@NotEmpty这三个注解的区别以及使用@NotNull:校验入参不能为空,无法正确校检长度为0的字符串或以完全为空格的字符串@NotBlank: 包含@NotNull的功能,可以校验字符串内容是否为空@NotEmpty: 校验传入集合是否为空当以上几个注解校验不被满足的时候,就会抛出异常,打印出默认的消息内容,
如
age not be null这样的错误信息想自定义错误信息可以如:
@NotNull(message = "信息不能为空")来定义@Valid的使用如果入参为一个对象,想校验这个对象内容是否正确的时候,会用到1节中所讲的几个注解,
但是此时会有一个问题:如果不使用
@Valid注解,1节中的注解在入参过程中是不生效的,只有保存的时候才会被校验(不排除PO和DTO是同一个对象的情况)当然,这有一个大前提,就是没有其它对入参校验的方法执行。
**所以如果是简单为了让异常报出来而不是直接返回的时候可以只用
@Valid自定义校验与错误信息的处理
(1)使用
BindingResult对象接收被@Valid校验不通过的错误信息/**
* 使用BindingResult与@Valid配合的方式
* 拿到错误信息,带部分堆栈
*/
@PostMapping("/validationTest6")
public String validationTest6(@RequestBody @Valid User user,
BindingResult result){
if(result.hasErrors()){
//取一条错误信息
ObjectError next = result.getAllErrors().iterator().next();
log.error("error={}", next);
//后边可以自己返回错误信息也可以自定义
return next.toString();
}
//do somethings
return "校验通过";
} /**
* 使用BindingResult与@Valid配合的方式
* 只拿到错误信息
*/
@PostMapping("/validationTest7")
public String validationTest7(@RequestBody @Valid User user,
BindingResult result){
if(result.hasErrors()){
//取一条错误信息
ObjectError next = result.getAllErrors().iterator().next();
String defaultMessage = next.getDefaultMessage();
log.error("error={}", defaultMessage);
//后边可以自己返回错误信息也可以自定义
return defaultMessage;
}
//do somethings
return "校验通过";
}
(2)使用Validator对象,不信赖于
@Valid的实现/**
* 使用Validator未抽取工具类时的实现
*/
@PostMapping("/validationTest9")
public String validationTest9(@RequestBody User user){
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<User>> validate = validator.validate(user);
if(!validate.isEmpty()){
ConstraintViolation<User> next = validate.iterator().next();
String message = next.getMessage();
log.error("error={}",message);
return message;
}
//do somethings
return "校验通过";
}
上边给大家介绍了两种方法,其中第二种看起来代码更多一些,其实这应该就是没有使用
@Valid的问题了,因为你并不知道@Valid注解校验错误代码有多少。效率基本差不多少下边为大家提供一个工具类,分别提供了上边两种方式的封装,如果只想使用
BindingResult方式,那么大可以去除用不到的代码封装的工具类与使用
(1)工具类代码
package com.cnblogs.hellxz.myutils; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError; import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Set; /**
* <b>类名</b>: ValidatorUtils
* <p><b>描 述</b> 校验入参 </p>
*
* <p><b>创建日期</b>: 8/24/18 12:54 PM </p>
*
* @author HELLXZ 张
* @version 1.0
* @since jdk 1.8
*/
public class ValidatorUtils { private static final Logger log = LoggerFactory.getLogger(ValidatorUtils.class);
private static final Validator validator; static {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
} /**
* 分组进行校验或完整校验
* 区别在于是否传groups类
* ps:分组的好处在于同一个DTO分别给不同的方法指定不同的校验参数时候非常有用
* 也就不用再去重写一个新的相同字段的DTO指定不同校验字段的操作,更灵活
* @param object 被校验的DTO对象
* @param groups 分组类,可以是接口也可以是类,仅作为标识
* @return 想要返回的结果
*/
public static <T> String validEntity(final T object, Class... groups) {
Set<ConstraintViolation<T>> violations = validator.validate(object, groups);
if (!violations.isEmpty()) {
//这里只取第一条错误,防止返回参数过多
ConstraintViolation<T> violation = violations.iterator().next();
log.error(violation.getMessage());
//下面的代码可以使用公司或个人习惯的返回工具类也可以
return "{\"code\":\"400\",\"msg\":\"" + violation.getMessage() + "\"}";
}
return null;
} /**
* 校验入参对象的某个属性是否满足要求,跳过其它校验, 支持分组
* @param object 被校验的DTO对象
* @param propertyName DTO对象内的属性名
* @param groups 分组名
* @return 校验出错返回的结果
*/
public static <T> String validProperty(final T object, String propertyName,
Class... groups) {
Set<ConstraintViolation<T>> violations = validator.validateProperty(object, propertyName, groups);
if (!violations.isEmpty()) {
//这里只取第一条错误,防止返回参数过多
ConstraintViolation<T> violation = violations.iterator().next();
log.error(violation.getMessage());
//下面的代码可以使用公司或个人习惯的返回工具类也可以
return "{\"code\":\"400\",\"msg\":\"" +
violation.getMessage() + "\"}";
}
return null;
} /**
* 使用BindingResult与@Valid注解一起使用实现的工具类
* @param result BindingResult对象
* @return 结果串
*/
public static String validEntity(BindingResult result){
if(result.hasErrors()){
//取一条错误信息
ObjectError next = result.getAllErrors().iterator().next();
String defaultMessage = next.getDefaultMessage();
log.error("error={}", defaultMessage);
//后边可以自己返回错误信息也可以自定义
return "{\"code\":\"400\",\"msg\":\"" + defaultMessage + "\"}";
}
return null;
}
}
(2) 工具类的使用
private static Logger log =
LoggerFactory.getLogger(ValidateController.class); /**
* 检查User对象注解在A组内的校验
*/
@PostMapping("/validationTest1")
public String validationTest1(@RequestBody User user){
String valid = ValidatorUtils.validEntity(user, A.class);
if(null != valid) return valid;
//do somethings
return "校验通过";
} /**
* 检查User对象注解在B组内的校验
*/
@PostMapping("/validationTest2")
public String validationTest2(@RequestBody User user){
String valid = ValidatorUtils.validEntity(user, B.class);
if(null != valid) return valid;
//do somethings
return "校验通过";
} /**
* 检查User对象注解在A组和B组内的校验
* ps: 是A组内校验加上B组内校验,不是校验同时在两个组!
*/
@PostMapping("/validationTest3")
public String validationTest3(@RequestBody User user){
String valid = ValidatorUtils.validEntity(user, A.class, B.class);
if(null != valid) return valid;
//do somethings
return "校验通过";
} /**
* 校验入参对象中指定字段
* 其中分组可以不传,如果传的话,请注意该字段必须在该组下,否则不会被校验
*/
@PostMapping("/validationTest4")
public String validationTest4(@RequestBody User user){
String valid = ValidatorUtils.validProperty(user,"age", B.class);
if(null != valid) return valid;
//do somethings
return "校验通过";
} /**
* 验证上边Test4的说法
*/
@PostMapping("/validationTest5")
public String validationTest5(@RequestBody User user){
String valid = ValidatorUtils.validProperty(user,"age", A.class);
if(null != valid) return valid;
//do somethings
return "校验通过";
} /**
* 使用方法7抽的工具类
*/
@PostMapping("/validationTest8")
public String validationTest8(@RequestBody @Valid User user,
BindingResult result){
String errorMsg = ValidatorUtils.validEntity(result);
if(StringUtils.isNotBlank(errorMsg)) return errorMsg;
//do somethings
return "校验通过";
}
(3) 补充:User类
public class User { @NotBlank(message = "用户名不能为空串",groups = A.class)
private String username;
@NotNull(message = "年龄不能为空",groups = B.class)
private String age;
@NotBlank(message = "身高不能为空", groups = {A.class, B.class})
private String height;
@NotEmpty(message = "孩子列表不能为空")
private List<Object> childs; @Email(message = "email不正确")
private String email; //省略get set 方法
}
扩展部分
空检查
@Null:验证某参数必须为空 ps: 没有过 =. = ,其余的空检查在上边已经讲了长度检查
@Size(min=, max=): 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内@Length(min=, max=): 长度是否在范围内Booelan检查
@AssertTrue: 验证 Boolean 对象是否为 true@AssertFalse: 验证 Boolean 对象是否为 false数值检查:建议用在基础类型包装类型上和String类型上
@Min: 验证最小值@Max: 验证最大值@DecimalMax:小数数值不能大于设置的值,小数存在精度@DecimalMin:小数数值不能小于设置的值,小数存在精度@Digits: 验证数字和字符串组成是否合法范围检查
@Range(min=, max=):验证对象最小与最大的范围号码检查
@CreditCardNumber: 信用卡验证(hibernate的实现)@Email: 验证是否是邮件地址,如果为null,则不进行验证,通过验证(validation和hibernate均有实现)日期检查
@Past:验证 Date 和 Calendar 对象是否在当前时间之前,null 被认为是通过验证@Future:验证 Date 和 Calendar 对象是否在当前时间之后 ,null 被认为是通过验证正则表达式检查
@Pattern(regexp = ""): 使用正则表达式验证String,接受字符序列,regexp必填,所修饰为null时认为是通过验证终了
憋了一晚上才想通校验的实际用法,参考了一些的博文,把最大部分的内容引用粘在下面了,基本是官方文档和一个外文网站
https://docs.oracle.com/javaee/7/api/toc.htm
https://docs.jboss.org/hibernate/stable/validator/api/
本文代码:https://github.com/HellxZ/MyUtils.git
声明:本文内容未经许可可以转载,但请注明出处
SpringMvc数据校验@Valid等注解的使用与工具类抽取的更多相关文章
- SpringMVC数据校验并通过国际化显示错误信息
目录 SpringMVC数据校验并通过国际化显示错误信息 SpringMVC数据校验 在页面中显示错误信息 通过国际化显示错误信息 SpringMVC数据校验并通过国际化显示错误信息 SpringMV ...
- 《Java从入门到放弃》入门篇:springMVC数据校验
昨天我们扯完了数据传递,今天我们来聊聊数据校验的问题.来,跟着我一起读:计一噢叫,一按艳. 在springMVC中校验数据也非常简单,spring3.0拥有自己独立的数据校验框架,同时支持JSR303 ...
- springMVC数据校验与单文件上传
spring表单标签: <fr:from/> 渲染表单元素 <fr:input/>输入框组件 <fr:password/>密码框组件标签 & ...
- SpringMVC——数据校验
数据校验在web应用里是非常重要的功能,尤其是在表单输入中.在这里采用Hibernate-Validator进行校验,该方法实现了JSR-303验证框架支持注解风格的验证. 一.导入jar包 若要实现 ...
- Spring MVC 数据校验@Valid
先看看几个关键词 @Valid @Pattern @NotNull @NotBlank @Size BindingResult 这些就是Spring MVC的数据校验的几个注解. 那怎么用呢?往下看 ...
- 《SpringMVC从入门到放肆》十三、SpringMVC数据校验
上一章,我们学习了SpringMVC的自定义类型转换器,但是如果转换后的数据传递到Controller的方法中,忽然发现有某些属性为Null了,这怎么办?我们需要一种有效的数据校验机制,来对数据进行有 ...
- 从深处去掌握数据校验@Valid的作用(级联校验)
每篇一句 NBA里有两大笑话:一是科比没天赋,二是詹姆斯没技术 相关阅读 [小家Java]深入了解数据校验:Java Bean Validation 2.0(JSR303.JSR349.JSR380) ...
- SpringMVC 数据校验(JSR-303)
项目中,通常使用较多的是前端的校验,比如页面中js校验以及form表单使用bootstrap校验.然而对于安全要求较高点建议在服务端进行校验. 服务端校验: 控制层controller:校验页面请求的 ...
- Springmvc数据校验
步骤一:导入四个jar包 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=" ...
随机推荐
- React半科普文
React半科普文 什么是React getting started 文件分离 Server端编译 定义一个组件 使用property 组件嵌套 组件更新 Virtual DOM react nati ...
- css怎样去掉多个Img标签之间的间隙
在写css的时候经常会遇到这样的情况,两张宽度加起来是2n的图片,在宽度为2n的容器中放不下,这是因为两张图片之间有一段间隙的缘故,产生这种现象的原因是浏览器把两个img标签之间的空格当成了空白节点. ...
- Vxlan抓包
实验目的:验证Openstack vxlan组网模式验证虚拟机数据是否通过物理网卡流出 一. 同网段不同主机间虚拟机通讯 (同网段通讯直接通过物理机隧道口链接对端物理机隧道口,不需要通过网络节点): ...
- c语言数字图像处理(二):图片放大与缩小-双线性内插法
图像内插 假设一幅大小为500 * 500的图像扩大1.5倍到750 * 750,创建一个750 * 750 的网格,使其与原图像间隔相同,然后缩小至原图大小,在原图中寻找最接近的像素(或周围的像素) ...
- Git 使用简记
目录 git 标签 添加标签 git tag <tagname> ,例:git tag v1.0 添加带有说明的标签 git tag -a v0.1 -m "第一次提交" ...
- Ubuntu命令行运行C程序和C++程序
首先Ctrl + T 打开一个终端,cd到你建立C/C++文件的目录下. 下面以建立 helloc.c 和 hellocpp.cpp 进行演示 vim helloc.c 按 i 进入插入操作,然后写C ...
- leetcode刷题笔记172 阶乘后的零
题目描述: 给定一个整数 n,返回 n! 结果尾数中零的数量. 示例1: 输入: 输出: 解释: ! = , 尾数中没有零. 示例2: 输入: 输出: 解释: ! = , 尾数中有 个零. 说明: 你 ...
- mui框架(三)
1.Ajax-get请求 // get测试请求地址 http://test.dongyixueyuan.com/link_app/get?state=index&num=0 mui.get(' ...
- Alpha阶段个人贡献分
根据任务完成情况与之前的评分标准,我们给组员分数如下: 团队成员 最终得分 程刚 49 李睿琦 50 刘丽萍 52 刘宇帆 53 王力民 54 杨昊岚 41 左少辉 51 转会人员: 杨昊岚转到Our ...
- Inside the Social Network’s (Datacenter) Network
摘要: 大量服务提供商投资越来越多的更大数据中心来保证基础计算需求以支持他们的服务.因此,研究人员和行业从业者都集中了大量的努力设计网络结构有效互连和管理流量以保证这些数据中心的性能.不幸的是,数据中 ...