Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring Boot参数校验以及分组校验的使用

Spring Boot参数校验以及分组校验的使用

作者头像
Vincent-yuan
发布于 2021-08-12 03:47:06
发布于 2021-08-12 03:47:06
1.8K00
代码可运行
举报
文章被收录于专栏:Vincent-yuanVincent-yuan
运行总次数:0
代码可运行

一 前言

做web开发有一点很烦人就是要对前端输入参数进行校验,基本上每个接口都要对参数进行校验,比如一些非空校验、格式校验等。

如果参数比较少的话还是容易处理的一但参数比较多了的话代码中就会出现大量的if-else语句。 使用这种方式虽然简单直接,但是也有不好的地方,一是降低了开发效率,因为我们需要校验的参数会存在很多地方,并且不同地方会有重复校验,其次降低了代码可读性,因为在业务代码中掺杂了太多额外工作的代码。 所以我们可以使用validator组件来代替我们进行不必要的coding操作。

本文基于validator的介绍资料,也结合自己在项目中的实际使用经验进行了总结,希望能帮到大家。

1 什么是validator

Bean Validation是Java定义的一套基于注解的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),已经经历了三个版本 。

需要注意的是,JSR只是一项标准,它规定了一些校验注解的规范,但没有实现,比如@Null、@NotNull、@Pattern等,它们位于 javax.validation.constraints这个包下。

而hibernate validator是对这个规范的实现,并增加了一些其他校验注解,如 @NotBlank、@NotEmpty、@Length等,它们位于org.hibernate.validator.constraints这个包下。 如果我们的项目使用了Spring Boot,hibernate validator框架已经集成在 spring-boot-starter-web中,所以无需再添加其他依赖。

如果不是Spring Boot项目,需要添加如下依赖。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.8.Final</version>
</dependency>

二 注解介绍

1 validator内置注解

注解

说明

@Null

被注释的元素必须为null

@NotNull

被注释的元素不能为null

@AssertTrue

被注释的元素必须为true

@AssertFalse

被注释的元素必须为false

@Min(value)

被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@Max(value)

被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@DecimalMin(value)

被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@DecimalMax(value)

被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@Size(max,min)

被注释的元素的大小必须在指定的范围内

@Digits(integer, fraction)

被注释的元素必须是一个数字,其值必须必须在可接受的范围内

@Past

被注释的元素必须是一个过去的日期

@Future

被注释的元素必须是一个将来的日期

@Pattern(value)

被注释的元素必须符合指定的正则表达式

hibernate validator中扩展定义了如下注解:

注解

说明

@NotBlank

被注释的元素不能为null,且长度必须大于0,只能用于注解字符串

@Email

被注释的元素必须是电子邮箱地址

@Length(min=,max=)

被注释的字符串的大小必须在指定的范围内

@NotEmpty

被注释的元素值不为null且不为空,支持字符串、集合、Map和数组类型

@Range

被注释的元素必须在规定的范围内

三 使用

使用起来比较简单,都是使用注解方式使用。

具体来说分为单参数校验、对象参数校验,单参数校验就是controller接口按照单参数接收前端传值,没有封装对象进行接收,如果有封装对象那就是对象参数校验。

1 单参数校验

单参数校验只需要在参数前添加注解即可,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public Result deleteUser(@NotNull(message = "id不能为空") Long id) {
  // do something
}

但有一点需要注意,如果使用单参数校验,controller类上必须添加@Validated注解,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RestController
@RequestMapping("/user")
@Validated // 单参数校验需要加的注解
public class UserController {
  // do something
}

2 对象参数校验

对象参数校验使用时,需要先在对象的校验属性上添加注解,然后在Controller方法的对象参数前添加@Validated 注解,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public Result addUser(@Validated UserAO userAo) {
    // do something
}

public class UserAO {
  @NotBlank
  private String name;

  @NotNull
  private Integer age;
  
  ……
}
注解分组

在对象参数校验场景下,有一种特殊场景,同一个参数对象在不同的场景下有不同的校验规则。

比如,在创建对象时不需要传入id字段(id字段是主键,由系统生成,不由用户指定),但是在修改对象时就必须要传入id字段。

在这样的场景下就需要对注解进行分组。

1)组件有个默认分组Default.class, 所以我们可以再创建一个分组UpdateAction.class,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface UpdateAction {
}

2)在参数类中需要校验的属性上,在注解中添加groups属性:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class UserAO {

    @NotNull(groups = UpdateAction.class, message = "id不能为空")
    private Long id;
    
    @NotBlank
    private String name;

    @NotNull
    private Integer age;
    
    ……
}

