SpringBoot+@Validate+全局异常拦截实现自定义规则参数校验(校验get请求参数不能为空且在指定枚举类型中)

news2024/9/22 23:28:45

场景

SpringBoot+@Validated实现参数验证(非空、类型、范围、格式等)-若依前后端导入Excel数据并校验为例:

SpringBoot+@Validated实现参数验证(非空、类型、范围、格式等)-若依前后端导入Excel数据并校验为例_@validated 怎么设置boolean类型非空_霸道流氓气质的博客-CSDN博客

https://www.cnblogs.com/badaoliumangqizhi/p/16893531.html

上面实现SpringBoot参数校验时以自带的注解进行校验,如果需要进行自定义校验规则,比如

请求时必须携带某个请求码,而且该请求码字符串必须在指定范围,即从枚举类中指定包含的。

上面是以post请求为例,下面以get请求为例。

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi 

实现

1、首先添加所需依赖

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

2、要实现非空校验已经有 @NotBlank注解,所以要实现自定义规则注解,可以新建

自定义注解类

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

/**
 * 自定义校验注解,校验请求参数是否存在指定枚举类中
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
@Constraint(validatedBy = EnumStringValidator.class)
public @interface EnumString {
    String message();

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

以上注解的含义:

@Retention

1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;

2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;

3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;

@Target用来表示注解作用范围,超过这个作用范围,编译的时候就会报错。

@Target:

注解的作用目标

@Target(ElementType.TYPE)——接口、类、枚举、注解

@Target(ElementType.FIELD)——字段、枚举的常量

@Target(ElementType.METHOD)——方法

@Target(ElementType.PARAMETER)——方法参数

@Target(ElementType.CONSTRUCTOR) ——构造函数

@Target(ElementType.LOCAL_VARIABLE)——局部变量

@Target(ElementType.ANNOTATION_TYPE)——注解

@Target(ElementType.PACKAGE)——包,用于记录java文件的package信息

@Constraint

此注解的验证逻辑交给EnumStringValidator来处理,这里是一个数组,我们可以传入多个处理逻辑。

ConstraintValidator接口,它有两个泛型,第一个是自定义的注解类,第二个就是要验证的数据的类型,

这两个类里面都有两个方法,initialize和isValid,第一个是初始化方法,第二个是验证的逻辑方法,

返回true,则验证通过,否则则不通过。



并且这里注解只有一个属性message需要传递,用来设置校验不通过时显示的信息。

3、实现上面具体的校验类EnumStringValidator

import com.badao.demo.enums.MineMessageEnum;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * 自定义校验逻辑实现-判断api请求码是否合法/是否存在
 */
public class EnumStringValidator implements ConstraintValidator<EnumString,String> {

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        MineMessageEnum resolve = MineMessageEnum.resolve(s);
        if(null == resolve){
            return false;
        }else {
        return true;
        }
    }
}

注意这里只需isValid进行参数校验规则自定义,如果需要传递另外的参数,可以通过

重写initialize方法,获取上面自定义注解的其他变量并在此进行变量赋值。

 

这里自定义的校验规则是判断字符串类型参数是否包含在指定枚举类MineMessageEnum中。

这里规则就需要根据自己实际需要去实现了,校验通过则在isValid中返回true,否则返回false。

下面附枚举类MineMessageEnum的实现

public enum MineMessageEnum
{
    JJT("jjt", "0001","名称1", Constants.SIFANGJI),
    ZLW("zlw", "0002","名称2",Constants.SIFANGJI),
    CCL("ccl", "0003","名称3",Constants.KEERMA);

    private final String apiCode;
    private final String mineCode;
    private final String mineName;
    private final String signalRule;

    private static final Map<String, MineMessageEnum> mappings = new HashMap<>();

    static
    {
        for (MineMessageEnum messageEnum : values())
        {
            mappings.put(messageEnum.apiCode, messageEnum);
        }
    }

