springboot 参数校验详解

https://www.jianshu.com/p/89a675b7c900

在日常开发写rest接口时,接口参数校验这一部分是必须的,但是如果全部用代码去做,显得十分麻烦,spring也提供了这部分功能,本文来探究一下如何实现

1.配置

spring-boot-starter-web包自动依赖hibernate-validator,不用再重复引入,直接开搞

<dependency><groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.3.1.Final</version> </dependency> 

声明一个bean注册到spring容器,这个bean是一个容器后处理器,会把校验的逻辑通过AOP织入有@Validated注解的class,具体可以看这个类的源码

这一步在springboot其实也不用做,ValidationAutoConfiguration这个配置类自动帮我们做了

 @Beanpublic MethodValidationPostProcessor methodValidationPostProcessor(){ return new MethodValidationPostProcessor(); } 

验证不通过会产生异常,因为我们项目提供rest接口,所以通过全局捕获异常,然后转换为json给前台


@ControllerAdvice
public class GlobalExceptionHandler { /** * 用来处理bean validation异常 * @param ex * @return */ @ExceptionHandler(ConstraintViolationException.class) @ResponseBody public WebResult resolveConstraintViolationException(ConstraintViolationException ex){ WebResult errorWebResult = new WebResult(WebResult.FAILED); Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations(); if(!CollectionUtils.isEmpty(constraintViolations)){ StringBuilder msgBuilder = new StringBuilder(); for(ConstraintViolation constraintViolation :constraintViolations){ msgBuilder.append(constraintViolation.getMessage()).append(","); } String errorMessage = msgBuilder.toString(); if(errorMessage.length()>1){ errorMessage = errorMessage.substring(0,errorMessage.length()-1); } errorWebResult.setInfo(errorMessage); return errorWebResult; } errorWebResult.setInfo(ex.getMessage()); return errorWebResult; } @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody public WebResult resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex){ WebResult errorWebResult = new WebResult(WebResult.FAILED); List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors(); if(!CollectionUtils.isEmpty(objectErrors)) { StringBuilder msgBuilder = new StringBuilder(); for (ObjectError objectError : objectErrors) { msgBuilder.append(objectError.getDefaultMessage()).append(","); } String errorMessage = msgBuilder.toString(); if (errorMessage.length() > 1) { errorMessage = errorMessage.substring(0, errorMessage.length() - 1); } errorWebResult.setInfo(errorMessage); return errorWebResult; } errorWebResult.setInfo(ex.getMessage()); return errorWebResult; } } 

这两个异常分别对应校验的两种使用方式

  1. 在方法里面校验
  2. 在bean对象里面校验
    经过测试,以上两种形式的数据验证不仅仅对controller层有用,在service层也行,只要这个类在spring ioc容器里面

2.使用

2.1常用校验注解

@AssertFalse 校验false
@AssertTrue 校验true @DecimalMax(value=,inclusive=) 小于等于value, inclusive=true,是小于等于 @DecimalMin(value=,inclusive=) 与上类似 @Max(value=) 小于等于value @Min(value=) 大于等于value @NotNull 检查Null @Past 检查日期 @Pattern(regex=,flag=) 正则 @Size(min=, max=) 字符串,集合,map限制大小 @Valid 对po实体类进行校验 

这篇文章介绍的注解更全一点

2.2在方法参数上使用

