什么是Hibernate Validator?

Hibernate Validator是Hibernate提供的一个开源框架,使用注解方式非常方便的实现服务端的数据校验。

官网:http://hibernate.org/validator/

hibernate Validator是 Bean Validation 的参考实现 。

Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint(约束) 的实现,除此之外还有一些附加的 constraint。

在日常开发中,Hibernate Validator经常用来验证bean的字段,基于注解,方便快捷高效。

在SpringBoot的spring-boot-starter-web启动器中已经集成了相关依赖:

或者可以添加依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Bean校验的常用注解:

@Valid 被注释的元素是一个对象,需要检查此对象的所有字段值
@Validated 被注解的元素是一个对象或者一个类,需要检查此对象的所有字段值
@AssertFalse 所注解的元素必须是Boolean类型,且值为false
@AssertTrue 所注解的元素必须是Boolean类型,且值为true
@DecimalMax 所注解的元素必须是数字,且值小于等于给定的值
@DecimalMin 所注解的元素必须是数字,且值大于等于给定的值
@Digits 所注解的元素必须是数字,且值必须是指定的位数
@Future 所注解的元素必须是将来某个日期
@Max(value) 所注解的元素必须是数字,且值小于等于给定的值
@Min(value) 所注解的元素必须是数字,且值小于等于给定的值
@Range 所注解的元素需在指定范围区间内
@NotNull 所注解的元素值不能为null
@NotBlank 所注解的元素值有内容
@Null 所注解的元素值为null
@Past 所注解的元素必须是某个过去的日期
@PastOrPresent 所注解的元素必须是过去某个或现在日期
@Pattern(value) 所注解的元素必须满足给定的正则表达式
@Size 所注解的元素必须是String、集合或数组,且长度大小需保证在给定范围之内
@Email 所注解的元素需满足Email格式

第一类:实体类参数校验

(1)实体类上加上注解,使用json传参,加@RequestBody解析json参数映射为实体类

@Data
public class User implements Serializable {
private String id; @NotNull(message = "姓名不能为空")
@Size(min = 1, max = 20, message = "姓名长度必须在1-20之间")
private String name; @Min(value = 10, message = "年龄必须大于10")
@Max(value = 150, message = "年龄必须小于150")
private Integer age; @Email(message = "邮箱格式不正确")
private String email; }

(2)Controller中加上注解

@Controller
public class LoginController { @PostMapping("/test")
@ResponseBody
public AjaxResult test(@Validated @RequestBody User user){
System.out.println(user);
return AjaxResult.success(user);
} }

(3)PostMan测试

响应数据:数据不友好,使用全局异常捕获返回友好提示。

{
"timestamp": "2020-06-17T10:16:50.591+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"Email.user.email",
"Email.email",
"Email.java.lang.String",
"Email"
],
"arguments": [
{
"codes": [
"user.email",
"email"
],
"arguments": null,
"defaultMessage": "email",
"code": "email"
},
[],
{
"arguments": null,
"defaultMessage": ".*",
"codes": [
".*"
]
}
],
"defaultMessage": "邮箱格式不正确",
"objectName": "user",
"field": "email",
"rejectedValue": "123456789",
"bindingFailure": false,
"code": "Email"
},
{
"codes": [
"NotNull.user.name",
"NotNull.name",
"NotNull.java.lang.String",
"NotNull"
],
"arguments": [
{
"codes": [
"user.name",
"name"
],
"arguments": null,
"defaultMessage": "name",
"code": "name"
}
],
"defaultMessage": "姓名不能为空",
"objectName": "user",
"field": "name",
"rejectedValue": null,
"bindingFailure": false,
"code": "NotNull"
}
],
"message": "Validation failed for object='user'. Error count: 2",
"path": "/test"
}

(4)全局处理异常,处理 @RequestBody参数校验异常,统一返回格式自定义

@RestControllerAdvice
public class GlobalExceptionHandler { /**
* 处理 @RequestBody参数校验异常
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public AjaxResult handleBindGetException(MethodArgumentNotValidException ex) { Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", new Date()); // 获取所有异常
List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toList());
body.put("errors", errors);
return AjaxResult.error("提交的数据校验失败", body);
} }

(5)再次测试:

第二类:使用表单传参,即不使用@RequestBody,跟上面的第一类异常捕获的异常类型不同而已。

@Controller
public class LoginController { @PostMapping("/test1")
@ResponseBody
public AjaxResult test1(@Validated User user){
System.out.println(user);
return AjaxResult.success(user);
} }
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理不带任何注解的参数绑定校验异常,即没有@RequestBody
*/
@ExceptionHandler(BindException.class)
public AjaxResult handleBingException(BindException ex) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", new Date());
// 获取所有异常
List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toList());
body.put("errors", errors);
return AjaxResult.error("提交的数据校验失败", body);
}
}

