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 的区别

  1. 适用范围:
    • @Valid 是 Java 校验(JSR-303)的一部分,通常用于标注在方法参数或方法返回值上,以触发参数校验或返回结果的校验。
    • @Validated 是 Spring 提供的,用于在方法级别进行校验。它支持分组校验,并且可以标注在类或方法上。
  2. 分组校验:
    • @Valid 支持分组校验,可以通过定义校验接口的不同分组来控制不同情况下的校验规则。
    • @Validated 也支持分组校验,但是它的分组校验是通过在校验注解上指定分组来实现的。
  3. 校验方式:
    • @Valid 主要用于标注在方法参数或返回值上,触发 Bean Validation 校验。
    • @Validated 主要用于方法级别的校验,并且支持 Spring 提供的校验方式,例如 Spring 的 @NotEmpty@Range 等。
  4. 引入依赖:
    • 使用 @Valid 需要引入 Java Bean Validation 的相关依赖,比如 Hibernate Validator。
    • 使用 @Validated 需要引入 Spring 的相关依赖,它是 Spring 提供的一个校验框架。
  5. 支持的校验注解:
    • @Valid 支持 JSR-303(Bean Validation)提供的注解,比如 @NotNull@Size 等。
    • @Validated 支持 Spring 提供的校验注解,例如 @NotEmpty@Range@Email 等。
  6. 参数校验异常类
    • @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 {

    @Serial
    private 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 {

    @Serial
    private 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;
    }

    @Override
    public 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 {

    @Serial
    private 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());
    }
}

测试

springboot3-全局异常处理

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Bert-vits2最终版Bert-vits2-2.3云端训练和推理(Colab免费GPU算力平台)

对于深度学习初学者来说&#xff0c;JupyterNoteBook的脚本运行形式显然更加友好&#xff0c;依托Python语言的跨平台特性&#xff0c;JupyterNoteBook既可以在本地线下环境运行&#xff0c;也可以在线上服务器上运行。GoogleColab作为免费GPU算力平台的执牛耳者&#xff0c;更…

【JavaScript】Set、Map、WeakSet、WeakMap

✨ 专栏介绍 在现代Web开发中&#xff0c;JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性&#xff0c;还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言&#xff0c;JavaScript具有广泛的应用场景&#x…

云计算:OpenStack 配置二层物理网卡为三层桥的接口

目录 一、理论 1.OpenStack 二、实验 1. Linux系统修改网卡 2.OpenStack 配置二层物理网卡为三层桥的接口 一、理论 1.OpenStack &#xff08;1&#xff09;概念 OpenStack是一个开源的云计算管理平台项目&#xff0c;是一系列软件开源项目的组合。由NASA(美国国家航空…

【Java 中锁的种类】

文章目录 一、公平锁和非公平锁二、可重入锁&#xff08;递归锁&#xff09;三、自旋锁四、独占锁(写锁)/共享锁(读锁)/互斥锁 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、公平锁和非公平锁 遵守先来后到的是公平锁&#xff0c;不遵守的是非公…

Jmeter 性能 —— 监控服务器!

