03 后端入参校验:自定义注解实现

03 后端入参校验:自定义注解实现

  • 一、前言
  • 二、实现
    • 1、新建Spring Boot项目
    • 2、引入依赖
    • 3、新建注解类
    • 4、新建校验器
    • 5、全局异常处理器
    • 6、编写Controller
    • 7、新建实体类
    • 8、启动并测试

在这里插入图片描述

一、前言

Java 后端开发中,为了实现入参校验,常常会使用一些特定的注解来标记参数的约束条件。这些注解通常与一个校验框架(如 Spring Boot 提供的 @Valid 等)配合使用,以便在方法调用前自动进行参数校验。以下是一些常见的用于入参校验的注解:

  • @NotNull: 适用于任何对象,包括基本类型、包装类型、集合类、Map等,判断对象本身是否为null,但是无法校验空字符串。

  • @NotEmpty: 适用于集合类(如 ListSet)、数组、MapCharSequence(如 String )等,判断是否非空(即长度不为0)。

  • @NotBlank: 专门用于 CharSequence(如 String )。不仅可以校验null,同时还可以校验空字符串

如果以上注解实际情况都不能用,需要自定义注解取代它们。

二、实现

1、新建Spring Boot项目

此步骤略过~

2、引入依赖

可以根据 GAV坐标 ,去 Maven官网 查询依赖版本。
Maven Repository: Search/Browse/Explore

<!-- Hibernate Validator: 强大的数据验证框架 -->
<dependency>  
    <groupId>org.hibernate.validator</groupId>  
    <artifactId>hibernate-validator</artifactId>  
    <version>版本号</version>  
</dependency>

<!-- Spring Messaging: 处理消息传递相关的注解。如:@Payload -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>当前Spring框架版本号</version>
</dependency>

3、新建注解类

package com.demo.springboot3.ParamValid;

import jakarta.validation.Constraint;
import org.springframework.messaging.handler.annotation.Payload;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Description: // 参数校验:注解
 * @Author: M.
 * @Date: 2024-04-25 18:35
 */
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ParamValidator.class)
public @interface ParamValid {
    // message支持自定义
    String message() default  "该字段不能为空!";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
  • @Target
    定义: 指定一个注解能够合法应用的位置。
属性简述
ANNOTATION_TYPE可应用于其他注解类型的定义
CONSTRUCTOR可应用于构造函数声明
FIELD可应用于字段(变量)声明,包括实例变量、静态变量和枚举常量
LOCAL_VARIABLE可应用于方法或块内部的局部变量声明
METHOD可应用于方法声明,包括实例方法、静态方法和抽象方法
PACKAGE可应用于源文件或目录结构开头的包声明
PARAMETER可应用于方法、构造函数或lambda表达式中的参数声明
METHOD可应用于类、接口(包括注解类型)或枚举声明
  • @Retention:
    定义: 指定一个自定义注解在何时何地保持其存在性。
属性简述详细描述
SOURCE源码级别保留这种策略下,注解只存在于源代码中,编译器不会把它们写入到编译后的字节码文件(.class 文件)中。因此,这些注解对于编译器在编译时有用(例如,触发代码生成或编译时检查),但在编译后的任何阶段(如类加载、运行时)都不可见。适用于编译时辅助工具和 IDE 插件。
CLASS类文件级别保留这是默认的保留策略,如果未明确指定 @Retention,则采用此策略。在这种情况下,注解会保留在编译后的字节码文件中,但对运行时环境不可见。这对于编译器、类加载器等工具在加载类时进行处理非常有用,如代码分析工具、构建工具或某些依赖于字节码分析的框架。
RUNTIME运行时级别保留当注解指定为运行时保留时,它们不仅存在于源代码中,而且会被编译器写入字节码文件,并且在程序运行时仍可通过反射 API 被访问到。这意味着应用程序或其他运行时库可以通过查询类或对象的注解来做出运行时决策,实现动态行为或元数据驱动的功能。
  • @Constraint:
    定义:Bean Validation框架中@Constraint 是一个元注解,用于标记一个类为自定义验证约束注解。
属性简述
validatedBy指定实现验证逻辑的校验器类
message定义当约束验证失败时显示的错误消息
groups用于分组验证,允许在不同上下文中执行不同的验证集
payload携带额外信息,供验证引擎或校验器使用,通常不直接使用

4、新建校验器

package com.demo.springboot3.ParamValid;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

import java.util.Collection;
import java.util.Map;

/**
 * @Description: // 参数校验:校验器
 * @Author: M.
 * @Date: 2024-04-25 19:17
 */
public class ParamValidator implements ConstraintValidator<ParamValid, Object> {
    @Override
    public void initialize(ParamValid constraintAnnotation) {
        ConstraintValidator.super.initialize(constraintAnnotation);
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
        return value != null // 参数不为null
                && !((value instanceof CharSequence && ((CharSequence) value).length() == 0) // 字符串不为空,同时校验了空字符串
                || (value instanceof Collection && ((Collection<?>) value).isEmpty()) // 集合不为空
                || (value instanceof Map && ((Map<?,?>) value).isEmpty())); // Map不为空
    }
}
  • ParamValid: 上文定义的注解名称
  • Object: 校验器的入参,需要检验的参数。

5、全局异常处理器

package com.demo.springboot3.ParamValid;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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 java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: // 参数校验:全局异常处理器
 * @Author: M.
 * @Date: 2024-04-25 19:35
 */
@ControllerAdvice
public class PVGlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<Map<String, Object>> handleValidationExceptions(MethodArgumentNotValidException ex, HttpServletRequest request){
        Map<String, Object> body = new HashMap<>();
        body.put("timestamp", new Date());
        body.put("status", HttpStatus.BAD_REQUEST.value());
        body.put("path",request.getRequestURI());