第三类:单个参数校验

(1)直接在参数前加上校验注解

@RestController
@Validated
public class UserController {
@GetMapping("/test3")
public AjaxResult test3(@NotNull(message = "name不能为空") String name ,@Email(message = "邮箱格式不正确") String email){
System.out.println(name);
System.out.println(email);
return AjaxResult.success(name+" "+email);
}
}

注意:需要在类上添加@Validated注解,否则不会校验。

@RestControllerAdvice
public class GlobalExceptionHandler { /**
* 处理所有参数校验时抛出的异常
* @param ex
* @return
*/
@ExceptionHandler(value = ValidationException.class)
public AjaxResult handleBindException(ValidationException ex) {
AjaxResult body = new AjaxResult(); body.put("timestamp", new Date()); // 获取所有异常
List<String> errors = new LinkedList<>();
if (ex instanceof ConstraintViolationException) {
ConstraintViolationException exs = (ConstraintViolationException) ex;
Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
for (ConstraintViolation<?> item : violations) {
errors.add(item.getMessage());
}
}
body.put("errors", errors);
body.put("code",900);
body.put("msg","提交的数据校验失败"); return body;
} }

第四类:参数校验分组

在实际开发中经常会遇到这种情况:添加用户时,id是由后端生成的,不需要校验id是否为空,但是修改用户时就需要校验id是否为空。如果在接收参数的User实体类的id属性上添加NotNull,那么都会校验,显然不符合要求。这时候就可以定义分组,在需要校验id的时候校验,不需要的时候不校验。

(1)定义表示组别的接口类

import javax.validation.groups.Default;
public interface Create extends Default {
}
import javax.validation.groups.Default;
public interface Update extends Default {
}

(2)在实体类的注解中标记id使用上面定义的组

@Data
public class User implements Serializable { @NotNull(message = "id不能为空",groups = Update.class)
private String id; @NotNull(message = "姓名不能为空")
@Size(min = 1, max = 20, message = "姓名长度必须在1-20之间")
private String name; @Min(value = 10, message = "年龄必须大于10")
@Max(value = 150, message = "年龄必须小于150")
private Integer age; @Email(message = "邮箱格式不正确")
private String email; }

(3)在controller中使用@Validated指定使用哪个@Controllerpublicclass LoginController {

    @PostMapping("/test4")
@ResponseBody
// 指定Update,这样就会校验id属性是否为空
// 注意:一般来说要添加Default.class,否则不会执行其他的校验(但是我也可以不加,也校验了,哈哈哈,不知道为啥)public AjaxResult test4(@Validated({Update.class, Default.class}) User user){
     System.out.println(user);
return AjaxResult.success(user);
} }

@Controller
public class LoginController { @PostMapping("/test4")
@ResponseBody
  // 这里就没有加default.class,但是测试结果还是校验其他数据了的
public AjaxResult test4(@Validated(Create.class) User user){
System.out.println(user);
return AjaxResult.success(user);
} }

在controller中使用@Valid 或者@Validated 注解校验的区别:

嵌套验证:

public class Item {
@NotNull(message = "id不能为空")
@Min(value = 1, message = "id必须为正整数")
private Long id; @Valid
@NotNull(message = "props不能为空")
@Size(min = 1, message = "至少要有一个属性")
private List<Prop> props;
}
public class Prop {
@NotNull(message = "pid不能为空")
@Min(value = 1, message = "pid必须为正整数")
private Long pid; @NotNull(message = "vid不能为空")
@Min(value = 1, message = "vid必须为正整数")
private Long vid; @NotBlank(message = "pidName不能为空")
private String pidName; @NotBlank(message = "vidName不能为空")
private String vidName;
}
@RestController
public class ItemController {
@RequestMapping("/item/add")
public void addItem(@Validated Item item, BindingResult bindingResult) {
doSomething();
}
}

验证多个对象:

@Controller
public class PeopleController {
@RequestMapping("/add")
public @ResponseBody String add(@Validated People pp, BindingResult result1, @Validated Person ps, BindingResult result2)
{
if(result1.hasErrors())
{
return false;
}
if(result2.hasErrors())
{
return false;
}
return true;
}
}

