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

场景

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、测试参数校验效果

参数不为空

 

参数不合法

 

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

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

相关文章

公司新来的00后真是卷王,工作没两年,跳槽到我们公司起薪18K都快接近我了

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。这不&#xff0c;前段时间我们公司来了个00后&#xff0c;工作都没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。…

瑞云渲染农场怎么用,瑞云渲染多少钱一分钟?

Renderbus瑞云渲染农场作为亚洲前沿的 云渲染平台&#xff0c;一直以“做最好的云渲染工具”为愿景&#xff0c;紧跟CG行业的技术创新与发展&#xff0c;致力于提供专业可靠、安全稳定、可持续创新的云渲染解决方案&#xff0c;助力推动行业快速发展&#xff0c;被誉为中国云渲…

【2023/05/10】Mitchel Resnick

Hello&#xff01;大家好&#xff0c;我是霜淮子&#xff0c;2023倒计时第5天。 Share Her wistful face haunts my dreams like the rain at night. 译文&#xff1a; 她的热切的脸&#xff0c;如夜雨似的&#xff0c;搅扰着我的梦魂。 Once we dreamt that we were stra…

支付系统设计三:渠道网关设计06-业务处理

文章目录 前言一、业务服务工厂二、业务处理服务1. 业务处理服务2. 业务处理抽象服务3. 流量控制4. 报文提交4.1 获取交易的服务端通讯列表4.2 循环请求支付渠道4.2.1 报文组装4.2.2 报文发送4.2.2.1 协议处理器获取4.2.2.2 构建通讯客户端4.2.2.3 发送请求4.2.2.4 响应报文读取…

股票量价关系基础知识2

内盘与外盘 外盘&#xff0c;是指在一个交易日获某段交易时间内&#xff0c;买方主动提价以委卖价成交的股数之和&#xff0c;也称为主动性买盘 内盘&#xff0c;是指在一个交易日获某段交易时间内&#xff0c;卖方主动降价以委买价成交的股数之和&#xff0c;也称主动性卖盘。…

中文润色ai-ai原创文章生成器

在现代社会&#xff0c;每天都有大量的中文文章被发布到互联网上&#xff0c;这些文章的质量和可读性直接影响着读者的阅读体验和文章的传播效果。为了让文章更加美好&#xff0c;越来越多的人开始尝试使用中文润色ai技术。 中文润色ai是一种先进的人工智能技术&#xff0c;它能…

数字图像处理-matlab图像内插

matlab图像内插 最近邻插值双线性插值双三次插值总结 最近邻插值 目标各像素点的灰度值代替源图像中与其最邻近像素的灰度值 参考博客 假设一个2X2像素的图片采用最近邻插值法需要放大到4X4像素的图片&#xff0c;右边该为多少&#xff1f; 最近邻插值法坐标变换计算公式&…

Vue核心 列表渲染 数据监视

1.13.列表渲染 1.13.1.基本列表 v-for指令 用于展示列表数据语法&#xff1a;&#xff0c;这里key可以是index&#xff0c;更好的是遍历对象的唯一标识可遍历&#xff1a;数组、对象、字符串&#xff08;用的少&#xff09;、指定次数&#xff08;用的少&#xff09; <!…

Kubesphere流水线实现蓝绿发布

Kubesphere流水线实现蓝绿发布 1. Gitlab仓库准备 1.1 创建仓库 新建空白项目,名字随便取 greenweb复制克隆地址 http://192.168.31.199/deploy/greenweb.git1.2 初始化并上传代码 克隆并初始化代码仓库 mkdir git cd git git clone http://192.168.31.199/deploy/green…

【嵌入式烧录刷写文件】-2.3-删除/修改Intel Hex文件中指定地址范围内的数据

案例背景&#xff08;共6页精讲&#xff09;&#xff1a; 有如下一段HEX文件&#xff0c;如何“自动”地完成地址范围0x9110-0x9113数据的删除或修改。 :2091000058595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576775F :2091200078797A7B7C7D7E7F808182838485…

一觉醒来Chat gpt就被淘汰了

