验证参数
关于JSR-303规范 JSR-303是JAVA
EE6中的一项子规范,validation-api是一套标准(JSR-303),叫做Bean
Validation,Hibernate
Validator是Bean Validation的参考实现,提供了JSR-303
规范中所有内置constraint的实现,除此之外Hibernate Validator还附加了一些constraint。
1、校验常用的值Apache Commons Validator完成常用的校验
<dependency><groupId>commons-validator</groupId><artifactId>commons-validator</artifactId><version>1.7</version>
</dependency>
分类 | 项目 | 说明 |
---|---|---|
分类 | 项目 | |
日期和时间 | 校验日期-时间 | |
格式校验 | ||
时区支持 | ||
日期和时间比较 | ||
数字校验 | 各种数字包装类型格式转换校验BigInteger和BigDecimal格式转换校验 | |
数字字符串格式校验(比如带千分隔符) | ||
范围校验 | ||
货币格式校验 | ||
百分比格式及范围校验 | ||
其他校验 | 正则校验 | |
特殊规格数字格式校验 | ||
IPV4格式校验 | ||
电子邮件地址格式校验 | ||
URL校验 | ||
域名校验 |
2、校验非空,大小,数字,布尔,范围等使用(javax.validation.validation-api)
如果是Spring Boot项目工程,可忽略此步骤,因为在Spring Boot组件内部已经内置了validation-api
<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>1.1.0.Final</version>
</dependency>
Validation-API | 概述 |
---|---|
@AssertFalse | 被注释的元素必须为 false |
@AssertTrue | 被注释的元素必须为 true |
@DecimalMax | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Digits | 被注释的元素必须是一个在可接受范围内的数字 |
被注释的元素必须是正确格式的电子邮件地址 | |
@Future | 被注释的元素必须是将来的日期 |
@FutureOrPresent | 被注释的元素必须是现在或将来的日期 |
@Max | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Min | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Negative | 被注释的元素必须是一个严格的负数(0为无效值) |
@NegativeOrZero | 被注释的元素必须是一个严格的负数(包含0) |
@NotBlank | 被注释的元素同StringUtils.isNotBlank,只作用在String上,在String属性上加上@NotBlank约束后,该属性不能为null且trim()之后size>0 |
@NotEmpty | 被注释的元素同StringUtils.isNotEmpty,作用在集合类上面,在Collection、Map、数组上加上@NotEmpty约束后,该集合对象是不能为null的,并且不能为空集,即size>0 |
@NotNull | 被注释的元素不能是Null,作用在Integer上(包括其它基础类),在Integer属性上加上@NotNull约束后,该属性不能为null,没有size的约束;@NotNull作用在Collection、Map或者集合对象上,该集合对象不能为null,但可以是空集,即size=0(一般在集合对象上用@NotEmpty约束) |
@Null | 被注释的元素元素是Null |
@Past | 被注释的元素必须是一个过去的日期 |
@PastOrPresent | 被注释的元素必须是过去或现在的日期 |
@Pattern | 被注释的元素必须符合指定的正则表达式 |
@Positive | 被注释的元素必须严格的正数(0为无效值) |
@PositiveOrZero | 被注释的元素必须严格的正数(包含0) |
@Szie | 被注释的元素大小必须介于指定边界(包括)之间 |
3、校验非空,大小,数字,布尔,范围等使用(org.hibernate.hibernate-validator)
如果是Spring Boot项目工程,可忽略此步骤,因为在Spring Boot组件内部已经内置了hibernate-validator
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>5.2.0.Final</version>
</dependency>
hibernate-validator | 概述 |
---|---|
@CodePointLength | 验证字符序列的编码点长度在min和max之间,可以通过设置规范化策略来验证规范化值 |
@ConstraintComposition | 布尔运算符,应用于合成约束注释的所有约束,组合约束注释可以定义组成它的约束的布尔组合,参考ConstraintComposition实现 |
@CreditCardNumber | 被注释元素必须是一个有效的信用卡号码,这是Luhn算法的实现,目的是检查用户的错误,而不是信用卡的有效性 |
@Currency | 参考moneyaryamount和CurrencyUnit实现 |
@EAN | 检查被注释的字符序列是否有效,EAN长度为13,支持的类型是String,当字符串为null被认为有效的 |
被注释的字符串必须是正确格式的电子邮件地址【已禁用】 | |
@ISBN | 检查被注释字符序列是否有效,支持的类型是String,null将被认为有效的,在验证过程中,忽略所有非ISBN字符,所有数字和“X”都被认为是有效的ISBN字符。主要用于证以破折号分隔的ISBN时,这很有用,例如:239-992-190-873-492 |
@Length | 被注释的字符串的长度必须在指定的范围内 |
@LuhnCheck | Luhn算法检查约束,用于验证一系列数字通过Luhn Modulo 10校验算法。Luhn Modulo 10的计算方法是把每一个数字加起来,每个数字都是奇数,数字(从右到左)的值乘以2,如果值大于9的,则结果数字的总和在总和之前,支持的类型是String,null被认为有效的 |
@Mod10Check | 允许验证一系列数字通过Mod10校验和算法。经典的Mod10是通过把每一个奇数加起来计算出来的数字(从右到左)的值乘以乘数,例如:ISBN-13是Modulo 10校验和乘数= 3,在已知的情况下,代码使用乘数的偶数和奇数数字;为了支持这种实现,Mod10约束使用权重选项,它具有与乘数相同的效果,但为偶数数字,支持的类型是String。null被认为有效的 |
@Mod11Check | 允许验证一系列数字通过Mod11校验和算法,对于最常见的Mod11变体的总和计算是通过乘以一个权重最右边的数字(不包括校验数字)到最左边。权重从2开始,每个数字加1。然后结果为11 - (sum % 11)计算校验数字。例如:24187的校验位是3 Sum = 7x2 + 8x3 + 1x4 + 4x5 + 2x6 = 74 11 - (74% 11) = 11 - 8 = 3,所以“24187-3”是一个有效的字符序列 |
@ModCheck | 被注解的元素表示验证一系列数字通过mod 10或mod 11校验和算法,支持的类型是String,null被认为有效的【已禁用】 |
@Normalized | 验证字符序列是否为规范化形式,可以通过设置规范化策略来验证规范化值 |
@NotBlank | 同StringUtils.isNotBlank,只作用在String上,在String属性上加上@NotBlank约束后,该属性不能为null且trim()之后size>0(同validation-api)【已禁用】 |
@NotEmpty | 同StringUtils.isNotEmpty,作用在集合类上面,在Collection、Map、数组上加上@NotEmpty约束后,该集合对象是不能为null的,并且不能为空集,即size>0【已禁用】 |
@Range | 被注释的元素必须在合适的范围内 |
@SafeHtml | 验证用户提供的富文本,以确保它不包含恶意代码,如嵌入式元素。注意,这个约束假设您想要验证代表HTML文档正文片段的输入。如果你想要验证代表一个完整HTML文档的输入,在校验的白名单中添加HTML、head和body标记【已禁用】 |
@ScriptAssert | 类级约束,它对脚本表达式求值注释的元素。此约束可用于实现验证日常活动,依赖于注释元素的多个属性。脚本表达式可以写在任何脚本或表达式语言中,其中的JSR 223兼容的引擎可以在类路径中找到 |
@UniqueElements | 验证集合中的每个对象都是唯一的,即不能找到两个相等的元素集合,这对于JAX-RS很有用,它总是将集合反序列化为一个列表。因此,当重复的将其转换为一个集合时,会被隐式或默认的删除掉 |
@URL | 验证带注释的字符串是一个URL,参数protocol、host和port对应URL的相应部分。可以加上一个额外的正则表达式regexp和flags可以进一步定制URL的验证标准。默认情况下,约束验证使用java.net.URL构造函数来验证字符串,这意味着匹配的协议处理程序需要可用,需要保证程序中以下协议的处理程序在默认JVM-HTTP、HTTPS、FTP文件和JAR中存在的 |
使用
package com.b2c.aiyou.device.inventory.dto;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.Date;
import java.util.List;@Data
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel
public class InventoryEntity implements Serializable {private static final long serialVersionUID = 1L;/*** 类别CODE*/@NotBlank(message = "类别CODE不能为Null")@Size(min = 8, max = 32, message = "类别CODE长度必须在{min}~{max}之间")@ApiModelProperty(value = "类别CODE")private String categoryCode;/*** 类型CODE*/@NotBlank(message = "类型CODE不能为Null")@Size(min = 8, max = 32, message = "类型长度必须在{min}~{max}之间")@ApiModelProperty(value = "类型CODE")private String typeCode;/*** 最高库存量*/@DecimalMax(value = "100000", message = "最高库存量必须小于或等于{value}")@ApiModelProperty(value = "最高库存量")private Integer inventoryMax;/*** 最低库存量*/@DecimalMin(value = "100", message = "最低库存量必须大于或等于{value}")@ApiModelProperty(value = "最低库存量")private Integer inventoryMin;/*** 最小进货量*/@Min(value = 100, message = "最小进货量必须大于或等于{value}")@ApiModelProperty(value = "最小进货量")private Integer restockMin;/*** 最大进货量*/@Max(value = 10000, message = "最大进货量必须小于或等于{value}")@ApiModelProperty(value = "最大进货量")private Integer restockMax;/*** 进货日期*/@Future(message = "进货日期必须大于当前日期")@ApiModelProperty(value = "进货日期")private Date restockTime;/*** 进货周期*/@NotEmpty(message = "进货周期不能为Null")@ApiModelProperty(value = "进货日期")private List<String> periodTime;/*** 备注*/@ApiModelProperty(value = "备注")@Size(min = 50, max = 500, message = "备注内容必须在{min}~{max}之间")private String remark;}
package com.b2c.aiyou.device.inventory.dto;import com.b2c.aiyou.device.common.annotation.Log;
import com.b2c.aiyou.device.inventory.service.IInventoryService;
import com.b2c.aiyou.common.constant.ResultCodeEnum;
import com.b2c.aiyou.common.result.AppException;
import com.b2c.aiyou.common.result.JSONResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.validation.Valid;@Slf4j
@RestController
@RequestMapping("/inventory")
public class InventoryController {@PostMapping("/addInventory")public JSONResult addInventory(@Valid @RequestBody InventoryDTO inventoryDTO, BindingResult bindingResult) {try {// 字段校验if (bindingResult.hasErrors()) {return JSONResult.failure(bindingResult);}// TODO 其它校验int result = this.inventoryService.insertInventory(inventoryDTO);if (result > 0) {// 成功处理逻辑return JSONResult.success();} else {// 失败处理逻辑return JSONResult.failure();}} catch (AppException e) {log.info("异常信息:{}", e);return JSONResult.failure(ResultCodeEnum.Failure.getCode(), e.getMessage());}}}
注意:在需要校验的对象后面,必须添加BindingResult来接收校验结果,并对校验结果进行处理bindingResult.hasErrors(),否则校验无意义。
直接在controller里面使用BindingResult,来处理结果,不是太友好。一般在controller里面不加BindingResult,校验参数出现的异常,通过全局异常进行捕获处理
/*** 方法参数校验* @param exception 参数校验异常* @return 错误信息*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<String> handleMethodArgumentNotValidException(final MethodArgumentNotValidException exception) {final String errorMessage = exception.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining("; "));log.error("参数校验异常: {}", errorMessage, exception);return ResultUtil.fail(errorMessage);
}
4、总结
1、不管项目是springmvc还是springboot项目,都是可以使用validation-api来做参数校验,校验出现的异常,可以通过全局异常进行捕获处理。
2、在controller层校验成功的前提是,对传入的参数,前面加上@Valid注解
3、在 Controller
类中添加接口,POST
方法中接收设置了 @Valid 相关注解的实体对象,然后在参数中添加 @Valid
注解来开启效验功能,需要注意的是, @Valid
对 Get
请求中接收的平面参数请求无效,一般可以进行手动校验参数,抛出自定义参数错误异常
4、对于一些校验邮箱、ip等,可以使用Apache Commons Validator完成常用的校验
5、一般hibernate-validator
校验参数使用的比较少,一般使用其他两个即可
6、如果实体类有嵌套的话,嵌套实体类上要加上@Valid
注解