如上所示,就表示只在UpdateAction分组下校验id字段,在默认情况下就会校验name字段和age字段。

然后在controller的方法中,在@Validated注解里指定哪种场景即可,没有指定就代表采用Default.class,采用其他分组就需要显示指定。如下代码便表示在addUser()接口中按照默认情况进行参数校验,在updateUser()接口中按照默认情况和UpdateAction分组对参数进行共同校验。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public Result addUser(@Validated UserAO userAo) {
  // do something
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public Result updateUser(@Validated({Default.class, UpdateAction.class}) UserAO userAo) {
  // do something
}
对象嵌套

如果需要校验的参数对象中还嵌套有一个对象属性,而该嵌套的对象属性也需要校验,那么就需要在该对象属性上增加@Valid注解。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class UserAO {

    @NotNull(groups = UpdateAction.class, message = "id不能为空")
    private Long id;
    
    @NotBlank
    private String name;

    @NotNull
    private Integer age;
    
    @Valid
    private Phone phone;
    
    ……
}

public class Phone {
    @NotBlank
    private String operatorType;
    
    @NotBlank
    private String phoneNum;
}

3 错误消息的捕获

参数校验失败后会抛出异常,我们只需要在全局异常处理类中捕获参数校验的失败异常,然后将错误消息添加到返回值中即可。

捕获异常的方法如下所示,返回值Result是我们系统自定义的返回值类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@RestControllerAdvice(basePackages= {"com.alibaba.dc.controller","com.alibaba.dc.service"})
public class GlobalExceptionHandler {

  @ExceptionHandler(value = {Throwable.class})
  Result handleException(Throwable e, HttpServletRequest request){
    // 异常处理
        }
}

需要注意的是,如果缺少参数抛出的异常是MissingServletRequestParameterException,单参数校验失败后抛出的异常是ConstraintViolationException,get请求的对象参数校验失败后抛出的异常是BindException,post请求的对象参数校验失败后抛出的异常是MethodArgumentNotValidException,不同异常对象的结构不同,对异常消息的提取方式也就不同。

1)MissingServletRequestParameterException

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(e instanceof MissingServletRequestParameterException){
    Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL);
    String msg = MessageFormat.format("缺少参数{0}", ((MissingServletRequestParameterException) e).getParameterName());
    result.setMessage(msg);
    return result;
}

2)ConstraintViolationException异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(e instanceof ConstraintViolationException){
  // 单个参数校验异常
  Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL);
  Set<ConstraintViolation<?>> sets = ((ConstraintViolationException) e).getConstraintViolations();
  if(CollectionUtils.isNotEmpty(sets)){
    StringBuilder sb = new StringBuilder();
    sets.forEach(error -> {
                    if (error instanceof FieldError) {
                        sb.append(((FieldError)error).getField()).append(":");
                    }
                    sb.append(error.getMessage()).append(";");
                });
    String msg = sb.toString();
    msg = StringUtils.substring(msg, 0, msg.length() -1);
    result.setMessage(msg);
  }
  return result;
}

3)BindException异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (e instanceof BindException){
      // get请求的对象参数校验异常
      Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL);
      List<ObjectError> errors = ((BindException) e).getBindingResult().getAllErrors();
      String msg = getValidExceptionMsg(errors);
      if (StringUtils.isNotBlank(msg)){
        result.setMessage(msg);
      }
      return result;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private String getValidExceptionMsg(List<ObjectError> errors) {
  if(CollectionUtils.isNotEmpty(errors)){
    StringBuilder sb = new StringBuilder();
    errors.forEach(error -> {
                    if (error instanceof FieldError) {
                       sb.append(((FieldError)error).getField()).append(":");
                    }
                    sb.append(error.getDefaultMessage()).append(";");
                });
    String msg = sb.toString();
    msg = StringUtils.substring(msg, 0, msg.length() -1);
    return msg;
  }
  return null;
}

4)MethodArgumentNotValidException异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (e instanceof MethodArgumentNotValidException){
      // post请求的对象参数校验异常
      Result result = Result.buildErrorResult(ErrorCodeEnum.PARAM_ILLEGAL);
      List<ObjectError> errors = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors();
      String msg = getValidExceptionMsg(errors);
      if (StringUtils.isNotBlank(msg)){
        result.setMessage(msg);
      }
      return result;
}

转自:

https://mp.weixin.qq.com/s/x6_mNdtb6i2XmTiyz4kXrg

