Spring Boot 入参校验及全局异常处理
版本依赖
- JDK 17
- Spring Boot 3.2.0
源码地址:Gitee
Spring Boot validation
spring-boot-starter-validation
是基于hibernate-validator
的实现,在Spring Boot项目中直接导入spring-boot-starter-validation
即可。
@Valid 和 @Validated 的区别
- 适用范围:
@Valid
是 Java 校验(JSR-303)的一部分,通常用于标注在方法参数或方法返回值上,以触发参数校验或返回结果的校验。@Validated
是 Spring 提供的,用于在方法级别进行校验。它支持分组校验,并且可以标注在类或方法上。
- 分组校验:
@Valid
支持分组校验,可以通过定义校验接口的不同分组来控制不同情况下的校验规则。@Validated
也支持分组校验,但是它的分组校验是通过在校验注解上指定分组来实现的。
- 校验方式:
@Valid
主要用于标注在方法参数或返回值上,触发 Bean Validation 校验。@Validated
主要用于方法级别的校验,并且支持 Spring 提供的校验方式,例如 Spring 的@NotEmpty
、@Range
等。
- 引入依赖:
- 使用
@Valid
需要引入 Java Bean Validation 的相关依赖,比如 Hibernate Validator。 - 使用
@Validated
需要引入 Spring 的相关依赖,它是 Spring 提供的一个校验框架。
- 使用
- 支持的校验注解:
@Valid
支持 JSR-303(Bean Validation)提供的注解,比如@NotNull
、@Size
等。@Validated
支持 Spring 提供的校验注解,例如@NotEmpty
、@Range
、@Email
等。
- 参数校验异常类:
@Valid
异常类为org.springframework.web.bind.MethodArgumentNotValidException
Validated
异常类为jakarta.validation.ConstraintViolationException
参数校验常用注解
@Null | 验证对象是否为null |
---|---|
@NotNull | 验证对象是否不为null, 无法查检长度为0的字符串 |
@NotBlank | 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格. |
@NotEmpty | 检查约束元素是否为NULL或者是EMPTY. |
@AssertTrue | 验证 Boolean 对象是否为 true |
@AssertFalse | 验证 Boolean 对象是否为 false |
@Size(min=, max=) | 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内 |
@Length(min=, max=) | 验证注解的元素值长度在min和max区间内 |
@Past | 验证 Date 和 Calendar 对象是否在当前时间之前 |
@Future | 验证 Date 和 Calendar 对象是否在当前时间之后 |
@Pattern | 验证 String 对象是否符合正则表达式的规则 |
@Min | 验证 Number 和 String 对象是否大等于指定的值 |
@Max | 验证 Number 和 String 对象是否小等于指定的值 |
@DecimalMax | 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度 |
@DecimalMin | 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度 |
@Digits | 验证 Number 和 String 的构成是否合法 |
@Digits(integer=,fraction=) | 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。 |
@Range(min=, max=) | 验证注解的元素值在最小值和最大值之间 |
用例代码
导入依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
</dependencies>
定义对象参数
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.hibernate.validator.constraints.Length;import java.io.Serial;
import java.io.Serializable;@Data
public class RequestVO implements Serializable {@Serialprivate static final long serialVersionUID = 1L;@NotBlank(message = "用户名不能为空")private String username;@NotBlank(message = "手机号码不能为空")@Length(min = 11, max = 11, message = "手机号码格式错误")private String phoneNumber;
}
定义测试Controller
package com.yiyan.study.controller;import com.yiyan.study.model.RequestVO;
import com.yiyan.study.model.Result;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 参数校验及全局异常处理测试Controller*/
@RestController
@RequestMapping("/ex")
@Validated
public class ExController {@GetMapping("/param_ex")public Result<RequestVO> paramEx(@Valid RequestVO request) {return Result.success();}@GetMapping("/param_in_query")public Result<String> paramInQuery(@NotBlank(message = "PARAM 不能为空") String param,@Min(value = 1, message = "number不能小于1") Integer number) {return Result.success();}
}
Spring Boot 全局异常处理
参数注释
@RestControllerAdvice
: 能够捕获应用中所有控制器抛出的异常@ExceptionHandler
:方法中定义统一的返回格式,比如将异常信息封装成一个标准的 JSON 对象,并设置响应状态码等。@ResponseStatus
:定义响应的HttpStatus,如400,401,403等
自定义业务异常类
import lombok.Data;
import lombok.EqualsAndHashCode;import java.io.Serial;
import java.io.Serializable;/*** 自定义业务异常*/
@EqualsAndHashCode(callSuper = true)
@Data
public class BizException extends RuntimeException implements Serializable {@Serialprivate static final long serialVersionUID = 1L;/*** 错误码*/private final String errorCode;/*** 错误信息*/private final String errorMessage;public BizException(String errorCode, String errorMessage) {super(errorCode);this.errorCode = errorCode;this.errorMessage = errorMessage;}public BizException(String errorCode, String errorMessage, Throwable cause) {super(errorCode, cause);this.errorCode = errorCode;this.errorMessage = errorMessage;}@Overridepublic synchronized Throwable fillInStackTrace() {return this;}
}
自定义API统一返回结构
示例
package com.yiyan.study.model;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;import java.io.Serial;
import java.io.Serializable;/*** 接口统一返回*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Result<T> implements Serializable {@Serialprivate static final long serialVersionUID = 1L;/*** 请求Status*/private String code;/*** 业务信息*/private String message;/*** 返回数据*/private T data;/*** Instantiates a new Result.*/public Result() {}public Result(String code, String message, T data) {this.code = code;this.message = message;this.data = data;}public static <T> Result<T> success() {return new Result<>("200", "请求成功", null);}public static <T> Result<T> success(String code, String message, T data) {return new Result<>(code, message, data);}public static <T> Result<T> error(String code, String message, T data) {return new Result<>(code, message, data);}public static <T> Result<T> error(String code, String message) {return error(code, message, null);}}
自定义全局异常处理类
import com.yiyan.study.model.Result;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.List;
import java.util.Map;
import java.util.TreeMap;/*** 全局异常处理*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {/*** 处理自定义的业务异常** @param req the req* @param e the e* @return result*/@ExceptionHandler(value = BizException.class)public Result<BizException> bizExceptionHandler(HttpServletRequest req, BizException e) {log.error("[ {} ] {} 请求异常: {}", req.getMethod(), req.getRequestURL(), e.getErrorCode());return Result.error(e.getErrorCode(), e.getErrorMessage());}/*** 参数异常信息返回** @param req the req* @param e the e* @return result*/@ResponseStatus(HttpStatus.BAD_REQUEST)@ExceptionHandler(value = MethodArgumentNotValidException.class)public Result<Map<String, String>> methodArgumentNotValidExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException e) {List<ObjectError> allErrors = e.getBindingResult().getAllErrors();log.error("[ {} ] {} 请求参数校验错误", req.getMethod(), req.getRequestURL());Map<String, String> paramExceptionInfo = new TreeMap<>();for (ObjectError objectError : allErrors) {FieldError fieldError = (FieldError) objectError;log.error("参数 {} = {} 校验错误:{}", fieldError.getField(), fieldError.getRejectedValue(), fieldError.getDefaultMessage());paramExceptionInfo.put(fieldError.getField(), fieldError.getDefaultMessage());}return Result.error(HttpStatus.BAD_REQUEST.toString(), "PARAM_EXCEPTION", paramExceptionInfo);}/*** 参数异常信息返回** @param req the req* @param e the e* @return result*/@ResponseStatus(HttpStatus.BAD_REQUEST)@ExceptionHandler(value = ConstraintViolationException.class)public Result<String> constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException e) {log.error("[ {} ] {} 请求参数校验错误", req.getMethod(), req.getRequestURL());return Result.error(HttpStatus.BAD_REQUEST.toString(), "PARAM_EXCEPTION", e.getMessage());}/*** 处理其他异常** @param req the req* @param e the e* @return result*/@ExceptionHandler(value = Exception.class)public Result<String> exceptionHandler(HttpServletRequest req, Exception e) {log.error("[ {} ] {} 未定义异常: {}", req.getMethod(), req.getRequestURL(), e.getMessage());return Result.error("500", e.getMessage());}
}
测试
相关文章:

Spring Boot 入参校验及全局异常处理
版本依赖 JDK 17 Spring Boot 3.2.0 源码地址:Gitee Spring Boot validation spring-boot-starter-validation是基于hibernate-validator的实现,在Spring Boot项目中直接导入spring-boot-starter-validation即可。 Valid 和 Validated 的区别 适用范围…...
MySQL 和 MySQL2 的区别
MySQL是最流行的开源关系型数据库管理系统,拥有大量的使用者和广泛的应用场景。而MySQL2是MySQL官方团队推出的新一代MySQL驱动,用于取代老版的MySQL模块,提供更好的性能和更丰富的功能。 本文将介绍MySQL2相较于MySQL有哪些优势以及具体的技术区别。 …...

AutoCAD图纸打印后内容不见
用户反映,在CAD里的对象打印出来不显示。其实,这是在CAD的打印对象颜色的问题。(在9.2以下版本有这种问题,9.2及以上版本已默认此种颜色) 1.当背景色为黑色的时候,这里的颜色是白,如下图 2.当C…...

ASUS华硕ROG幻16 2023款GU603VU VV VI笔记本电脑原厂Win11.22H2系统
链接:https://pan.baidu.com/s/1AgevUZleCHBJgCBcIp5CFQ?pwdhjxy 提取码:hjxy 华硕笔记本2023款幻16原厂Windows11系统自带所有驱动、出厂主题壁纸、Office办公软件、MyASUS华硕电脑管家、Armoury Crate奥创控制中心等预装程序 文件格式࿱…...
学习笔记 k8s常用kubectl命令
k8s常用kubectl命令 pod 相关强制删除pod查看 Pod 中指定容器的日志pod 扩容 etcd 备份集群设置集群上下文配置文件切换集群 节点cordondrain pod 相关 强制删除pod pod 状态terminal了,需要强制删除 kubectl delete pod <pod_name> --grace-period0 --force…...

