优雅的入参校验,Valid常用校验

更好的阅读体验:优雅的入参校验,Valid常用校验


对于前端传递的参数,正常情况下后端是要进行一些必要的校验,最简单的做法是用 if

效果是可以,但不优雅。使用 @Validator 代替 if,就会优雅很多


ps:Validator 也可用于Dubbo参数校验


一、效果展示


如Post请求需要一个name参数,当name参数不传递的时候

在这里插入图片描述


二、引入 Validator


2-1、pom 文件引入

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <scope>compile</scope>
</dependency>

本质上引入的是

<dependency>
  <groupId>org.hibernate.validator</groupId>
  <artifactId>hibernate-validator</artifactId>
  <scope>compile</scope>
</dependency>

2-2、全局异常处理器


校验不通过会抛出异常,所以需要一个异常处理器来做提示语处理

对全局异常拦截器感兴趣的看这里 @ControllerAdvice异常拦截原理解析

import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

@ControllerAdvice
@RestController
public class AllControllerAdvice {
    public final static Logger logger = LoggerFactory.getLogger(AllControllerAdvice.class);
    
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(IllegalArgumentException.class)
    public String illegalArgumentHandler(IllegalArgumentException e) {
        logger.error("IllegalArgumentException-error->", e);
        return e.getMessage();
    }
    
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        logger.error("MethodArgumentNotValidException->", e);

        return this.getErrorMessages(e.getBindingResult());
    }
    
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BindException.class)
    public String handleBindException(BindException e) {
        logger.error("BindException error->", e);
        return String.format("xxxxxx" + ":%s", this.getBindingErrorField(e.getBindingResult()));
    }
    
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(InvalidFormatException.class)
    public String handleInvalidFormatException(InvalidFormatException e) {
        logger.error("InvalidFormatException error->", e);
        return e.getMessage();
    }
    
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(ConstraintViolationException.class)
    public String handleConstraintViolationException(ConstraintViolationException e) {
        logger.error("ConstraintViolationException-error->", e);
        return e.getConstraintViolations().stream().map(this::getMessage).collect(Collectors.joining(";"));
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public String exceptionHandler(Exception e) {
        logger.error("Exception-error->", e);
        return "UNKNOWN_ERROR_MESSAGE";
    }

    private String getBindingErrorField(BindingResult bindingResult) {
        return bindingResult
                .getAllErrors()
                .stream()
                .map(this::getFieldName)
                .collect(Collectors.joining(";"));
    }

    private String getErrorMessages(BindingResult bindingResult) {
        return bindingResult
                .getAllErrors()
                .stream()
                .map(this::getMessage)
                .collect(Collectors.joining(";"));
    }

    private String getMessage(ObjectError error) {
        if (error instanceof FieldError) {
            FieldError fieldError = (FieldError) error;
            return fieldError.getField() + ":" + fieldError.getDefaultMessage();
        }
        return error.getObjectName() + ":" + error.getDefaultMessage();
    }

    private String getFieldName(ObjectError error) {
        if (error instanceof FieldError) {
            FieldError fieldError = (FieldError) error;
            return fieldError.getField();
        }
        return error.getObjectName();
    }


    private String getMessage(ConstraintViolation<?> violation) {
        return violation.getPropertyPath() + ":" + violation.getMessage();
    }
}

如果在Dubbo中使用,那就需要定义一个Filter,这个Filter就用来充当全局异常处理器


2-3、Controller


Controller

import com.xdx97.cli.pojo.entity.ValidQuery;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/cli")
public class CliController {

    @PostMapping(value = "/valid")
    public String valid(@RequestBody @Validated ValidQuery validQuery) {

        System.out.println(validQuery);
        return "success";
    }
}

ValidQuery

import lombok.Data;
import lombok.ToString;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.*;

@Data
@ToString
public class ValidQuery {

  @NotBlank(message = "不能为空")
  @Length(min = 1, max = 5, message = "长度必须在[1,5]之间")
  private String name;
}

注:@Data@ToString 是 lombok 提供了,用来省略get、set、toString方法,和校验无关


三、常用校验


已经知道如何使用参数校验,下面再来看看常用的校验有哪些,只需要把对应的校验复制到 ValidQuery 就可以验证了


3-1、基础校验


字符串

@NotBlank(message = "不能为空")
@Length(min = 1, max = 5, message = "长度必须在[1,5]之间")
@Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "用户名只能包含字母、数字和下划线")
private String name;

数字

Integer、Long 都适用

@NotNull(message = "不能为空")
@Max(value = 100, message = "最大为100")
@Min(value = 1, message = "最小为1")
private Integer age;

小数

BigDecimal、Double、Float 都适用