使用起来比较简单,都是使用注解方式使用。具体来说分为单参数校验、对象参数校验,单参数校验就是controller接口按照单参数接收前端传值,没有封装对象进行接收,如果有封装对象那就是对象参数校验。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
机器之心GMIS 2017圆满闭幕,全面解读前沿研究、产业落地及AI全球化
机器之心原创 机器之心编辑部 5 月 28 日,机器之心主办的第一届全球人工智能峰会(GMIS 2017)顺利闭幕。在为期两天的大会中,许多学界和业界的重量级嘉宾在 GMIS 的舞台上分享了机器学习的前沿进展、交叉学科的新奇思想、人工智能的炫酷应用以及机器智能时代的创业经验。在第一天,有「LSTM 之父」之称的 Dalle Molle 人工智能研究所副主任 Jürgen Schmidhuber、Citadel 首席人工智能官邓力、腾讯 AI Lab 副主任俞栋等嘉宾为我们带来了干货十足的头脑风暴和前沿解读。
机器之心
2018/05/07
6410
机器之心GMIS 2017圆满闭幕,全面解读前沿研究、产业落地及AI全球化
【327峰会直击】新智元“春节”引爆AI原力,群星纵论中国AI大棋局
【新智元导读】新智元327技术峰会今天圆满举行。 腾讯科技直播地址:http://v.qq.com/live/p/topic/26417/preview.html 2017年3月27日,一场中国人工智能界的 “狂欢节” 在北京盛大启幕:智能+中国主平台新智元携手行业巨头英特尔联合举办新智元2017开源·生态AI技术峰会暨新智元创业大赛颁奖盛典。包括“BAT”在内的中国主流 AI 公司、600多名行业精英齐聚,共同为2017中国人工智能的发展画上浓墨重彩的一笔。 新智元连续两年在3月27日举办行业技术峰会,
新智元
2018/03/27
1.2K0
【327峰会直击】新智元“春节”引爆AI原力,群星纵论中国AI大棋局
72小时AI生存挑战,发生了什么?| Q推荐
7 位来自不同背景的参与者——大厂产品经理、20 岁大学生、独立开发者、大模型算法工程师、金鸡奖提名导演、AI 博士生……在一个 72 小时的 AI 封闭空间,没有智能手机,无法使用 APP、浏览器等互联网及移动互联网产品,只有 AI 工具和 100 元启动资金。他们需要靠 AI 活下来,最好还能创造点什么。
深度学习与Python
2025/06/13
160
72小时AI生存挑战,发生了什么?| Q推荐
一周AI看点 |上汽拿到加州第35张自动驾驶测试牌照,下一代Windows 10更新可用AI抵御勒索病毒
大家好,今天又是周末了,又双叒叕到了给大家写AI行业一周回顾的“好时候”了。今天是7月2日,想到此,小编内心惶恐不安,因为 我却是没什么太大的进步,该念的书还是没有念,该上的课也错过好几期了,真的好心痛... 如果周一到周五以工作忙,学习忙为借口,好吧,我可以原谅自己下班后懒惰一下,但是周末如果还不利用时间学习下,简直无法原谅自己... 因为我深深知道能主宰周末的人生才是赢家。 好了,感慨完毕,我们一起看看本周AI圈儿里都发生了哪些事儿。 行业 ➤埃森哲预测:2035年人工智能有望拉动中国经济增
AI科技大本营
2018/04/26
1.1K0
一周AI看点 |上汽拿到加州第35张自动驾驶测试牌照,下一代Windows 10更新可用AI抵御勒索病毒
马云底特律演讲:AI革命或引发第三次世界大战,但胜利属于人类
文字来源 | 环球时报 当地时间6月21日,马云在“连接世界”美国中小企业论坛上,发表了以“中国的贸易机会”为主题的公开演讲。演讲中他不仅收获了现场观众的数次热烈鼓掌,也引发了线上网友的极大共鸣。 马云讲到:“我问过很多美国人对中国有何印象,答案总是熊猫、自行车、长城、太极……中国已经改变了,中国已经从无名小卒,成长为今天的全球第二大经济体”。马云认为,未来30年对中小企业意味着新的机遇,“在中国你能找到几乎所有的美国大企业,但我们需要更多中小企业。我鼓励政府要为中小企制定特别自由贸易区。”这一提议得到了在
大数据文摘
2018/05/24
6720
万字长文:AI陪伴产品的终极解法?
导语|此篇文章是本人及多名朋友联合 产品人Super黄 共同创作的深度长文,欢迎对这个话题感兴趣的各位“浩浩爸”们疯狂戳戳俺,一起讨论交流~
腾讯大讲堂
2024/01/03
1.1K0
万字长文:AI陪伴产品的终极解法?
AI时代,人类就业的终极未来
2025年1月8日,由腾讯研究院和腾讯可持续社会价值事业部主办的“2025 腾讯科技向善创新节 T-WEEK”正式播出。本次创新节以“拟合”为主题,包含近二十场主题演讲与圆桌论坛。
小腾资讯君
2025/01/17
2240
纽约客:AI 是否会成为人类的最后发明?
【导读】Nick Bostrom 是《超级智能:路线图、危险性与应对策略》的作者,他认为真正的人工智能可能拥有巨大的威胁,如果人类没有小心处理,很可能会走向自我灭绝的道路。 Bostrom 提出了大过滤器的观点,他说生命总倾向于扩张,但到目前为止我们还没有观察到外星生命。Bostrom 说这可能是大过滤器的原因,所有的文明可能都得发展出某些技术,而新的技术发现也许会导致普遍的生存灾难。 这里所说的技术,就是人工智能。 Bostrom 的论述总有一种“优雅”的悖论:一方面是逻辑清晰的分析和论述,另一方面又不
新智元
2018/03/13
1.6K0
纽约客:AI 是否会成为人类的最后发明?
AI崛起,新闻长存|3万字圆桌实录
本期为《仲夏六日谈》第三季第二期节目文字内容,主题为《生成与真相:大模型时代的传媒业》。
小腾资讯君
2024/08/15
1690
新冠疫情过后,世界将会怎样?| “互联网女皇”疫情趋势深度报告
报告要点: 1、新冠疫情改变了我们的现代化生活方式,但我们对这种变化的理解才刚刚开始。 2、以前的史诗级病毒已经永久性地改变了世界,但是由于目前拥有信息共享和科学技术,所以新冠病毒的影响可能会减弱。 3、科学家和其他领域的专家正在获得更多话语权。 4、由于在家工作的人很多,数字化转型正在加速。工作与生活逐渐达到新的平衡。 5、从远程医疗到快速定点诊断,再到将自动化和人工智能技术在医疗保健领域的应用,这可能会吹响技术与医疗加强融合的号角。 6、“我们是乐观主义者,并相信绝望的另一面是希望……我们需要政府、企
腾讯大讲堂
2020/04/23
8540
人工智障 2 : 你看到的AI与智能无关
两年前,写了一篇文章《为什么现在的人工智能助理都像人工智障》,当时主要是怼“智能助理们”。这次呢则是表达 “我不是针对谁,只是现在所有的深度学习都搞不定对话AI”,以及“你看都这样了,那该怎么做AI产品”。
Fayson
2019/11/28
1.3K0
拐点时刻?AIGC时代的新闻业
2022年底,OpenAI发布自然语言对话应用ChatGPT,并在今年3月迭代推出GPT-4,迅速吸引了各行业与公众的关注。全球范围内大模型风云骤起,资金、技术、人才持续涌入,科技公司布局不断,纷纷推出自家的大模型。据估算,到2030年,AIGC市场规模有望突破万亿元。
小腾资讯君
2023/08/30
6810
拐点时刻?AIGC时代的新闻业
形塑新闻:AI时代新闻业的7个变化|腾讯研究院3万字报告
时至 2024 年 10 月,生成式 AI 的热潮尚未褪去,但现实也已经与 GPT-3 刚刚发布时的那种狂热图景完全不同。人们开始更冷静地审视大模型的技术局限,更关注大模型在各种领域的实际应用与落地情况,以及由此带来的改变。
小腾资讯君
2024/11/11
5590
《增长黑客》节选与笔记[通俗易懂]
这本书涉及了很多具体又贴合现实的互联网产品问题,即使你是非专业人士,也应该读一读,了解开发者是如何把你当猫耍的,以便你更好地认识一些套路,解锁,为选择手机软件或者云端应用擦亮眼睛!
全栈程序员站长
2022/08/27
7.8K0
斯坦福博士退学,在 3 个领域改变世界,科技狂人马斯克的巅峰之路
近日,美股特斯拉(TSLA)股价连创新高,按1月6日收盘价每股451.54美元计算,总市值已达813.9亿美元。
AI科技大本营
2020/02/20
1.4K0
斯坦福博士退学,在 3 个领域改变世界,科技狂人马斯克的巅峰之路
龙哥风向标 20230411~20230418 GPT拆解
盈利点:利用Midjourney的提示词样式衣服商机,可以开展国内的衣服定制业务,提供定制化的提示词样式衣服,包括MJ提示词样式和其丨他样式,同时可以考虑提供定制情侣衫、班服等服务。
ApacheCN_飞龙
2024/01/31
3650
推荐阅读
相关推荐
机器之心GMIS 2017圆满闭幕,全面解读前沿研究、产业落地及AI全球化
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验