目录 什么是Auto GPT&#xff1f; 与其他语言生成模型相比&#xff0c;Auto GPT具有以下优点 Auto GPT的能力 Auto GPT的能力非常强大&#xff0c;它可以应用于各种文本生成场景&#xff0c;包括但不限于以下几个方面 Auto GPT的历史 马斯克说&#xff1a;“ChatGPT 好得吓…

记csdn打不开或打开缓慢后的修复--如何查找dns并修改hosts文件

记csdn打开缓慢后的修复–如何查找dns并修改hosts文件 问题&#xff1a; CSDN文章打开的十分缓慢&#xff0c;经常出现无法打开页面的错误提示 &#xff08;以前用的好好的&#xff0c;现在不知道公司局域网改了什么东西&#xff0c;导致我的电脑打开CSDN经常缓慢好久&#x…

Lesson14 高级IO

前言 IO 等待 数据拷贝,比如read/recv,write/send只要在单位事件里,让等的比重减低,IO的效率就越高 五种IO模型 钓鱼小案例 阻塞式 阻塞式: 张三拿着一根鱼竿,一直在岸边钓鱼,期间一直盯着鱼竿,等待鱼上钩 非阻塞式轮询式 非阻塞式轮询式: 李四拿着一根鱼竿,在岸边钓鱼,期…

Linux共享库、动态库详解

目录 一.静态库 二.动态库 三.静态库的制作与使用 四.动态库的制作与使用 在日常编程中我们不想让别人看到我们写的源码&#xff0c;但还需要发给对方使用&#xff0c;在这种情况下我们引入了静态库动态库&#xff0c;让对方用调库的方式也可以实现我们写的代码的功能&…

Android电源管理介绍

一、电源管理基础知识 1.1电源管理的几种状态 Android kernel源码中&#xff0c;定义了三种电源状态&#xff0c;在kernel/power/suspend.c中&#xff1a; 对应的宏定义/include/linux/suspend.h 1.2 电源管理状态的介绍&#xff1a; PM_SUSPEND_ON 设备处于正常工作状态 …

vue2 框架运行原理剖析系列(一)之 new Vue()实例化过程到底做了什么!!!

一、vue 基础用法 1.1 引入vue 1.2 使用vue语法编写ui 1.3 实现数据绑定 示例代码如下 <div id"app">{{ message }} </div> <script> var app new Vue({el: #app,data: {message: Hello Vue!} }) </script>1.4 代码效果&#xff1a;使用浏…

Nessus 10.5 Auto Install for macOS Ventura(自动化安装 Nessus 试用版)

发布 Nessus 试用版自动化安装程序&#xff0c;支持 macOS Ventura、RHEL 9 和 Ubuntu 22.04 请访问原文链接&#xff1a;https://sysin.org/blog/nessus-auto-install-for-macos/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.o…

js实现产品页点击小图在大图区显示

企业网站产品图片可能会比较多&#xff0c;需要在产品页面多放几张展示图片&#xff0c;我们可以使用一张大图几张小图的形式排列&#xff0c;并使用js代码实现点击小图显示大图。效果如下所示 html代码部分&#xff1a; <div class"img_bd"> <img src"…

linux0.12-8-7-signal.c

[334页] (-:这一小节很难理解。但我基本都理解了&#xff0c;哈哈。 1、为什么signal不可靠&#xff0c;而sigaction可靠&#xff1b; 2、 为什么系统调用会被打断&#xff1f; 3、 sys_signal&#xff0c;sys_sigaction&#xff0c;函数作用&#xff1f; 4、 do_signal&#x…

IDEA中java文件出现黄色的J文件同时maven项目导入了依赖但是idea依赖加不进去的问题记录

IDEA导入项目后依赖jar包没有显示 报错提示尝试的解决方法检查对应的sdkmodule等配置信息开始尝试是不是版本问题&#xff0c;因为对上述maven报错进行查询&#xff0c;好像是因为版本太高导致的&#xff0c;开始下一个低版本进行尝试切换版本即可解决 总结后续出现的BUG 此次环…