        List<Map<String, String>> errorMessages = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(fileError -> {
                    Map<String, String> error = new HashMap<>();
                    error.put("field", fileError.getField());
                    error.put("message", fileError.getDefaultMessage());
                    return error;
                })
                .collect(Collectors.toList());

        body.put("errors", errorMessages);
        return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
    }
}
  • @ControllerAdvice
    定义:Spring 框架中用于全局处理控制器(@Controller 或其派生注解如 @RestController)中异常和数据绑定问题的一个特殊注解。
    使用场景: 全局异常处理、数据绑定验证、模型属性添加。

  • @ExceptionHandler
    定义: @ExceptionHandler 注解的方法会在目标控制器方法抛出指定异常类型时被调用,用于捕获和处理异常,生成合适的响应结果返回给客户端。

  • @ResponseStatus
    定义:@ExceptionHandler 方法上,当该方法处理异常并返回时,应返回的 HTTP 状态码。

📣拓展:
如果各位同学使用了 jdk9 及以上版本,可以使用一下jdk新特性 Map.of() 方法。

List<Map<String, String>> errorMessages = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(fileError -> {
                    Map<String, String> error = new HashMap<>();
                    error.put("field", fileError.getField());
                    error.put("message", fileError.getDefaultMessage());
                    return error;
                })
                .collect(Collectors.toList());

优化后代码如下:

List<Map<String, String>> errorMessages = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(fileError -> Map.of(
                        "field", fileError.getField(),
                        "message", fileError.getDefaultMessage()
                ))
                .collect(Collectors.toList());

6、编写Controller

package com.demo.springboot3.controller;

import com.demo.springboot3.entity.User;
import jakarta.validation.Valid;
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.RestController;

/**
 * @Description: // 用户信息:Controller
 * @Author: M.
 * @Date: 2024-04-25 20:11
 */
@RestController
@Validated
public class UserController {
    @PostMapping("/query")
    public String queryUser(@Valid @RequestBody User user) {
        System.out.println(user);
        return "success";
    }
}
  • @Validated
    定义: Spring 提供的一个批注,用于启用 JSR-303/JSR-349Bean Validation 规范)数据校验功能。它通常应用于控制器方法的参数、控制器类或服务类上,指示 Spring 在方法调用前对指定的 Java 对象进行数据验证。@Validated@Valid 注解配合使用,后者用于标记需要验证的参数或字段。

7、新建实体类

package com.demo.springboot3.entity;

import com.demo.springboot3.ParamValid.ParamValid;
import lombok.Data;

import java.util.List;

/**
 * @Description: // 用户类
 * @Author: M.
 * @Date: 2024-04-25 20:00
 */