    @Nullable
    public static MineMessageEnum resolve(@Nullable String mineApiCode)
    {
        return (mineApiCode != null ? mappings.get(mineApiCode) : null);
    }

    MineMessageEnum(String apiCode, String mineCode, String mineName,String signalRule)
    {
        this.apiCode = apiCode;
        this.mineCode = mineCode;
        this.mineName = mineName;
        this.signalRule = signalRule;
    }

    public String getApiCode() {
        return apiCode;
    }

    public String getMineCode() {
        return mineCode;
    }

    public String getMineName() {
        return mineName;
    }

    public String getSignalRule() {
        return signalRule;
    }
}

4、封装请求参数实体,并在属性上添加参数校验注解

import com.badao.demo.constant.Constants;
import lombok.Data;
import javax.validation.constraints.NotBlank;

/**
 * 自定义请求参数带参数校验
 */
@Data
public class MyRequestParams {

    @EnumString(message = Constants.ILLEGAL_API_CODE)
    @NotBlank(message = Constants.NO_API_CODE)
    private String mineApiCode;

}

注意这里使用lombok,所以省略了get、set方法。

给注解设置message内容时这里使用的是常量类,也可直接使用字符串。

附常量类

public class Constants {
    //请求响应常量
    public static final String NO_API_CODE = "请求码不能为空";
    public static final String ILLEGAL_API_CODE = "请求码不存在";
}

5、在Controller中接口参数添加注解

    @GetMapping("/badao")
    public AjaxResult badao(@Validated MyRequestParams requestParams)

此时进行接口请求时如果参数mineApiCode为空或者不存在上面枚举类的指定范围中,

则会直接提示400,bad request,会触发异常。

但是并没有实现按照我们传递的message显示不同的提示信息。

这里因为没有对异常进行捕获和处理响应。

6、新建全局异常处理类,并添加注解@RestControllerAdvice

添加该注解则会对添加了@RestController注解的类进行异常捕获和处理

@RequestMapping("test")
@RestController
public class TestController{

比如上面的接口的controller。

所以新建全局异常捕获和处理类

import com.badao.demo.common.AjaxResult;
import com.badao.demo.constant.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//注意引入包的路径
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

//    @ExceptionHandler(Exception.class)
//    public AjaxResult handleException(Exception e)
//    {
//        log.error(e.getMessage(), e);
//        return AjaxResult.error(e.getMessage());
//    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public AjaxResult handleBindException(BindException e) {
        log.error(e.getMessage(), e);
        String message = e.getAllErrors().get(0).getDefaultMessage();
        return AjaxResult.error(HttpStatus.BAD_REQUEST, message);
    }
    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
    {
        log.error(e.getMessage(), e);
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return AjaxResult.error(message);
    }
}

注意这里不光可以只对BindException和MethodArgumentNotValidException类型的异常进行捕获和处理

还可对其它类型异常、自定义异常、Exception类进行捕获和处理。

所以说怎么能知道接口校验不通过时触发的是何种类型,放开上面的

//    @ExceptionHandler(Exception.class)
//    public AjaxResult handleException(Exception e)
//    {
//        log.error(e.getMessage(), e);
//        return AjaxResult.error(e.getMessage());
//    }

Exception的处理,注释掉其他处理,然后在此处打断点,触发参数校验不通过时就可以看到具体的异常类型了。

 

当具体类型的捕获和Exception类型同时存在时,则会只触发具体类型的Handler

 

所以这里会具体触发BindException

但是这里为什么是

String message = e.getAllErrors().get(0).getDefaultMessage();

为什么要获取第一个的message,因为当同时触发多个错误时,需要优先取一个显示即可。

 

get的顺序与注解的顺序有关

 

这里@NotBlank在下面,则get时索引为0。

6、测试参数校验效果

参数不为空

 

参数不合法

 

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

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

相关文章

Elasticsearch02