Jmeter 监控Linux需要三个文件 JMeterPlugins-Extras.jar (包&#xff1a;JMeterPlugins-Extras-1.4.0.zip)JMeterPlugins-Standard.jar (包&#xff1a;JMeterPlugins-Standard-1.4.0.zip)ServerAgent-2.2.3.zip 1、Jemter 安装插件 在插件管理中心的搜索Servers Performa…

基于ChatGpt,Java,SpringBoot,Vue,Milvus向量数据库的定制化聊天Web demo

customized chat GitHub - bigcyy/customized-chatgpt: 基于ChatGpt&#xff0c;Java&#xff0c;SpringBoot&#xff0c;Vue&#xff0c;Milvus向量数据库的定制化聊天Web demo 简介 基于ChatGpt&#xff0c;Java&#xff0c;SpringBoot&#xff0c;Vue&#xff0c;Milvus向…

【MyBatis-Plus】进阶之乐观锁、悲观锁逻辑删除分页和查询构造器的使用

目录 一、乐观锁、悲观锁 1、什么是乐观锁和悲观锁 ①乐观锁&#xff08;Optimistic Locking&#xff09;: ②悲观锁&#xff08;Pessimistic Locking&#xff09;: ③实现方式 2、乐观锁和悲观锁的区别 ①乐观锁&#xff08;Optimistic Locking&#xff09; ②悲观锁&…

【头歌实训】PySpark Streaming 数据源

文章目录 第1关&#xff1a;MySQL 数据源任务描述相关知识PySpark JDBC 概述PySpark JDBCPySpark Streaming JDBC 编程要求测试说明答案代码 第2关&#xff1a;Kafka 数据源任务描述相关知识Kafka 概述Kafka 使用基础PySpark Streaming Kafka 编程要求测试说明答案代码 第1关&a…

亿赛通电子文档安全管理系统 linkfilterservice 未授权漏洞

产品简介 亿赛通电子文档安全管理系统&#xff0c;&#xff08;简称&#xff1a;CDG&#xff09;是一款电子文档安全加密软件&#xff0c;该系统利用驱动层透明加密技术&#xff0c;通过对电子文档的加密保护&#xff0c;防止内部员工泄密和外部人员非法窃取企业核心重要数据资…

在Spring Cloud中使用Ribbon完成一个简单的负载均衡demo

Spring Cloud系列断更了有一段时间了&#xff0c;这段时间最近都在忙着项目上的事&#xff0c;天天修复bug以及调整需求&#xff0c;反正各种操劳&#xff0c;了解业务需求&#xff0c;然后开发相关功能&#xff0c;很久都没碰Spring Cloud系列的相关文章了&#xff0c;最近回头…

ASP.Net实现新闻添加查询(三层架构,含照片)

目录 演示功能&#xff1a; 点击启动生成页面 点击搜索模糊查询 点击添加跳转新界面 ​编辑 点击Button添加 步骤&#xff1a; 1、建文件 ​编辑 2、添加引用关系 3、根据数据库中的列写Models下的XueshengModels类 4、DAL下的DBHelper&#xff08;对数据库进行操作…

Win10电脑蓝牙默认音量100的设置教程

在Win10电脑操作过程中&#xff0c;用户想设置连接蓝牙后音量默认是100&#xff0c;但不知道具体的设置操作步骤。这时候用户需要打开Win10系统上的注册表&#xff0c;点击修改注册表来完成这一设置&#xff0c;下面就是Win10电脑蓝牙默认音量100的设置教程介绍&#xff0c;帮助…

【网络安全 | 指纹识别工具】WhatWeb使用详析

前言 WhatWeb 是一款用于识别 Web 应用程序和 Web 服务器的开源工具。它可以识别网站使用的编程语言、Web 框架、Web 服务器软件、Web 应用程序等信息&#xff0c;从而帮助安全测试人员快速了解目标网站的技术特征&#xff0c;发现可能存在的漏洞。 本文将对 WhatWeb 的使用方法…

使用Rust发送邮件

SMTP协议与MIME协议 SMTP&#xff08;简单邮件传输协议,Simple Mail Transfer Protocol&#xff09;是一种用于发送和接收电子邮件的互联网标准通信协议。它定义了电子邮件服务器如何相互发送、接收和中继邮件。SMTP 通常用于发送邮件&#xff0c;而邮件的接收通常由 POP&#…

在wps里导入Mathtype、改变字体

1 在wps里导入Mathtype 开发工具--加载项 2. 在“模板和加载项”窗口中再点击“添加” 3.找到mathtype安装路径下面的“OfficeSupprot”&#xff0c;这时会看到有“32”和“64”两个文件夹&#xff0c;分别对应WPS软件的系统&#xff08;任务管理器可以直接查看wps版本&#x…

three.js实现3D汽车展厅效果展示

项目搭建 本案例还是借助框架书写three项目&#xff0c;借用vite构建工具搭建vue项目&#xff0c;搭建完成之后&#xff0c;用编辑器打开该项目&#xff0c;在终端执行 npm i 安装一下依赖&#xff0c;安装完成之后终端在安装 npm i three 即可。 因为我搭建的是vue3项目&…

理解 Go Mod Init

初始化Go模块和管理依赖的全面指南 go mod init 是Go编程语言&#xff08;通常称为Golang&#xff09;中用于初始化新Go模块的命令。在Go中&#xff0c;一个模块是一组相关的Go包&#xff0c;它们作为一个单元一起进行版本控制。通常&#xff0c;在项目目录的根目录下使用 go m…

NLP论文阅读记录 - 01 | 2021 神经抽象摘要方法及摘要事实一致性综述

文章目录 前言0、论文摘要一、Introduction二.背景2.1自动总结任务2.2 数据集DUC-2004Gigaword [Graff et al., 2003, Napoles et al., 2012]CNN/DailyMail [Nallapati 等人&#xff0c;2016]XSum [Narayan 等人&#xff0c;2018] 2.3 摘要系统的评估2.3.1 Rouge [Lin, 2004] 三…

用编程解决习题【计算机图像处理】

用编程解决习题【计算机图像处理】 前言版权第三章 03采样量化与像素间关系作业编程 第六章 06图像的直方图变换作业编程 第七章 07图像的噪声抑制作业编程 第十章 10二值图像的分析作业编程 最后 前言 2023-12-27 21:11:27 以下内容源自《【计算机图像处理】》 仅供学习交流…

CSS3用户界面弹性盒子

CSS3用户界面 resize 该CSS3属性用于定义元素是否应该调整大小&#xff0c;如果需要调整大小&#xff0c;那么以哪个轴进行调整。 语法&#xff1a;resize:both | horizontal | none | vertical 注意&#xff1a;该属性仅应用在overflow值而不是visible的元素上。通常而言&am…