企业数据可视化-亿发数据化管理平台提供商,实现一站式数字化运营
近些年来,国内企业数据化管理升级进程持续加速,以物联网建设、人工智能、大数据和5G网络等新技术的发展,推动了数字经济的蓬勃发展,成为维持经济持续稳定增长的重要引擎。如今许多国内中小型企业纷纷摒弃传统管理模式,…...

网络通信-Linux 对网络通信的实现
Linux 网络 IO 模型 同步和异步,阻塞和非阻塞 同步和异步 关注的是调用方是否主动获取结果 同步:同步的意思就是调用方需要主动等待结果的返回 异步:异步的意思就是不需要主动等待结果的返回,而是通过其他手段比如,状态通知࿰…...
mysql修改密码
mysql -u root -p ALTER USER USER() IDENTIFIED BY root; FLUSH PRIVILEGES; 其它cmd: ①查看端口,找到占用3306端口的进程:命令行输入 netstat -aon ,找到端口号为3306的对应的PID ②结束占用端口3306的进程:命令…...
深入解析C语言中void (*signal(int ,void(*)(int) ) ) (int)
目录 深入解析C语言中的signal函数声明 1. signal函数声明 1.1 signal是一个函数 1.2 返回类型是一个函数指针 2. 函数指针的理解 3. 简化声明使用typedef 为啥不这么写typedef void (*)(int) acc? 代码: 结论 深入解析C语言中的signal函数声明…...

网站显示不安全警告怎么办?消除网站不安全警告超全指南
网站显示不安全警告怎么办?当用户访问你的网站,而您的网站没有部署SSL证书实现HTTPS加密时,网站就会显示不安全警告,这种警告,不仅有可能阻止用户继续浏览网站,影响网站声誉,还有可能影响网站在…...

