当前位置: 首页 > news >正文

Java参数校验(最佳实践)

验证参数

关于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被注释的元素必须是一个在可接受范围内的数字
@Email被注释的元素必须是正确格式的电子邮件地址
@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被认为有效的
@Email被注释的字符串必须是正确格式的电子邮件地址【已禁用】
@ISBN检查被注释字符序列是否有效,支持的类型是String,null将被认为有效的,在验证过程中,忽略所有非ISBN字符,所有数字和“X”都被认为是有效的ISBN字符。主要用于证以破折号分隔的ISBN时,这很有用,例如:239-992-190-873-492
@Length被注释的字符串的长度必须在指定的范围内
@LuhnCheckLuhn算法检查约束,用于验证一系列数字通过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 注解来开启效验功能,需要注意的是, @ValidGet 请求中接收的平面参数请求无效,一般可以进行手动校验参数,抛出自定义参数错误异常

4、对于一些校验邮箱、ip等,可以使用Apache Commons Validator完成常用的校验

5、一般hibernate-validator校验参数使用的比较少,一般使用其他两个即可

6、如果实体类有嵌套的话,嵌套实体类上要加上@Valid注解

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 2024.8.19(静态文件共享、playbook)
  • Python进阶必看:深入解析yield的强大功能
  • Leetcode面试经典150题-15.三数之和
  • 故障诊断 | GNN图神经网络故障诊断(Python)
  • 用QTdesigner制作自己的双目标定软件
  • Java常用API第二篇
  • llama3 结构详解
  • Upload-Lab第12关:如何巧妙利用%00截断法绕过上传验证
  • linux 改文件夹所有者
  • Git工具练习网站
  • 【k8s从节点报错】error: You must be logged in to the server (Unauthorized)
  • Oracle RAC vs Clusterware vs ASM
  • 【Linux系列】telnet使用入门
  • 基于Mybatis 数据过滤组件(二) - 使用文档
  • web技术1——http详解(重要)
  • [数据结构]链表的实现在PHP中
  • [译]CSS 居中(Center)方法大合集
  • 2017-08-04 前端日报
  • C语言笔记(第一章:C语言编程)
  • ERLANG 网工修炼笔记 ---- UDP
  • Flannel解读
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • JavaScript DOM 10 - 滚动
  • PermissionScope Swift4 兼容问题
  • Vultr 教程目录
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 给第三方使用接口的 URL 签名实现
  • 前端代码风格自动化系列(二)之Commitlint
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 三栏布局总结
  • 跳前端坑前,先看看这个!!
  • 网页视频流m3u8/ts视频下载
  • 学习使用ExpressJS 4.0中的新Router
  • 译有关态射的一切
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • ​渐进式Web应用PWA的未来
  • #Linux(make工具和makefile文件以及makefile语法)
  • #我与Java虚拟机的故事#连载04:一本让自己没面子的书
  • ()、[]、{}、(())、[[]]命令替换
  • (C语言)fread与fwrite详解
  • (补充)IDEA项目结构
  • (分类)KNN算法- 参数调优
  • (附源码)ssm高校实验室 毕业设计 800008
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (九)One-Wire总线-DS18B20
  • (六)c52学习之旅-独立按键
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (一)基于IDEA的JAVA基础12
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)重识new
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET MAUI Sqlite程序应用-数据库配置(一)
  • .NET 通过系统影子账户实现权限维持
  • .NET程序员迈向卓越的必由之路