@Controller
@Validated
public class ValidationController {@GetMapping("/validate1") @ResponseBody public String validate1( @Size(min = 1,max = 10,message = "姓名长度必须为1到10")@RequestParam("name") String name, @Min(value = 10,message = "年龄最小为10")@Max(value = 100,message = "年龄最大为100") @RequestParam("age") Integer age, @Future @RequestParam("birth")@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss") Date birth){ return "validate1"; } } 

注意类名需要加注解@Validated
校验失败会抛出ConstraintViolationException异常
然后我们在全局异常捕获类捕获这个异常,返回给前台对应的错误json

2.3在bean内属性上使用

给model类增加校验注解

public class User { @Size(min = 1,max = 10,message = "姓名长度必须为1到10") private String name; @NotEmpty private String firstName; @Min(value = 10,message = "年龄最小为10")@Max(value = 100,message = "年龄最大为100") private Integer age; @Future @JSONField(format="yyyy-MM-dd HH:mm:ss") private Date birth; ...getter setter } 

在controller对应User实体前增加@Valid注解

@PostMapping("/validate2")
@ResponseBody
public User validate2(@Valid @RequestBody User user){ return user; } 

3.扩展

除了默认提供的校验注解外,我们可以定义自己的校验注解

3.1.创建约束注解类

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented @Constraint(validatedBy = { HandsomeBoyValidator.class}) public @interface HandsomeBoy { String message() default "盛超杰最帅"; String name(); Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default {}; } 

注意:message用于显示错误信息这个字段是必须的,groups和payload也是必须的
@Constraint(validatedBy = { HandsomeBoyValidator.class})用来指定处理这个注解逻辑的类

一开始写了这个自定义注解和验证类,发现没有生效,最后发现是@Constraint这个注解里的类没有配置,还跟了很多源码,蛋疼,总的来讲,这个配置还是挺方便的

外国人写的一篇博客,介绍自定义验证配置,挺全的

3.2.创建验证器类

public class HandsomeBoyValidator implements ConstraintValidator<HandsomeBoy, User> { private String name; /** * 用于初始化注解上的值到这个validator * @param constraintAnnotation */ @Override public void initialize(HandsomeBoy constraintAnnotation) { name =constraintAnnotation.name(); } /** * 具体的校验逻辑 * @param value * @param context * @return */ @Override public boolean isValid(User value, ConstraintValidatorContext context) { return name ==null || name.equals(value.getName()); } } 

这边的功能是user类里面的name字段必须和配置的一样,否则输出一个事实

3.3. 测试

@PostMapping("/validate3")
@ResponseBody
public User validate3(@Valid @HandsomeBoy(name = "scj",message = "盛超杰第二帅") @RequestBody  User user){return user; } 

如果验证不通过,会输出盛超杰第二帅,全局异常处理器不要忘记配置

4.demo源码下载

https://github.com/shengchaojie/springboot-validation-demo

小礼物走一走,来简书关注我

转载于:https://www.cnblogs.com/kelelipeng/p/10183904.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248762.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序——账号及开发工具

1. 注册微信小程序账号 点击我进入微信公众平台 进入后点击立即注册 注册成功且登录后进入小程序管理后台 2. 安装开发者工具 点击进入开发文档 进入安装开发工具&#xff08;稳定版本&#xff09; 一路默认下一步进行安装 3. 开发者工具的使用 使用注册微信小程序的微信号…

CSS注意的地方

content-box和border-box的区别 2018年02月27日 22:20:16 sulingliang 阅读数&#xff1a;8011盒子模型 盒子宽度&#xff1a;paddingbordercontent-width 盒子高度&#xff1a;paddingbordercontent-height 如图所示 盒子模型content-box 说明&#xff1a;在内容宽度和高度之…

机器学习笔记(6) 线性回归

先从最简单的例子开始,假设我们有一组样本(如下图的一个个黑色的圆点),只有一个特征,如下图,横轴是特征值,纵轴是label。比如横轴是房屋面积,纵轴是房屋价格. 现在我们要做什么呢&#xff1f;我们试图找到一条直线yaxb,可以尽量好的拟合这些点. 你可能要问了,为啥是直线,不是曲…

仿微信朋友圈项目梳理

项目功能简介&#xff1a; 用户通过手机号验证码进行登录和注册 可以浏览动态列表中的所有动态 登录成功后用户可以发表自己的动态 也可以对自己认可欣赏的动态进行点赞和评论 也可以通过动态结识志同道合的朋友 进行聊天和探讨 前端&#xff1a;采用Vue框架搭建 weui进行页面…

如何处理大流量高并发

1.动静分离。 将网站中的静态资源单独拆分出来, 比如 css, js, 图片, 视频资源单独存储在一台服务器上, 或者直接使用云存储平台, 七牛云或者阿里云之类的, 这样能有效的降低主服务器的运行压力 2.CDN加速。 云平台提供 CDN 加速, 可以对资源进行全国服务器节点的分发, 提高全国…

echarts鼠标事件以及自定义数据获取

事件添加方法&#xff1a; 对应官网位置&#xff1a;https://www.echartsjs.com/api.html#events 鼠标事件包括 click、dblclick、mousedown、mousemove、mouseup、mouseover、mouseout、globalout、contextmenu。 myChart.on(click, function (params) {console.log(params); …

[数学]点、线、面分割问题

平面分割问题 p条直线相交于一点时&#xff0c;分割的图形有 2*(n-1) 个&#xff0c;此时再加一条直线&#xff0c;在 2*(n-1) 的基础上再加 n条&#xff0c;此时为2*n n条曲线&#xff0c;其中有m条相交于一点&#xff0c;每两个曲线都交于两点 平面上有n条直线&#xff0c;且…

移动开发

1.移动端基础 1.1 浏览器现状 PC端浏览器 360浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、百度浏览器&#xff08;停止服务&#xff09;、搜狗浏览器、IE浏览器 移动端浏览器 UC、QQ浏览器、欧朋浏览器、百度手机浏览器、360、搜狗、猎豹、谷歌等其他手机自带的浏览器 国…

Django之路由系统

Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。 你就是以这种方式告诉Django&#xff0c;对于这个URL调用这段代码&#xff0c;对于那个URL调用那段代码。 URLconf配置…

微信小程序——操作数据库

案例一&#xff1a;统计用户的访问次数 业务需求&#xff1a; 统计每个用户对程序的访问次数将访问次数存储到数据库中访问次数应该与用户进行关联 业务逻辑&#xff1a; 如果用户是第一次访问此程序&#xff0c;向数据库添加一条记录&#xff1a;{openid&#xff1a;45454…

shop--12.阿里云部署以及域名绑定

一、申请阿里云服务器&#xff08;1&#xff09;PC访问阿里云https://www.aliyun.com/&#xff0c;申请阿里云帐号&#xff08;可以用您的支付宝帐号登录&#xff0c;因为支付宝帐号已经进行了实名认证&#xff0c;使用起来更方便&#xff09;并登录&#xff08;2&#xff09;找…

微信小程序——获取用户的运动步数

程序获取用户信息步骤 点击参考微信文档中的授权首先程序先向用户申请访问哪些权限用户做出选择后返回给程序程序携带权限访问服务器如果用户允许则返回信息如果用户为允许则不返回 自定义函数getUserRun 为获取用户的微信运动数据 页面加载调用此函数函数中执行下面操作 1…

C++之前置自增与后置自增

关于前置自增与后置自增的区别我是参考这里&#xff1a;http://bbs.bccn.net/thread-454977-1-1.html 简单复述下&#xff0c;比如x; 与 x; 在C中&#xff0c;x这个表达式的值为原先x的值1&#xff0c;副作用是x的值增加了1&#xff1b;&#xff08;C中不是这样定义的&#xff…

第一次个人作业

该作业所属课程&#xff1a;https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2作业要求地址&#xff1a;https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2/homework/3340团队名称&#xff1a;脑壳痛 作业的目标 1.通过测试其他组的软件项目学习其…

微信小程序——解决上传并部署云函数时报错ResourceNotFound.Function, 未找到函数版本,请创建后再试。 (7f2d9d2d-5eac-4575-9n57-acd66cfa587g

1. 上传部署我们的云函数 2. 报错 错误信息为&#xff1a;Error: ResourceNotFound.Function, 未找到函数版本&#xff0c;请创建后再试。 (7f2d9d2d-5eac-4575-9b57-acd66cfa587e) 3. 原因 原因是可能我们在调试的时候不小心将我们开发控制台中的云函数删除了 4. 解决办法…

前端面试题——HTML基础篇

如何进行网站的性能优化 content方面 减少http请求 合并文件 css精灵图减少 DNS 查询 DNS缓存 将资源分布到恰当数量的主机名减少 DOM 元素的数量 Server方面 使用CDN配置Etag对组件使用 Gzip 压缩 Cookie方面 减小cookie大小 css方面 将样式表放到页面顶部不使用css表…

【IT界的厨子】酱香鲈鱼

食材: 前世曾经回眸的鲈鱼一条(主要选刺少的鱼&#xff0c;适合孩子吃&#xff0c;大人吃随意&#xff0c;草鱼比较大) 五花肉少许(肥一些的) 豆腐 辅料: 葱姜 蒜(选) 大料 香菜 调味: 啤酒(两罐) 黄豆酱或豆瓣酱(选) 老抽 生抽 料酒 盐 步骤: 1、鱼肉划开&#xff0c;方便炖的…

第二章:09流程控制[3for]

①格式for(初始化语句;判断条件语句;控制条件语句) { 循环体语句; } ②注意事项A:判断条件语句无论简单还是复杂结果是boolean类型。 B:循环体语句如果是一条语句,大括号可以省略&#xff1b;如果是多条语句,大括号不能省略。建议永远不要省略。 C:一般来说&#xff1a;有左大括…

LeetCode,第377场周赛,个人题解

目录 100148.最小数字游戏 题目描述 思路分析 代码详解 100169.移除栅栏得到的正方形田地的最大面积 题目描述 思路分析 代码详解 100156.转换字符串的最小成本I 题目描述 思路分析 代码详解 100158.转换字符串的最小成本II 题目描述 思路分析 代码详解 100148.…

for each....in、for in、for of

一、一般的遍历数组的方法: var array [1,2,3,4,5,6,7]; for (var i 0; i < array.length; i) { console.log(i,array[i]); } 二、用for in的方遍历数组 for(let index in array) { console.log(index,array[index]); }; 三、forEach array.forEach(v>{ cons…