spring boot 之 接口参数校验

引入pom依赖

<!--参数校验-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

统一返回结果封装

import lombok.Data;import java.io.Serializable;@Data
public class Result<T> implements Serializable {private Integer code;private String msg;private T data;}
import lombok.Getter;@Getter
public enum ResultEnum {SUCCESS(200, "请求成功"),FAIL(500, "请求失败");private final Integer code;private final String msg;ResultEnum(Integer code, String msg) {this.code = code;this.msg = msg;}}
public class AjaxResult {public static <T> Result<T> success() {return common(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null);}public static <T> Result<T> success(T data) {return common(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data);}public static <T> Result<T> fail() {return common(ResultEnum.FAIL.getCode(), ResultEnum.FAIL.getMsg(), null);}public static <T> Result<T> fail(String msg) {return common(ResultEnum.FAIL.getCode(), msg, null);}/*** 公共响应方法*/private static <T> Result<T> common(Integer code, String msg, T data) {Result<T> result = new Result<>();result.setCode(code);result.setMsg(msg);result.setData(data);return result;}
}

全局异常处理

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;@Data
@Setter
@Getter
@EqualsAndHashCode(callSuper = true)
public class SelfException extends RuntimeException {private String message;public SelfException(String message) {this.message = message;}public SelfException(String message, Throwable e) {super(message);this.message = message;}@Overridepublic String getMessage() {return message;}
}
import com.sun.result.AjaxResult;
import com.sun.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import javax.validation.ConstraintViolationException;
import java.util.List;@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {/*** 参数校验异常*/@ExceptionHandler(ConstraintViolationException.class)@ResponseBodypublic Result<Object> error(Exception e) {log.error("参数校验异常:{}", e.getMessage());return AjaxResult.fail(e.getMessage());}/*** 参数校验异常*/@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseBodypublic Result<Object> error(MethodArgumentNotValidException e) {// 获取异常体BindingResult bindingResult = e.getBindingResult();// 从异常体中获取所有异常列表List<FieldError> errors = bindingResult.getFieldErrors();// 要返回的字符串,拼接的是参数名称以及对应的报错提示StringBuilder messageBuilder = new StringBuilder();String message = null;for (FieldError error : errors) {// 报错的参数String field = error.getField();// 报错的信息message = error.getDefaultMessage();// 拼接参数名称以及对应的报错提示messageBuilder.append(field).append("\t").append(message).append("\n");}log.error("参数校验异常详情:{}", messageBuilder);return AjaxResult.fail(message);}/*** 自定义异常*/@ExceptionHandler(SelfException.class)@ResponseBodypublic Result<Object> error(SelfException e) {log.error("自定义异常:{}", e.getMessage());return AjaxResult.fail(e.getMessage());}/*** 空指针异常*/@ExceptionHandler(NullPointerException.class)@ResponseBodypublic Result<Object> error(NullPointerException e) {log.error("空指针异常:{}", e.getMessage());return AjaxResult.fail("空指针异常");}/*** 拦截运行时异常*/@ExceptionHandler(value = RuntimeException.class)@ResponseBodypublic Result<Object> runtimeExceptionHandle(RuntimeException e) {log.error("捕捉到运行时异常:{}", e.getMessage());return AjaxResult.fail("系统运行中异常");}/*** 兜底异常,捕获系统级异常*/@ExceptionHandler(value = Throwable.class)@ResponseBodypublic Result<Object> throwableHandle(Throwable throwable) {log.error("捕获系统级异常:{}", throwable.getMessage());return AjaxResult.fail("系统程序异常");}}

@Valid@Validated的区别

参数验证使用到了两个关键注解,区分如下:

1、来源
@Validated:是Spring框架特有的注解,属于Spring的一部分,也是JSR 303的一个变种。它提供了一些 @Valid 所没有的额外功能,比如分组验证。
@ValidJava EE提供的标准注解,它是JSR 303规范的一部分,主要用于Hibernate Validation等场景。

2、注解位置
@Validated: 用在类、方法和方法参数上,但不能用于成员属性。
@Valid:可以用在方法、构造函数、方法参数和成员属性上。

3、分组
@Validated:支持分组验证,可以更细致地控制验证过程。此外,由于它是Spring专有的,因此可以更好地与Spring的其他功能(如Spring的依赖注入)集成。
@Valid:主要支持标准的Bean验证功能,不支持分组验证。

4、嵌套验证
@Validated:不支持嵌套验证。
@Valid:支持嵌套验证,可以嵌套验证对象内部的属性。

新建实体类与控制层

import lombok.Data;import javax.validation.constraints.NotBlank;
import java.util.Date;@Data
public class SysUser {private Integer id;@NotBlank(message = "姓名不得为空!")private String name;}
// 个人理解 @Validated 和 @Valid 使用方法
// 如果控制层的接口中有test01这样传参是实体类的,在类前加@Valid或者@Validated注解,实体类标记的参数校验注解才会起作用;
// 如果接口参数是test02这样直接传参数的,要在控制层的类上加@Validated注解,参数前标记的参数校验注解才会起作用;
@Validated
@RestController
@RequestMapping(value = "sysUser", produces = "application/json; charset=utf-8")
public class SysUserController {@PostMapping("test01")public Result<SysUser> test01(@RequestBody @Valid SysUser sysUser) {return AjaxResult.success(sysUser);}@GetMapping("test02")public Result<String> test02(@RequestParam("name") @NotBlank(message = "姓名不得为空!") String name) {return AjaxResult.success("OK: " + name);}}

接口访问测试

访问test01接口,返回如下:

{"code": 500,"msg": "姓名不得为空!","data": null
}

访问test02接口,返回如下:

{"code": 500,"msg": "test2.name: 姓名不得为空!","data": null
}

常用注解

@AssertFalse[必须为false]

@AssertFalse(message = "结果必须为false")
private boolean flag;

AssertTrue[必须为true]

@AssertTrue(message = "参数必须为true")
private boolean flag;

DecimalMax

数字,其值必须小于或等于指定的最大值;

支持的类型有:BigDecimalBigIntegerCharSequencebyteshortintlong以及他们的包装类。

@DecimalMax(value = "10", message = "参数age应该小于或等于10.")
private int age;

DecimalMin

数字,其值必须大于或等于指定的值

支持的类型有:BigDecimalBigIntegerCharSequencebyteshortintlong以及他们的包装类。

@DecimalMin(value = "10", message = "参数age应该大于或等于10.")
private int age;

Digits

整数位数不能超过integer位数,小数位数不能超过fraction位数

支持的类型有:BigDecimalBigIntegerCharSequencebyteshortintlong以及他们的包装类。

@Digits(integer = 1, fraction = 2, message = "整数位数不能超过1,小数位数不能超过2.")
private BigDecimal num;

Email

参数必须为email格式,如果参数为空,也会通过校验,所以如果参数为非空且必须为email格式时,需要与@NotNull结合使用。

适用于字符串类型的校验

@Email(message = "参数必须为email格式.")
@NotNull(message = "参数不能为null.")
private String email;

Future

参数必须为将来的日期或时间,适用于日期,时间等参数类型:java.util.Datejava.util.Calendarjava.time.LocalDatejava.time.LocalDateTime等等。

@Future(message = "日期参数必须为将来的时间.")
private Date time;
@Future(message = "任务时间参数必须为将来的时间.")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date time;

FutureOrPresent

参数必须为当前或将来的日期或时间

@FutureOrPresent(message = "任务时间参数必须为当前或将来的时间.")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date time;

Max

数值类型,值必面小于或等于一个值。

@Max(value = 99 , message = "年龄参数最大不能超过99.")
private int age;

Min
数值类型,值必面大于或等于一个值。

@Min(value = 18 , message = "年龄参数必须大于或等于18.")
private int age;

Negative
数值,参数校验必须为负数。

@Negative(message = "value必须为负数.")
private int num;

NegativeOrZero
数值,参数校验必须为负数或者0。

@Negative(message = "value必须为负数.")
private int num;

NotBlank
参数为字符串,且不能为空,至少包含一个非空白字符串

@NotBlank(message = "value参数不能为空.")
private String num;

NotEmpty
参数为字符串,且不能为空,不能为空字符串,空白字符串可以通过校验。

@NotEmpty(message = "value参数不能为空,不能为空字符串.")
private String num;

NotNull
参数为任意类型,且不能为空。

@NotNull(message = "value参数不能为空.")
private String num;

Null
参数必须为Null

@Null(message = "value参数应该为空.")
private String num;

Past
时间参数需要一个过去的时间

@Past(message = "时间参数需要是过去的时间")
private Date num;

PastOrPresent
时间参数需要是过去的时间或当前的时间,而不是将来。

@PastOrPresent(message = "时间参数需要是过去的时间或当前的时间,而不是将来。")
private Date num;

Pattern
正则表达式参数校验,必须满足对应的正则表达式语法
比如电话号码校验

@Pattern(regexp = "^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$",message = "参数必须为电话号码!")
private String phoneNum;

Positive
数值校验,校验参数必须为正数。

@Positive(message = "参数必须为正数!")
private BigDecimal num;

PositiveOrZero
数值校验,校验参数必须为正数或者0。

@PositiveOrZero(message = "参数必须为正数或者0!")
private BigDecimal num;

Size
字符数校验,最小min个字符,最大max字符,max可以省去,默认为Integer.MAX_VALUE

@Size(min = 5, max = 10,message = "参数需要最少五个字符,最大10个字符!")
private String num;
@Size(min = 5, message = "参数需要最少五个字符!")
private String num;

Length
org.hibernate.validator.constraints中的注解,有点类似Size注解
校验字符串长度是否在minmax之间

@Length(min = 5, max = 10, message = "参数需要最少五个字符,最大10个字符!")
private String num;

Range
范围校验,数值型适用

@Range(min = 60, max = 100, message = "Value值需要在60至100之间")
private int num;

Regexp正则

@Pattern(regexp = "^(agree|disagreeToModify|disagreeToEnd)$", message = "只能传agree、disagreeToModify、disagreeToEnd")
private String agree;

嵌套校验

嵌套校验(Nested Validation) :指的是在验证对象时,对对象内部包含的其他对象进行递归验证的过程。当一个对象中包含另一个对象作为属性,并且需要对这个被包含的对象也进行验证时,就需要进行嵌套校验。

嵌套属性:指的是在一个对象中包含另一个对象作为其属性的情况。换句话说,当一个对象的属性本身又是一个对象,那么这些被包含的对象就可以称为嵌套属性。

其实就是在当前实体类中的某个属性,是另一个实体类,两个实体类一起校验。

import lombok.Data;import javax.validation.constraints.NotBlank;
import java.util.Date;@Data
public class SysUser {private Integer id;@NotBlank(message = "姓名不得为空!")private String name;// 嵌套校验@NotNull(message = "jobDetail不能为空")// 必加注解,否则JobDetail类中的参数校验注解不生效@Validprivate JobDetail jobDetail;}

分组校验

分组验证是为了在不同的验证场景下能够对对象的属性进行灵活地验证,从而提高验证的精细度和适用性。一般我们在对同一个对象进行保存或修改时,会使用同一个类作为入参。那么在创建时,就不需要校验id,更新时则需要校验用户id,这个时候就需要用到分组校验了。

对于定义分组有两点要特别注意

  1. 定义分组必须使用接口。
  2. 要校验字段上必须加上分组,分组只对指定分组生效,不加分组不校验。

创建分组

// CreationGroup 用于创建时指定的分组:public interface CreationGroup {
}
// UpdateGroup 用于更新时指定的分组:public interface UpdateGroup {
}

用户类

import lombok.Data;import javax.validation.constraints.NotBlank;
import java.util.Date;@Data
public class SysUser {@Min(value  = 1, message = "id不能小于1", groups = {UpdateGroup.class})private Integer id;@NotEmpty(message = "姓名不得为空!" , groups = {CreationGroup.class})private String name;}

创建接口

@RestController
@RequestMapping("sysUser")
public class SysUserController {@GetMapping("updateUser")public UserBean updateUser(@Validated({UpdateGroup.class}) SysUser sysUser){return sysUser;}@GetMapping("createUser")public UserBean createUser(@Validated({CreationGroup.class})  SysUser sysUser){return sysUser;}
}

测试

1、先对 createUser接口进行测试,我们将id的值设置为0,也就是不满足id必须大于0的条件,同样username不传值,即不满足 username 不能为空的条件。

{"code": 500,"msg": "姓名不得为空!","data": null
}

2、再对 updateUser接口进行测试,条件和测试 createUser接口的条件一样,再看测试结果,和 createUser接口测试结果完全相反,只提示了id最小不能小于1。

{"code": 500,"msg": "id不能小于1","data": null
}

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

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

相关文章

申请的商标名称相同或近似,如何解决!

最近遇到一些首次申请注册商标的主体&#xff0c;基本想的名称都是两个字或或者两个字加通用词&#xff0c;还有用的行业描述词或缺乏显著特征词&#xff0c;这样去申请注册商标&#xff0c;普推知产老杨分析这样去直接申请注册大概率驳回。 两个字基本上注册的差不多了&#…

Ubuntu 20.04中用scrapy爬取博客园新闻首页的简单示例

一、梳理scrapy项目目录创建&#xff1a; 1、命令行终端定位到pycharm主目录&#xff1a;cd PycharmProjects 2、建立项目名称&#xff1a;scrapy startproject searchArticle 3、定位到项目目录下&#xff1a;cd searchArticle 4、设置爬虫名称与欲爬取的域名地址&#xf…

可变参数函数

可变参数函数指的是函数的参数个数可变&#xff0c;参数类型不定的函数。 C提供了两种主要的方法&#xff1a; &#xff08;1&#xff09;如果所有的实参类型相同&#xff0c;可以传递一个名为initializer_list的标准库类型。 &#xff08;2&#xff09;如果所有的实参类型不完…

为什么c语言不对0和NULL做严格的区分?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01;这个答案很简单:c语言不区分…

上海亚商投顾:沪指冲高回落 电力、电网产业链持续爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日震荡调整&#xff0c;深成指、创业板指均跌超1%。电力、电网股再度爆发&#xff0c;众智科技、郴电国…

展望跨境智慧银行在全球化金融服务中的发展趋势和机遇

一、引言 随着全球经济的不断融合和金融科技的迅猛发展,跨境智慧银行作为连接不同国家和地区金融市场的桥梁,正逐渐展现出其独特的魅力和潜力。跨境支付与结算作为跨境智慧银行的核心业务之一,随着全球化的深入发展和国际贸易的日益频繁,其业务场景也愈发丰富和复杂。本文…

武大深度学习期末复习-常见神经网络概念

深度学习经典神经网络概念、优缺点及应用场景 文章目录 一、多层感知机&#xff08;MLP&#xff09;1.1 结构和原理1.2 优缺点1.3 应用场景 二、卷积神经网络&#xff08;CNN&#xff09;2.1 结构和原理2.2 优缺点2.3 应用场景 三、循环神经网络&#xff08;RNN&#xff09;3.1…

15.微信小程序之async-validator 基本使用

async-validator是一个基于 JavaScript 的表单验证库&#xff0c;支持异步验证规则和自定义验证规则 主流的 UI 组件库 Ant-design 和 Element中的表单验证都是基于 async-validator 使用 async-validator 可以方便地构建表单验证逻辑&#xff0c;使得错误提示信息更加友好和…

#笔记#笔记#其他

大鱼论文是一款非常靠谱、方便、值得推荐的论文写作工具。无论是在学术研究中还是在日常写作中&#xff0c;大鱼论文都能够帮助用户轻松完成论文的写作工作。 首先&#xff0c;大鱼论文提供了强大的查重降重功能&#xff0c;能够帮助用户快速定位论文中可能存在的抄袭问题&…

Xcode 15 libarclite 缺失问题

升级到Xcode 15运行项目报错&#xff0c;报错信息如下&#xff1a; SDK does not contain libarclite at the path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a; try increasing the minimum d…

电力业务模型

电力业务模型 目录概述需求&#xff1a; 设计思路实现思路分析 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,challenge Survive. happy…

华为超融合数据中心网络【笔记】

对动态流量和海量参数调整&#xff0c;提炼出不同的流量特征模型&#xff1b;在交换机中实时采集流量特征和网络状态&#xff0c;使用独创的iLossless智能无损算法&#xff0c;本地实时决策并动态调整网络参数配置&#xff0c;使得交换机缓存被合理高效利用&#xff0c;实现整网…

基于PHP+MySQL组合开发的720VR全景小程序源码系统 一键生成三维实景 前后端分离带网站的安装代码包以及搭建教程

系统概述 这款源码系统是专门为实现 720VR 全景展示而设计的。它结合了先进的技术和创新的理念&#xff0c;能够将真实场景以全景的形式呈现给用户&#xff0c;让用户仿佛身临其境。该系统采用 PHP 进行后端开发&#xff0c;MySQL 作为数据库管理系统&#xff0c;确保了系统的…

debian 常用命令

Debian 是一个广泛使用的 Linux 发行版&#xff0c;这里列出了一些常用的 Debian 命令&#xff0c;适用于系统管理和日常使用&#xff1a; ### 文件与目录操作 1. **ls** - 列出目录内容&#xff1a; bash ls ls -l # 长格式显示 ls -a # 显示所有文件&#xff…

G60-M60F-ZQ手动抓取快速接头,专用于吊装设备的重物快速抓取

客户需求概述&#xff1a; 客户需要将重达将近400公斤的产品从一个工作台移动至另一个工作台&#xff0c;目前的方法是通过人工将吊环的螺纹与产品的螺纹相互拧紧&#xff0c;然后利用装备吊起移动&#xff0c;但这种方式效率低下&#xff0c;且因为工人的操作有时难以达到理想…

使用vanna实现Text2SQL

这节一起用vanna来实现自然语言转SQL&#xff0c;之前的大模型一直停留在问答阶段&#xff0c;答案基本都是大模型提供的&#xff0c;至多是加点本地知识库&#xff0c;tet&#xff0c;pdf等文档&#xff0c;丰富大模型的内容&#xff0c;但是想要大模型与一些管理系统对接还是…

XDebug配置极简教程,phpstorm实现http请求断点调试

写这篇的文章的初衷:网络上配置XDebug的文章有很多,XDebug也有官方的文档, PhpStorm也有官方的文档,为什么还要写那? 相信不少人,都有一种感觉,虽然教程很多,但是按教程走一遍,自己的确不能正常调试。 问题出在下面几个方面: 1. 对调试过程中,没有一定的认识,因此…

使用ETL读取文件数据并快速写入mysql中

本文介绍使用国产的ETL工具ETLCloud平台来读取文件文件中的数据到mysql数据库中&#xff0c;首先需要安装ETLCloud的社区版本&#xff0c;然后在示例应用中创建一个文件读取流程如下&#xff1a; 点击“流程设计”后打开流程图如下 打开文本文件读取节点配置要读取的文件目录和…

刷代码随想录有感(82):贪心算法——摆动序列

题干&#xff1a; 代码&#xff1a; class Solution { public:int wiggleMaxLength(vector<int>& nums) {if(nums.size() < 1)return nums.size();int prediff 0;int curdiff 0;int res 1;for(int i 0; i < nums.size() - 1; i){curdiff nums[i 1] - nu…

【美羊羊拿金币问题】

问题&#xff1a; 有一天美羊羊正在草地上玩耍&#xff0c;突然天上开始落金币&#xff0c;这些金币掉落的范围在一个固定的水平区域内&#xff0c;但这些金币一旦掉落到地上就消失了&#xff0c;因此美羊羊只有不断地移动并从空中接住这些金币才能得到它们。假设金币掉落的位…