@NotNull(message = "不能为空")
@DecimalMax(value = "100.00", message = "最大为100.00")
@DecimalMin(value = "1.00", message = "最小为1.00")
@Digits(integer = 3, fraction = 2, message = "金额整数位最多3位,小数位最多2位")
private BigDecimal amount;

集合

List、Set、Map 都适用

@NotEmpty(message = "列表不能为空")
@Size(min = 1, max = 5, message = "列表长度必须在1到5之间")
private List<Integer> statuses;

时间/日期

@NotNull(message = "日期不能为空")
@Past(message = "日期必须是过去的时间")
@Future(message = "日期必须是未来的时间")
private LocalDate date;

3-2、嵌套校验


对象里面嵌套集合对象

@Data
@ToString
public class ValidQuery {

    @NotEmpty(message = "列表不能为空")
    @Valid
    private List<ValidQueryChild> items;

    @Data
    @ToString
    static class ValidQueryChild {

        @NotBlank(message = "不能为空")
        @Length(min = 1, max = 5, message = "长度必须在[1,5]之间")
        private String childName;
    }
}

参数是集合对象且对象里面嵌套集合对象

ValidQuery 还是和上面一样,但Controller要改变

  1. 把 @Validated 移到Controller上
  2. 入参添加 @Valid和 @NotEmpty
@RestController
@RequestMapping("/cli")
@Validated
public class CliController {

    @PostMapping(value = "/valid")
    public String valid(@RequestBody @NotEmpty(message = "列表不能为空") @Valid List<ValidQuery> validQueries) {

        System.out.println(validQueries);
        return "success";
    }
}

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

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

相关文章

【从零开发Mybatis】引入MapperConfig.xml和Mapper映射配置

引言 学习MyBatis源码之前&#xff0c;了解它是如何通过JDBC查询数据库数据的基础知识是非常有用的。 上一篇我们编写了一个最简单的示例&#xff0c;通过JDBC查询数据库数据&#xff0c;从本文开始&#xff0c;我们将正式开始Mybatis框架的开发。 通过JDBC查询数据库数据存…

中国移动机器人将投入养老场景;华为与APUS共筑AI医疗多场景应用

AgeTech News 一周行业大事件 华为与APUS合作&#xff0c;共筑AI医疗多场景应用 中国移动展出人形机器人&#xff0c;预计投入养老等场景 作为科技与奥富能签约&#xff0c;共拓智能适老化改造领域 天与养老与香港科技园&#xff0c;共探智慧养老新模式 中山大学合作中国…

改变函数调用上下文:apply与call方法详解及实例

目录 改变函数调用上下文&#xff1a;apply与call方法详解及实例 一、什么是 apply 方法&#xff1f; 1、apply 语法 2、apply 示例 二、什么是 call 方法&#xff1f; 1、call 语法 2、call 示例 三、apply 和 call 的共同与差异 1、apply 和 call 的共同点 2、apply…

opencv学习:基于计算机视觉的表情识别系统

简介 基于计算机视觉的表情识别系统&#xff0c;该系统能够从视频流中实时检测人脸&#xff0c;并识别出两种基本表情&#xff1a;大笑和微笑。实验通过分析人脸关键点来计算表情特征指标&#xff0c;从而判断表情类型。 原理 基于以下原理进行&#xff1a; 人脸检测&#x…

Transformer(Vit+注意力机制)

文献基本信息&#xff1a; Encoder-Decoder&#xff1a; Transformer的结构&#xff1a; 输入编码器解码器输出 Transformer的工作流程&#xff1a; 获取输入句子的每一个单词的表示向量X&#xff0c;X由单词的embedding&#xff08;embedding是一种将高维特征映射到低维的技…

机器学习中的图像处理与计算机视觉

引言 在现代计算机科学中&#xff0c;图像处理和计算机视觉已成为最活跃的研究领域之一&#xff0c;这得益于机器学习和深度学习的发展。本文将深入探讨图像处理与计算机视觉的基础概念、常见应用、关键技术、常用工具&#xff0c;以及在这些领域中的代码示例。通过本篇文章&a…

约80%的巴西消费者热捧跨境电商平台Shopee

巴西作为南美洲最大的经济体&#xff0c;拥有庞大的消费群体和日益增长的消费需求。随着互联网的普及和电子商务的快速发展&#xff0c;巴西消费者对海外商品的兴趣日益浓厚。他们渴望获得更多元化的商品选择&#xff0c;尤其是那些在国内难以找到的特色商品或国际知名品牌。这…

Python3 接口自动化测试,HTTPS下载文件(GET方法和POST方法)

Python3 接口自动化测试,HTTPS下载文件(GET方法和POST方法) requests-pkcs12 PyPI python中如何使用requests模块下载文件并获取进度提示 1、GET方法 1.1、调用 # 下载客户端(GET)def download_client_get(self, header_all):try:url = self.host + "/xxx/v1/xxx-mod…

