Java类属性字段校验(validation的使用)
Java类属性字段校验(validation的使用)
- 1、需求来源:日常校验需求
- 2、validation介绍
- 2-1、常见的注解
- 2-2、快速入门
- 1、简单校验
- 2、自定义校验注解
- 3、通用的Validtor校验工具类
1、需求来源:日常校验需求
日常开发中,我们时常需要提供可靠的 API 接口,此时对于请求的入参就需要校验,以保证最终数据入库的正确性,这就成了必不可少的活。例如说,用户注册时,会校验手机格式的正确性、邮箱格式的正确性、密码非弱密码等。
但是如果使用 if-else 这种代码去校验, 那么需要校验的地方有很多情况下,代码量就会变的十分臃肿,若是一个类请求参数校验字段又多的化,相信各位小伙伴对不会开心,这么干肯定不合适,代码也不优雅,那么如何解决这个问题呢?
答案就是下面要介绍的 validation
2、validation介绍
validation 技术在Java中运用最早在2009 年,Java 官方提出了 Bean Validation 规范,而后经历了JSR303、JSR349、JSR380 三次标准的更迭,发展到了 2.0 。
Bean Validation 和 我们以前学习过的 JPA 一样,只提供规范,不提供具体的实现。因此实际使用过程,常用的是 hibernate 的校验组件:org.hibernate.hibernate-validator
2-1、常见的注解
通常情况下,在javax.validation.constraints 包下,定义了一系列的约束(constraint)注解,一共 22 个注解,快速略过即可。如下:
空和非空检查
@NotBlank
:只能用于字符串不为 null ,并且字符串 .trim() 以后 length 要大于 0 。@NotEmpty
:集合对象的元素不为 0 ,即集合不为空 。@NotNull
:不能为 null 。@Null
:必须为 null 。
数值检查
@DecimalMax(value)
:被注释的元素必须是一个数字,其值必须小于等于指定的最大值。@DecimalMin(value)
:被注释的元素必须是一个数字,其值必须大于等于指定的最小值。@Digits(integer, fraction)
:被注释的元素必须是一个数字,其值必须在可接受的范围内。@Positive
:判断正数。@PositiveOrZero
:判断正数或 0 。@Max(value)
:该字段的值只能小于或等于该值。@Min(value)
:该字段的值只能大于或等于该值。@Negative
:判断负数。@NegativeOrZero
:判断负数或 0 。
Boolean 值检查
@AssertFalse
:被注释的元素必须为 true 。@AssertTrue
:被注释的元素必须为 false 。
长度检查
@Size(max, min)
:检查字段的 size 是否在 min 和 max 之间,可以是字符串、数组、集合、Map 等。
日期检查
@Future
:被注释的元素必须是一个将来的日期。@FutureOrPresent
:判断日期是否是将来或现在日期。@Past
:检查该字段的日期是在过去。@PastOrPresent
:判断日期是否是过去或现在日期。
其它检查
@Email
:被注释的元素必须是电子邮箱地址。@Pattern(value)
:被注释的元素必须符合指定的正则表达式。
Hibernate Validator 附加的约束注解,在org.hibernate.validator.constraints 包下,定义了一系列的约束(constraint)注解。常见的如示。
@Range(min=, max=)
:被注释的元素必须在合适的范围内。@Length(min=, max=)
:被注释的字符串的大小必须在指定的范围内。@URL(protocol=,host=,port=,regexp=,flags=)
:被注释的字符串必须是一个有效的 URL 。@SafeHtml
:判断提交的 HTML 是否安全。例如说,不能包含 javascript 脚本等等。
其他的就不一一列举了,有感兴趣的小伙伴可以去源码包看看。
@Valid
和@Validated
@Valid
注解,是 Bean Validation 所定义,可以添加在普通方法、构造方法、方法参数、方法返回、成员变量上,表示它们需要进行约束校验。@Validated
注解,是 Spring Validation 锁定义,可以添加在类、方法参数、普通方法上,表示它们需要进行约束校验。同时,@Validated
有 value 属性,支持分组校验。
对于初学者来说,很容易搞混
@Valid
和@Validated
注解。
① 声明式校验:Spring Validation 仅对 @Validated 注解,实现声明式校验。
② 分组校验:Bean Validation 提供的 @Valid
注解,因为没有分组校验的属性,所以无法提供分组校验。此时,我们只能使用 @Validated
注解。
③ 嵌套校验:相比来说,@Valid
注解的地方,多了【成员变量】。这就导致,如果有嵌套对象的时候,只能使用@Valid
注解。
2-2、快速入门
- 在 pom.xml 文件中,引入相关依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.1.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><modelVersion>4.0.0</modelVersion><groupId>com.raos</groupId><artifactId>validation-demo</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- 实现对 Spring MVC 的自动化配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- lombok依赖(代码简洁处理) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>compile</scope></dependency><!-- 单元测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>
spring-boot-starter-web 依赖里,已经默认引入 hibernate-validator 依赖,所以本示例使用的是 Hibernate Validator 作为 Bean Validation 的实现框架。
1、简单校验
- 编写实体类(这里以常用的用户注册为场景)
@Data
public class SysUser {private Long userId;/*** 账号*/@NotBlank(message = "用户名不能为空")@Size(min = 6, message = "用户名长度不能小于6个字符")private String username;/*** 密码*/@NotEmpty(message = "密码不能为空")@Size(min = 8, message = "密码长度不能小于8个字符")private String password;/*** 手机号*/@NotBlank(message = "手机号不能为空")@Size(min = 11, max = 11, message = "手机号长度不对")private String mobile;
}
- 编写前端控制器
@RestController
@RequestMapping("/user")
public class SysUserController {@PostMapping("/add")public R addUser(@RequestBody @Valid SysUser sysUser) {System.out.println("走到这里说明校验成功");System.out.println(sysUser);return R.ok(R.SUCCESS_MSG);}
}
- 编写前端响应封装实体
public class R extends HashMap<String, Object> {private static final long serialVersionUID = 1L;public static final String SUCCESS_MSG = "操作成功!";public static final String FAIL_MSG = "操作失败!";public R() {this.put((String) "code", 0);}public static R error() {return error(500, "未知异常,请联系管理员");}public static R error(String msg) {return error(500, msg);}public static R error(int code, String msg) {R r = new R();r.put((String) "code", code);r.put((String) "msg", msg);return r;}public static R ok(String msg) {R r = new R();r.put((String) "msg", msg);return r;}public static R ok(Object object) {R r = new R();r.put("result", object);return r;}public static R ok(int code, String msg) {R r = new R();r.put((String) "code", code);r.put((String) "msg", msg);return r;}public static R ok(Map<String, Object> map) {R r = new R();r.putAll(map);return r;}public static R ok() {return new R();}public R put(String key, Object value) {super.put(key, value);return this;}
}
- 编写自定义异常(用于后续业务抛出异常错误)
public class RRException extends RuntimeException {private static final long serialVersionUID = 1L;private String msg;private int code = 500;public RRException(String msg) {super(msg);this.msg = msg;}public RRException(String msg, Throwable e) {super(msg, e);this.msg = msg;}public RRException(String msg, int code) {super(msg);this.msg = msg;this.code = code;}public RRException(String msg, int code, Throwable e) {super(msg, e);this.msg = msg;this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}
}
当访问/user/add
这个post接口时,如果参数不符合Model中定义的话,程序中就回抛出400异常状态码,并提示错误信息,如下所示。
{"timestamp": "2021-05-20T01:08:28.831+0000","status": 400,"error": "Bad Request","errors": [{"codes": [ "Size.sysUser.mobile", "Size.mobile", "Size.java.lang.String", "Size" ],"arguments": [ { "codes": [ "sysUser.mobile", "mobile" ], "arguments": null, "defaultMessage": "mobile", "code": "mobile" },11,11], "defaultMessage": "手机号长度不对","objectName": "sysUser","field": "mobile","rejectedValue": "155833013","bindingFailure": false,"code": "Size"}],"message": "Validation failed for object='sysUser'. Error count: 1","path": "/user/add"
}
2、自定义校验注解
虽然 JSR303 和 Hibernate Validtor 已经提供了很多校验注解,但是当面对复杂参数校验时,还是不能满足我们的要求,这时候我们就需要 自定义校验注解。
下面以“List数组中不能含有null元素”为实例自定义校验注解
1、注解定义如示。
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = ListNotHaveNullValidatorImpl.class)//此处指定了注解的实现类
public @interface ListNotHaveNull {/*** 添加value属性,可以作为校验时的条件,若不需要,可去掉此处定义*/int value() default 0;String message() default "List集合中不能含有null元素";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};/*** 定义List,为了让Bean的一个属性上可以添加多套规则*/@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})@Retention(RUNTIME)@Documented@interface List {ListNotHaveNull[] value();}
}
2、编写自定义校验实现类
@Service
public class ListNotHaveNullValidatorImpl implements ConstraintValidator<ListNotHaveNull, List> {private int value;@Overridepublic void initialize(ListNotHaveNull constraintAnnotation) {//传入value 值,可以在校验中使用this.value = constraintAnnotation.value();}public boolean isValid(List list, ConstraintValidatorContext constraintValidatorContext) {for (Object object : list) {if (object == null) {//如果List集合中含有Null元素,校验失败return false;} else if (object instanceof String) {String value = object.toString();if (value.trim().length() == 0){return false;}}}return true;}
}
3、model中添加注解:
@Data
public class SysRole {private Long roleId;@NotBlank(message = "角色名不能为空")private String name;@NotEmpty(message = "资源列表不能为空")@ListNotHaveNull(message = "List 中不能含有null元素")@Validprivate List<String> paths;}
4、编写前端控制器
@PostMapping("/addRole")public R addRole(@RequestBody @Valid SysRole sysRole) {System.out.println("走到这里说明校验成功");System.out.println(sysRole);return R.ok(R.SUCCESS_MSG);}
使用方法同 “简单校验”,在在需要校验的Model上面加上@Valid
即可。
3、通用的Validtor校验工具类
public class ValidatorUtils {private ValidatorUtils() { }private static Validator validator;static {validator = Validation.buildDefaultValidatorFactory().getValidator();}/*** 校验对象** @param object 待校验对象* @param groups 待校验的组* @throws RRException 校验不通过,则报RRException异常*/public static void validateEntity(Object object, Class<?>... groups) throws RRException {Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);if (!constraintViolations.isEmpty()) {Iterator<ConstraintViolation<Object>> iterator = constraintViolations.iterator();StringBuilder msg = new StringBuilder();while (iterator.hasNext()) {ConstraintViolation<Object> constraint = iterator.next();msg.append(constraint.getMessage()).append(',');}throw new RRException(msg.toString().substring(0,msg.toString().lastIndexOf(',')));}}
}
使用方式,在接收到前端传递的参数后,使用ValidatorUtils.validateEntity(【参数名】);
即可校验,支持分组校验,分组需要定义分组接口。
以上待续。
Java类属性字段校验(validation的使用)相关推荐
- java 编写方法和属性,Java类属性及方法的定义
文章导读 [在定义类时,经常需要抽象出它的属性和方法,并定义在类的主体中.本文探讨Java类属性及方法的定义和使用.通过本文的学习,你将了解如何在Java类中定义属性及方法.属性值的设置和获取.] 本 ...
- aop+注解 实现对实体类的字段校验_SpringBoot实现通用的接口参数校验
来自:掘金,作者:cipher 链接:https://juejin.im/post/5af3c25b5188253064651c76 原文链接:http://www.ciphermagic.cn/sp ...
- java 类 属性数量_跟我学java编程—Java类的属性与成员变量
在定义类时,经常需要抽象出它的属性,并定义在类的主体中.下面就来介绍与属性相关的内容. 常量属性 在类中定义的属性有常量属性和成员属性之分.常量属性用final关键字修饰,常量只能赋值一次,在程序中不 ...
- aop+注解 实现对实体类的字段校验_SpringBoot2.0实战(6)整合hibernate-validator进行参数校验...
spring-boot-starter-web 项目中默认已经集成了 hibernate-validator 相关知识 @AssertTrue // 用于 boolean 字段,该字段只能为 true ...
- 【记】Java 类属性首字母大写Response其结果为小写
原因:项目是JavaSpringboot,问题由于JavaBean底层处理代码问题导致. 建议:请使用规范标识,遵循驼峰式的规范命名.如果一定要开头大写,请在两个或两个字符以上. 深扒代码:原帖传送门 ...
- springboot使用Mybatis-plus3.5.0 数据库取日期数据映射java 类LocalDateTime字段 为null
问题描述 提示:问题: 数据库字段 :DATETIME Java 实体类 字段 LocalDateTime 用查询语句查询出来的日期字段为null 即使 使用 @TableField(value = ...
- 如何理解Java的类变量、成员变量、常量、类属性、实例属性、字段(field)、成员方法、类方法
文章目录 变量相关概念 变量/常量 类变量/静态变量 成员变量/实例变量 类属性/实例属性/对象属性 什么是 field 成员变量和类变量的区别 两个变量的生命周期不同 访问方式不同 数据存储位置不同 ...
- 如何配置数据库带有下划线字段对应Java实体类属性(驼峰命名)
一般开发中,数据库字段设计推荐使用下划线(u_name),Java实体类属性使用驼峰命名(uName),为了能使数据库字段与Java实体类属性一一映射,需要做一下的配置,这里我用的是spring bo ...
- java jsr 303_java对象校验(validation)-JSR303规范
JSR303 规范简介 web开发有一句名言:永远不要相信用户输入,在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情.应用程序必须通过某种手段来确保输入进来的数据从语义 ...
- Java参数校验validation和validator区别
Java参数校验validation和validator区别 1. 参数校验概述 2. validation与validator区别 3. validation注解说明 4. validator注解说 ...
最新文章
- 03Template Method模式
- 打开AI芯片的“万能钥匙”
- 关系型数据库的ACID规则
- [BZOJ3206][Apio2013]道路费用
- (详细)Hibernate查询技术(Query、Session、Criteria),Hibernate的三种状态,Hibernate集合struts2实现登录功能(二)
- linux下kegg注释软件,KEGG功能注释工具 KofamKOALA 安装与使用
- Python+pyplot绘制带文本标注的柱状图
- Linux下双网卡绑定bond0
- Java 集合深入理解(15):AbstractMap
- 如何让ul的符号隐藏_亚马逊关键词大师,那些你不知道的隐藏keywords操作方法(干货)...
- 极棒开启AI挑战 全球寻找顶级语音合成“机械师”
- 互联网全球化趋势下,印度极得美自我革新
- 北京首都国际机场1号航站楼、2号航站楼、3号航站楼航空公司名单
- _tsplitpath_s(分解路径)
- u-boot:env源码目录分析一
- 基于html+JS实现canvas简易画图工具
- iOS 开发中的 Flux 架构模式
- 【C语言】让你不再害怕指针——C指针详解(经典,非常详细)
- 【12】理解电路:从电报机到门电路,我们如何做到“千里传信”?
- Hibernate 入门 练习
热门文章
- 线性代数----逆矩阵的性质和求法
- Linux查看ip 地址命令(ip addr)
- npn三种波形失真_三极管放大电路各点电压、电流波形图
- 《Java并发编程的艺术》读书笔记
- c语言程序设计诗句,诗歌大全
- 百度echart世界各国及国内省市经纬度坐标
- C++ 栈实现逆波兰式求解运算式和两栈共享存储空间
- php企业微信回调url校验失败,企业微信第三方服务商回调URL无法通过验证
- 说说我的专业计算机作文,说说我自己作文(精选11篇)
- 用计算机打元宵节快乐,2019元宵节祝福语大全简短 祝大家元宵节快乐