目录 Elasticsearch02DSL查询文档查询所有全文检索查询精确查询地理查询复合查询 搜索结果处理排序分页高亮 DSL总结RestClient查询文档快速入门:match_all查询match查询精确查询布尔查询排序、分页高亮 实战案例HotelControllerIHotelServiceHotelMapperHotelHotelDocPageResu…

Google SEO优化的10大误区

以下是 Google SEO 优化的十大误区&#xff1a; 1、关键词堆砌&#xff1a; 过度使用关键词&#xff0c;使得内容不自然&#xff0c;难以阅读&#xff0c;同时也会被搜索引擎认为是垃圾信息&#xff0c;影响网站排名。 2、内容质量差&#xff1a; 质量差的内容会降低用户的体…

矩池云上配置FusionGan环境

1、租赁环境 2、vscode 连接 矩池云 教程&#xff1a;https://www.matpool.com/supports/doc-vscode-connect-matpool/ 3、进入mnt文件夹 cd ../mnt 4、克隆代码 git clone https://github.com/jiayi-ma/FusionGAN.git 如果克隆不下来&#xff0c;就自己下载&#xff0c;…

ESP32 DW1000 UWB 室内定位系统

相关软件代码下载》》 概述 在这个项目中,我们将制作一个基于 ESP32 DW1000 UWB 的室内定位系统。为此,我们将使用 2 个 UWB 锚点和 1 个 UWB 标签。当标签移动时,UWB 标签的实时位置可以使用Python 程序在PC 上以图形方式显示。 工业环境中的室内跟踪通常需要非常精确的…

C++引用的相关定义以及使用场景与指针之前的区别

一、引用的定义与特性 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 引用的特性&#xff1a; 引用在定义时必须初始化一个变量可以有多个引用引用一旦引用…

电脑技巧:宽带怎么设置教程笔记,看完你就会了

宽带的设置是指将计算机连接到互联网的过程。一般来说&#xff0c;宽带的设置是非常简单的&#xff0c;只需要按照提供商的要求&#xff0c;正确地连接硬件和软件就可以了。下面将详细介绍如何设置宽带。 硬件设置&#xff1a;首先&#xff0c;需要连接计算机和调制解调器&…

sharding-jdbc读写分离实战

一、读写分离介绍 Sharding-JDBC读写分离则是根据SQL语义的分析&#xff0c;将读操作和写操作分别路由至主库与从库。它提供透明化读写分离&#xff0c;让使用方尽量像使用一个数据库一样使用主从数据库集群。 为了实现Sharding-JDBC的读写分离&#xff0c;首先&#xff0c;要…

Leetcode2404. 出现最频繁的偶数元素

Every day a Leetcode 题目来源&#xff1a;2404. 出现最频繁的偶数元素 解法1&#xff1a;哈希 我们构建一个这样的哈希表 unordered_map<int, int> umap&#xff1a; key&#xff1a;偶数数组元素 nums[i]value&#xff1a;nums[i]的出现次数 count 我们遍历一次数…

算法之路--快速排序算法

由于冒泡算法算法之路--冒泡算法&#xff08;算法之路--冒泡算法&#xff09;每轮都要进行从头到落位之前的每个元素的比较&#xff0c;在执行效率上需要提升&#xff0c;快速排序算法就是对冒泡算法的一种效率上的提升。 算法思路 快速排序是基于冒泡的改进&#xff0c;所以基…

力扣回溯算法专题(二)- 切割 子集问题 131.分割回文串、93. 复原IP地址、78. 子集、90. 子集Ⅱ、491.递增子序列 思路 C++实现 总结

文章目录 切割问题子集问题回溯法模板与伪代码131. 分割回文串三要素及思路回文字符串判断代码 93. 复原IP地址三要素及思路验证子串是否合法代码 78. 子集三要素及思路代码 90. 子集Ⅱ三要素及思路三种去重方式代码 491.递增子序列三要素及思路去重方式及去重优化代码 总结1. …