@Data
public class User implements java.io.Serializable{
    @ParamValid(message = "用户名(name)不能为空!!!")
    private String name;
    @ParamValid(message = "用户名(age)不能为空!!!")
    private Integer age;
    @ParamValid(message = "用户名(addressList)不能为空!!!")
    private List<String> addressList;
}
  • @ParamValid: 此注解就是上文新建的参数校验注解。需要放在实体类属性上方。

8、启动并测试

在这里插入图片描述
在这里插入图片描述


本文隶属于个人专栏:00 个人小笔记📋📋📋
到这里 03 后端入参校验:自定义注解实现 就结束了!!!🎉🎉🎉
欢迎小伙伴们学习和指正!!!😊😊😊
祝大家学习和工作一切顺利!!!😎😎😎

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

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

相关文章

【SpringCloud】CircuitBreaker断路器之Resilience4J快速入门

【SpringCloud】CircuitBreaker断路器之Resilience4J快速入门 文章目录 【SpringCloud】CircuitBreaker断路器之Resilience4J快速入门1. 概述2. 服务熔断服务降级(CircuitBreaker)2.1 案例说明2.1.1 基于计数的滑动窗口2.1.2 测试2.2.1 基于时间的滑动窗口2.2.2 测试 3. 隔离(B…

多行Textview 计算切分后的长度,并回退长度

实现类似的效果&#xff0c;一个多行的 textview&#xff0c; 如果赋值一个超长的字符&#xff0c;尾部长度回退部分&#xff0c;并添加 ... 最后添加一个详情按钮。 如果不超长则不显示详情 效果如图&#xff1a; 获取截断之后的字符长度 fun getLimitedCharacterCount(textV…

更新!!!Unity移动端游戏性能优化简谱

UWA官方出品&#xff0c;结合多年优化经验撰写了《Unity移动端游戏性能优化简谱》&#xff0c;文章从Unity移动端游戏优化的一些基础讨论出发&#xff0c;例举和分析了近几年基于Unity开发的移动端游戏项目中最为常见的部分性能问题&#xff0c;并展示了如何使用UWA的性能检测工…

Java web应用性能分析之【6种OOM监控和分析】

Java web应用性能分析之【Linux服务器性能监控分析概叙】-CSDN博客 Java web应用性能分析概叙-CSDN博客 Java web应用性能分析之【基准测试】-CSDN博客 Java web应用性能分析之【sysbench基准测试】-CSDN博客 Java web应用性能分析之【CPU飙升分析概述】-CSDN博客 Java we…

GPT学术优化推荐(gpt_academic )

GPT学术优化 (GPT Academic):支持一键润色、一键中英互译、一键代码解释、chat分析报告生成、PDF论文全文翻译功能、互联网信息聚合GPT等等 ChatGPT/GLM提供图形交互界面&#xff0c;特别优化论文阅读/润色/写作体验&#xff0c;模块化设计&#xff0c;支持自定义快捷按钮&…

014_用vim复制粘贴_保持双手正位

[oeasy]python0014_用vim复制粘贴_保持双手正位 继续运行 &#x1f94a; 回忆上次内容 程序员 还是 很可爱的 要关心 身边的程序员 啊 毕竟是新时代的 典型新职业 文明 主流职业 血型 渔猎采集文明 猎人 O 游牧文明 牧民 B 农业文明 农民 A 工业文明 工人 商…

Linux——DNS的配置和使用

一、DNS 域名服务器&#xff0c;实现IP和域名的转换 DNS 协议运行在 UDP 协议之上&#xff0c;使用端口号 53 2.结构 DNS 的命名空间的结构如下&#xff1a; 1. 根域名&#xff08; Root Domain &#xff09;&#xff1a; 根域名位于 DNS 命名空间的顶部&#xff0c;它表示…

【继承和多态】

闭上眼睛&#xff0c;什么都不听.............................................................................................................. 文章目录 前言 一、【继承】 1.1【继承的概念】 1.2【 继承的定义】 1.2.1【定义格式】 1.2.2【继承关系和访问限定符】 1.2…

浏览器的同源策略与解决跨域

同源策略&#xff08;协议、域名、端口&#xff09; 同源策略&#xff08;Same-Origin Policy&#xff09;是一个在浏览器安全模型中被实施的重要安全机制。它是基于域名、协议和端口号的限制&#xff0c;用于防止不同源的网页间的恶意行为和信息泄露。 根据同源策略&#xf…

探秘Java线程:从概念到实践

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一个人虽可以走的更快&#xff0c;但一群人可以走的更远。 我是一名后…

Unity Timeline学习笔记(4) - 自定义轨道OnCreateClip和CreateTrackMixer用法上的区分

前面我们第二篇文章Unity Timeline学习笔记(2) - PlayableTrack是一个初步的PlayableTrack使用方法&#xff0c;有时候可能会个性化定制专属轨道。 OnCreateClip的例子 下面我们做一个例子&#xff1a; 首先是轨道 //FeatureTrack.cs using System.ComponentModel; using U…

以太网口硬件知识分享

一、了解网口通信基本原理 实现网络通信实质上是PHY与MAC及RJ45接口实现信号传输。MAC 就是以太网控制器&#xff0c;MAC属于数据链路层&#xff0c;主要负责把数据封装成帧&#xff0c;对帧进行界定实现帧同步。对MAC地址和源MAC地址及逆行相应的处理并对错误帧进行处理。PHY…

JavaScript-3(内置对象+数组对象+字符串对象)

目录 1.预解析 2.对象 什么是对象 创建对象的三种方法 利用字面量创建方法 利用new Object创建对象 构造函数创建对象 new关键字 遍历对象 3.内置对象 Math对象 Math概述 Math随机数 Date日期对象 格式化日期 Date总的时间毫秒 4.数组对象 创建数组的两种方式…

进销存单机版和excel进销存那个好用

进销存单机版和EXCEL进销存哪个好用&#xff1f;单机版是安装在单台电脑上使用的&#xff0c;它不能像网络版一样可以多台电脑同时共享数据&#xff0c;所以进销存单机版有一个优势就是不需要连接网络也可以使用。 进销存单机版 进销存软件单机版是经过开发人员设计好的一种信…

网页提示语闪太快的定位问题(selenium)

selenium UI自动化时&#xff0c;提示语闪太快&#xff0c;导致无法获取元素的问题 解决办法 步骤一&#xff1a; F12---》控制台输入debugger 步骤二&#xff1a;对于需要定位的部分&#xff0c;在控制台的debugger处回车&#xff0c;可以定住页面 步骤三&#xff1a;正常定…

生成式AI原理技术详解(一)——神经网络与深度学习

本文主要介绍了生成式AI的最新发展&#xff0c;提到了GPT-5和AI软件工程师在行业中的影响&#xff0c;指出AI技术进步对国家竞争和个人职业发展的潜在影响。 未来已来 最近有两则新闻&#xff1a; sam altman自曝GPT-5细节&#xff0c;公开宣称GPT-5提升将非常大&#xff0c;任…

62、回溯-N皇后

思路&#xff1a; N皇后问题要求在一个nn的棋盘上放置n个皇后&#xff0c;使得它们不能相互攻击。皇后可以攻击同一行、同一列&#xff0c;以及两个对角线方向上的其他皇后。解决这个问题意味着找到所有可能的棋盘配置&#xff0c;每个配置都符合上述条件。 1、初始化数据结构…

Docker 入门篇(二)-- Linux 环境离线安装

引言 docker 系列文章&#xff1a; Docker 入门篇&#xff08;一&#xff09;-- 简介与安装教程&#xff08;Windows和Linux&#xff09; 一、安装环境准备 centos &#xff1a;CentOS Linux release 7.6.1810 (Core)docker 版本&#xff1a;docker-26.1.0.tgz 官网下载地址…

Linux驱动开发——(七)Linux阻塞和非阻塞IO

目录 一、阻塞和非阻塞IO简介 二、等待队列 2.1 等待队列头 2.2 等待队列项 2.3 将队列项添加/移除等待队列头 2.4 等待唤醒 2.5 等待事件 三、轮询 四、驱动代码 4.1 阻塞IO 4.2 非阻塞IO 一、阻塞和非阻塞IO简介 IO指的是Input/Output&#xff0c;也就是输入/输…

十个案例学习Flume

在上一篇文章中&#xff0c;已经知道了Flume的架构、概述、与安装&#xff0c;现在我们来用十个案例去学习flume的使用。 在使用之前&#xff0c;提供一个大致思想&#xff0c;使用Flume的过程是确定scource类型&#xff0c;channel类型和sink类型&#xff0c;编写conf文件并开…