[SWPUCTF 2021 新生赛]finalrce
[SWPUCTF 2021 新生赛]finalrce wp 注:本文参考了 NSSCTF Leaderchen 师傅的题解,并修补了其中些许不足。 此外,参考了 命令执行(RCE)面对各种过滤,骚姿势绕过总结 题目代码: <?php highlight_file(__FILE__); …...

如何底层调用最快地复制OPC数据到关系数据库
计算机上的二大应用,一是从WEB服务器上获得数据,另一种是向关系数据库中写入数据。在上集我已提出了一个从WEB上获得OPC数据的独创方法,现在谈谈第二种如何快速地把OPC数据写进到数据库中,这也是Calssic OPC最典型的一个应用场景。…...

接口测试工具——ApiFox使用初体验 postman导出和ApiFox导入
目录 ApiFox使用初体验初步使用从postman导出到apifox导入 IDEA简单测试Postman测试工具post请求 接口测试工具swaggerKnife4j1.引入依赖2.配置3.常用注解4.接口测试 JMeter什么是JMeter?JMeter安装配置1.官网下载2.下载后解压3.汉语设置 JMeter的使用方法1.新建线程组2.设置参…...

搜维尔科技:经脉腧穴虚拟针灸VR虚拟教学平台AcuMap软件案例分享
北京中医药大学经脉腧穴VR虚拟教学平台案例 主要产品 HTCvive ,AcuMap; 实施内容 一、项目说明 (1)穴位取穴与体表解剖标志关系;(2)穴下层次解剖及周围解剖结构展示; …...
Jenkins的shared library相关
Jenkins的shared library是一种用于在多个Jenkins流水线项目中共享和重用代码的机制。它可以将常用的构建逻辑、工具函数或自定义步骤封装为可复用的库,并以插件的形式提供给Jenkins。 Shared library的作用主要包括以下几个方面: 代码复用:…...

文件IO
文章目录 文章目录 前言 一 . 文件 文件路径 文件类型 Java中操作文件 File 概述 属性 构造方法 方法 createNewFile mkdir 二 . 文件内容的读写 - IO InputStream 概述 FileInputStream 概述 利用 Scanner 进行字符读取 OutputStream 概述 PrintWriter封装O…...

【日常聊聊】编程语言的未来:趋势、多样性、人工智能融合、教育与生态系统
🍎个人博客:个人主页 🏆个人专栏: 日常聊聊 ⛳️ 功不唐捐,玉汝于成 目录 前言: 正文 1. 编程语言的发展趋势 1.1 新语言和编程范式的涌现 1.2 影响和挑战 2. 编程语言的多样性 2.1 互操作性和可移…...

无需手动搜索!轻松创建IntelliJ IDEA快捷方式的Linux教程
轻松创建IntelliJ IDEA快捷方式的Linux教程 一、IntelliJ IDEA简介二、在Linux系统中创建快捷方式的好处三、命令行创建IntelliJ IDEA快捷方式四、图形界面创建IntelliJ IDEA快捷方式五、常见问题总结 一、IntelliJ IDEA简介 IntelliJ IDEA是一个由JetBrains搞的IDE࿰…...

如何去掉微博水印?用它一键去除三秒出图
微博是一款非常流行的社交媒体平台,许多人都在上面分享自己的生活点滴和心得体会。但是,有时候我们会发现,在上传图片时,微博会自动添加水印,这会影响到图片的美观度。那么,如何去掉微博水印呢?…...

Golang 泛型实现原理
文章目录 1.什么是泛型?2.有 interface{} 为什么还要有泛型?3.泛型有哪些特性?3.1 类型参数泛型函数泛型类型 3.2 类型约束3.3 类型集3.4 约束元素任意类型约束元素近似约束元素联合约束元素约束中的可比类型 3.5 类型推断 4.实现原理4.1 类型擦除虚方法…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...