springboot参数据校验的更多相关文章

  1. 补习系列(4)-springboot 参数校验详解

    目录 目标 一.PathVariable 校验 二.方法参数校验 三.表单对象校验 四.RequestBody 校验 五.自定义校验规则 六.异常拦截器 参考文档 目标 对于几种常见的入参方式,了解如 ...

  2. SpringBoot 参数校验的方法

    Introduction 有参数传递的地方都少不了参数校验.在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全.试想一下,如果在controller层中没有经过任何校验的参数通过s ...

  3. SpringBoot接口 - 如何优雅的对参数进行校验?

    在以SpringBoot开发Restful接口时, 对于接口的查询参数后台也是要进行校验的,同时还需要给出校验的返回信息放到上文我们统一封装的结构中.那么如何优雅的进行参数的统一校验呢? @pdai ...

  4. # SpringBoot使用Validation校验参数 ##

    SpringBoot使用Validation校验参数 一.简介 参考 (14条消息) 1. 不吹不擂,第一篇就能提升你对Bean Validation数据校验的认知_@decimalmax和@max_ ...

  5. SpringBoot 参数校验

    一.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  6. SpringBoot系列: Java应用程序传参和SpringBoot参数文件

    ===========================向java 程序传参的几种形式:===========================1. 使用 OS 环境变量. 这个不推荐. 2. 使用JVM ...

  7. 前端参数统一校验工具类ValidParamUtils

    1,前端参数不可信,对于后端开发人员来说应该是一条铁律,所以对于前端参数的校验,必不可少,而统一的前端参数校验工具,对我们进行参数校验起到事半功倍的效果 2,统一参数校验工具ValidParamUti ...

  8. WebApi安全性 参数签名校验(结合Axios使用)

    接口参数签名校验,是WebApi接口服务最重要的安全防护手段之一. 结合项目中实际使用情况,介绍下前后端参数签名校验实现方案. 签名校验规则 http请求,有两种传参形式: 1.通过url传参,最常见 ...

  9. SpringBoot 请求参数后端校验

    1.例如: package com.model.user; import com.model.PageEntity;import lombok.Getter;import lombok.Setter; ...

  10. springboot 参数校验详解

    https://www.jianshu.com/p/89a675b7c900 在日常开发写rest接口时,接口参数校验这一部分是必须的,但是如果全部用代码去做,显得十分麻烦,spring也提供了这部分 ...

随机推荐

  1. TienChin-课程管理-课程搜索

    后端 新建 CourseVO.java: /** * CourseVO类是一个课程的值对象,用于存储课程的相关信息. * 它包含了课程的名称.类型.适用对象.最低价格和最高价格等属性. */ publ ...

  2. centOS系统 迁移docker镜像及数据文件到指定目录

    话说我今天正在快乐的敲代码,突然看到IDE报警磁盘空间不足了,du -h 查看了一下磁盘占用情况,发现是自己的docker镜像全部放/var/lib/docker目录下 这个系统磁盘给根目录只分配了5 ...

  3. 2022 JuiceFS 社区用户调研结果出炉

    为了使 JuiceFS 的发展更贴合用户的真实需求,我们在三周前向社区发出了一份调研问卷.此次调研面向已经将 JuiceFS 应用于生产环境的用户,了解其在应用 JuiceFS 前和使用中的体验与评价 ...

  4. Python-wxauto微信自动发送消息或文件

    1.安装wxauto和pyautogui库,pip安装即可. pip install wxauto pip install pyautogui 2.登录电脑微信客户端 这里有两个注意点:(1)不能将客 ...

  5. CF1841

    A 题意:给一个长度为 \(n\) 的全是 \(1\) 的数列,Alice 先操作,Bob 交替.每次操作选择至少两个(可以更多)相等的数字,删除它们,在序列中加入它们的和.直到有人不能操作为止,这个 ...

  6. DP的各种优化小结

    动态规划算法(简称动规,DP),是IO中最为常见的,也是最为重要的算法之一.这也就意味着,在各种题目与比赛中它会有很多稀奇古怪的算法和优化,时不时地在你的面前出现一个TLE,MLE和RE来搞你的心态. ...

  7. JS 这一次彻底理解冒泡排序

    壹 ❀ 引 在面试环节中,算法总是逃不掉的一关,对于我这种非班科出生且大学不接触数学的人来说,逻辑思维方面确实较为欠缺,昨晚跟百度的同学聊到凌晨,自我感觉差距较大,受了不小打击,所以决心抓一抓算法,做 ...

  8. NC208250 牛牛的最美味和最不美味的零食

    题目链接 题目 题目描述 牛牛为了减(吃)肥(好),希望对他的零食序列有更深刻的了解,所以他把他的零食排成一列,然后对每一个零食的美味程度都打了分,现在他有可能执行两种操作: eat k:吃掉当前的第 ...

  9. NC20272 [SCOI2009]生日快乐

    题目链接 题目 题目描述 windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕.现在包括windy ,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积 ...

  10. .NET周刊【2月第2期 2024-02-11】

    国内文章 C#/.NET该如何自学入门? https://www.cnblogs.com/Can-daydayup/p/18006914 随着DotNetGuide技术社区交流群的扩大,很多新成员希望 ...