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

server/2024/12/22 14:24:33/

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> {@Overridepublic void initialize(ParamValid constraintAnnotation) {ConstraintValidator.super.initialize(constraintAnnotation);}@Overridepublic 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 后端入参校验:自定义注解实现 就结束了!!!🎉🎉🎉
欢迎小伙伴们学习和指正!!!😊😊😊
祝大家学习和工作一切顺利!!!😎😎😎


http://www.ppmy.cn/server/18328.html

相关文章

Swift 中的条件语句:if 和 else

在 Swift 编程语言中&#xff0c;条件语句 if 和 else 是控制程序流程的重要工具。它们允许我们根据不同的条件执行不同的代码块&#xff0c;从而实现更灵活的程序逻辑。 if 语句 if 语句用于执行一个代码块&#xff0c;当指定的条件为真时。其基本语法如下&#xff1a; if …

OpenSceneGraph

文章目录 关于 OpenSceneGraphScreenshots - OpenMW 关于 OpenSceneGraph 官网&#xff1a;https://openscenegraph.github.io/openscenegraph.io/github : https://github.com/openscenegraph/OpenSceneGraphClasses : https://podsvirov.github.io/osg/reference/opensceneg…

Unity中的UI系统之UGUI

目录 概述UGUI基础——六大基础组件六大基础组件概述Canvas画布组件CanvasScaler画布缩放控制器组件必备知识恒定像素模式缩放模式恒定物理模式3D模式 Graphic Raycaster图形射线投射器EventSystem和Standalone Input ModuleRectTransform UGUI基础——三大基础控件Image图像控…

抽象的算法0.1.2版本

前言&#xff1a; 公式&#xff1a;&#xff08;基础 基础 基础 ...更多的基础&#xff09; 维度&#xff08;影响因素&#xff09; 问题 总感觉这个公式还缺了什么&#xff0c;将会在后续更新&#xff01; 斐波那契数列 斐波那契数列&#xff08;Fibonacci sequence&am…

RedisTemplate-opsForStream实现消息队列,主要演示 xgroup,xreadgroup,xpending,xack,xinfo的用法

stream 更多详细命令使用&#xff0c;可查看博文redis基于Stream类型实现消息队列&#xff0c;命令操作&#xff0c;术语概念&#xff0c;个人总结等-CSDN博客1 springboot整合redis 就不多说了 2 有用到hutool工具类&#xff0c;添加下 pom 依赖 <dependency><grou…

前端兼容 适配

一、浏览器 1、内核 浏览器内核优缺点IEtrident不安全Chromewebkit -> blink速度快&#xff0c;有兼容safriwebkit有兼容firefoxgecko功能强大 耗性能Operapresto -> blinkpresto 速度快&#xff0c;有兼容 2、浏览器兼容 1、html兼容 超链接访问过后hover样式不再出…

Cocos Creator 声音管理模块SoundMgr详解

前言 Cocos Creator 是一款用于开发2D和3D游戏的跨平台游戏引擎&#xff0c;它提供了丰富的功能和工具&#xff0c;使开发者能够快速开发出高质量的游戏。在游戏开发中&#xff0c;声音是一个非常重要的元素&#xff0c;可以增强游戏的氛围和互动性。为了更好地管理游戏中的声…

3.常用的“二次”编解码方式

为什么需要“二次”编解码? 假设我们把解决半包粘包问题的常用三种解码器叫一次解码器 那么我们在项目中,除了可选的的压缩解压缩之外,还需要一层解码,因为一次解码的结果是字节,需要和项目中所使用的对象做转化,方便使用,这层解码器可以称为“二次解码器”,相应的,…