DBdoctor推出无Agent轻量级纳管解决方案

目录 背景 DBdoctor推出无Agent轻量级纳管解决方案 方案优势&#xff1a; 实例纳管方式&#xff1a; 无Agent纳管可体验哪些功能&#xff1f; 1.全量SQL审核功能 2.实例巡检功能 3.性能洞察功能 4.基础监控功能 总结 背景 在数字化时代&#xff0c;数据库作为信息系…

前端拦截302重定向

背景: 根据业务场景需要拦截302做后续的逻辑处理 尝试一: : axios拦截 、、、、、async created() {// 获取302请求返回的location后手动修改video的src路径let targetSrc;try {await axios.get(this.video).then((res) > {const { headers, status } res;const { locat…

unity 屏幕波动反馈打击效果(附资源下载)

unity 屏幕波动反馈打击效果 一枪打出去整个屏幕都回波动的效果反馈。 知识点&#xff1a; 1、动画事件 2、屏幕后处理 效果如图&#xff1a;&#xff08;波动速度浮动都可调整&#xff09; 附件下载

[C#][winform]基于yolov8的DMS驾驶员抽烟打电话喝水吃东西检测系统C#源码+onnx模型+评估指标曲线+精美GUI界面

【重要说明】 该系统以opencvsharp作图像处理,onnxruntime做推理引擎&#xff0c;使用CPU进行推理&#xff0c;适合有显卡或者没有显卡windows x64系统均可&#xff0c;不支持macOS和Linux系统&#xff0c;不支持x86的windows操作系统。由于采用CPU推理&#xff0c;要比GPU慢。…

EWM 库存盘点

目录 1 业务流程图 2 后台配置 & 主数据 3 业务操作 1 流程图 2 后台配置 & 主数据 仓库活动区域设置 SCM Extended Warehouse Management -> Extended Warehouse Management -> Internal Warehouse Processes -> Physical Inventory -> Physical-Inv…

k8s-pod详解

Pod生命周期 我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期&#xff0c;它主要包含下面的过程 pod创建过程 运行初始化容器&#xff08;init container&#xff09;过程 运行主容器&#xff08;main container&#xff09; 容器启动后钩子&#xff08;post st…

C语言【调试】(个人笔记版)

调试 前言一、Bug二、调试工具1.DeBug2.Release 三、调试快捷键1、断点 四、调试时查看程序的当前信息1、查看临时变量2、查看内存3、查看调用堆栈、汇编、寄存器 总结 前言 这篇文章大都是我的个人笔记&#xff1a; 调试在日常程序设计中是很重要的。调试说白了就是为了解决代…

zookeeper客户端

启动单机版的zookeeper 配置Maven环境 (1) IDEA自带maven (2) 更新Maven库镜像地址&#xff1a; ① 拷贝D:\Program Files\JetBrains\IntelliJ IDEA 2018.3.5\plugins\maven\lib\maven3\conf\settings.xml [IntelliJ的安装目录]到 C:/用户/username/.m2 (如果.m2文件不存在&…

大话哈希冲突

Map是很常用的数据结构, 而哈希表是 HashMap 等集合的底层实现之一&#xff0c;它通过将键的哈希值映射到数组中的位置来存储键值对。哈希冲突 (Hash Collision) 是指在使用哈希函数将数据映射到有限大小的哈希表时&#xff0c;不同的数据项被映射到了同一个哈希表位置上。 一…

【C++】拆分详解 - stack和queue

文章目录 一、stack的介绍和使用1. 简介2. 使用3. 模拟实现 二、queue的介绍和使用1. 简介2. 使用3. 模拟实现 三、容器适配器1. 简介2. STL标准库中的使用 四、deque&#xff08;了解&#xff09;1. 简介2. 底层原理2.1 底层空间2.2 模拟访问元素2.3 迭代器2.4 STL源码片段摘要…

高清无水印推文视频素材下载网站推荐

在制作抖音短视频时&#xff0c;选择合适的视频素材至关重要。想知道哪里可以下载热门的推文视频素材吗&#xff1f;别担心&#xff0c;我为你整理了六个高品质的视频素材网站&#xff0c;让我们一起来看看吧&#xff01; 蛙学网 首先介绍的是蛙学网&#xff0c;作为国内知名的…

期权懂|股票下跌时可以使用期权止损吗?

本期让我懂 你就懂的期权懂带大家来了解&#xff0c;股票下跌时可以使用期权止损吗&#xff1f;有兴趣的朋友可以看一下。期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 股票下跌时可以使用期权止损吗&#xff1f; 在股市中&am…