Django框架004:orm对mysql的增删改查

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

TypeScript 配置简述

TypeScript 配置简述 初始化项目的过程为&#xff1a; 新建一个项目 这里使用 yarn init -y 去创建一个 node 项目&#xff0c;随后使用 yarn add typescript 下载 TS 的依赖 新建一个 ts 文件 console.log(test);随意 log 一点东西进行测试 使用 tsc 编译 ts 文件 ❯ yarn …

为什么国外资深的软件测试多是手动测试,但在国内,都推崇自动化测试?

将自动化测试当成很了不起的资本&#xff0c;源于国内对Coding的崇拜 譬如一个Dev跟一个QA放在一起&#xff0c;大家的第一直观印象就是——前者的技术能力比较强。 实际上&#xff0c;这个问题分两面看&#xff1a; 自动化测试能力是不是资本&#xff1f; 当然是。 测试自动…

redis(7)

全局ID生成器: 全局ID生成器&#xff0c;是一种在分布式系统下用来生成全局唯一ID的工具&#xff0c;一般要满足以下特性 唯一性高可用(随时访问随时生成)递增性安全性(不能具有规律性)高性能(生成ID的速度快) 为了增加ID的安全性&#xff0c;我们不会使用redis自增的数值&am…

yolov4

1 V4版本概述 集各种优秀方案于一身&#xff0c;嫁接了众多主流的目标识别方面的情况。 V4 贡献 3. 数据增强策略分析 BOF Bag of freebies(BOF) Mosiac 数据增强 Mixup 比如将狗和猫的两张图片混合&#xff0c;一半猫&#xff0c;一半狗。 label 也变成 Dog 0.5 , Cat 0…

JAVA中PO、VO、BO、POJO、DAO、DTO、TO的理解

目录 1.阿里规范 1.1.Service/DAO 层方法命名规约 1.2.领域模型命名规约 1.3.命名风格 2.简单类&#xff1a;包括 DO/DTO/BO/VO 等 3.与MVC三层架构的关系 4.总结 4.1.为什么要分这些对象 4.2.什么时候需要定义这么多O 4.3.实体对象之间如何转换&#xff1f; 参考资…

Ground-aware Monocular 3D Object Detection for Autonomous Driving论文

1 摘要 摘要&#xff1a;使用单个RGB相机估计环境中物体的3D位置和方向是低成本城市自主驾驶和移动机器人的一项至关重要的挑战性任务。大多数现有算法基于二维-三维对应中的几何约束&#xff0c;这源于一般的6D目标姿态估计。我们首先确定地平面如何在驾驶场景的深度推理中提…

RT-Thread 5.0.1 qemu-virt64-aarch64 解决编译问题

前言 最近在最新的 RT-Thread 上搭建 bsp qemu-virt64-aarch64 的编译环境&#xff0c;发现较新的 gcc 交叉编译器编译失败了。 经过尝试较旧版本的 gcc 交叉编译工具链&#xff0c;终于编译通过了 下载 gcc 交叉编译工具链&#xff0c;这里推荐使用 arm 官方的 gcc 下载地址…

Apache Shiro 1.2.4反序列化漏洞(Shiro-550)--Shiro rememberMe反序列化漏洞(CVE-2016-4437)

前言 Apache Shiro是一款开源安全框架&#xff0c;提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用&#xff0c;同时也能提供健壮的安全性。 Apache Shiro 1.2.4及以前版本中&#xff0c;加密的用户信息序列化后存储在名为remember-me的Cookie中。攻击者可以使用S…

sort、uniq、tr、cut命令的使用

sort、uniq、tr、cut命令的使用 一、sort二、uniq三、tr四、cut 一、sort sort是一个以行为单位对文件内容排序的工具&#xff0c;也可以根据不同的数据类型来排序&#xff0c;例如数据和字符的排序就不一样。比较原则是从首字符向后&#xff0c;依次按ASCII码进行比较&#x…