9个Spring Boot参数验证高阶技巧,第8,9个代码量直接减半!

点击上方"程序员蜗牛g",选择"设为星标"跟蜗牛哥一起,每天进步一点点程序员蜗牛g大厂程序员一枚 跟蜗牛一起 每天进步一点点32篇原创内容**公众号

本篇文章将详细的介绍基于注解参数验证的9大技巧。

实战案例

2.1 基本注解

Spring Validation 提供了一组用于常见验证任务的标准如下示例:

在Controller接口参数上开启验证功能:

**

**

2.2 自定义注解验证

对于特定的业务规则,你可以创建自己的自定义验证约束。

**

**

typescript 复制代码
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {  @Resource  private UserRepository userRepository;  @Override  public boolean isValid(String username, ConstraintValidatorContext context) {    if (username == null) {      return true; // Let @NotNull handle null values    }    return !userRepository.existsByUsername(username);  }}

2.3 分组验证

分组验证允许你针对不同场景应用不同的规则,例如创建操作与更新操作。如下示例(定义分组):

使用分组

less 复制代码
public class ProductDTO {  @Null(groups = ValidationGroups.Create.class, message = "创建商品时ID必须为空")  @NotNull(groups = ValidationGroups.Update.class, message = "更新商品时商品ID不能为空")  private Long id;  @NotBlank(groups = {ValidationGroups.Create.class, ValidationGroups.Update.class})  private String name;}

分组验证

注意:使用 @Validated 注解,因为它是支持验证组的注解。@Valid 不支持。

2.4 嵌套验证

对于复杂对象,你可以验证嵌套对象和集合。

注意:使用 @Valid 注解需要级联验证的字段,以确保验证器深入检查嵌套对象。

2.5 方法级验证

你也可以直接对服务层方法进行验证,而不仅仅是对控制器参数进行验证。

如果你是在Controller方法上那么你 不需要 在类上使用@Validated注解。

2.6 错误消息国际化

当发生错误时我们可以通过2中方式来提示具体的错误消息。

  • 直接指定错误消息

**

**

直接通过 message 指定要展示的错误消息。

  • 使用占位符

message属性可以使用 {xxx} 语法,其中 xxx 为你在资源文件中定义的key。

接下来,新建 classpath:messages_zh_CN.properties 和 classpath:messages_en_US.properties 资源文件。

上面我们是使用的spring boot默认的basename,你可以自定义,通过 spring.messages.basename 属性配置。

2.7 编程验证

除了注解之外,你还可以手动触发验证。

适用于验证是有条件的复杂业务逻辑,或用于验证未通过控制器传递的对象。

2.8 组合验证

将多个基本约束组合成一个单一的、可复用的且更具表现力的注解。

less 复制代码
@NotNull@Size(min = 8, max = 30)@Pattern(regexp = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).*$",         message = "密码必须包含至少一个数字、小写字母、大写字母和特殊字符")@Target({ElementType.FIELD, ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = {})public @interface StrongPassword {
  String message() default "密码不符合安全要求";  Class<?>[] groups() default {};  Class<? extends Payload>[] payload() default {};}

使用组合注解

优点:提高代码可读性,并确保验证规则得到一致应用。

2.9 跨字段验证

根据字段与其他字段的关系来验证字段,例如确保 "确认密码" 字段与 "密码" 字段匹配。创建一个类级约束:

密码验证器

vbnet 复制代码
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> {  private String field;  private String fieldMatch;  @Override  public void initialize(PasswordMatches constraintAnnotation) {    this.field = constraintAnnotation.field();    this.fieldMatch = constraintAnnotation.fieldMatch();  }  @Override  public boolean isValid(Object value, ConstraintValidatorContext context) {    try {      // 通过反射获取字段值      Field field1 = value.getClass().getDeclaredField(field);      field1.setAccessible(true);      Object fieldValue1 = field1.get(value);      Field field2 = value.getClass().getDeclaredField(fieldMatch);      field2.setAccessible(true);      Object fieldValue2 = field2.get(value);      // 比较两个字段值(处理null情况)      if (fieldValue1 == null) {        return fieldValue2 == null;      }      return fieldValue1.equals(fieldValue2);    } catch (NoSuchFieldException | IllegalAccessException e) {      throw new RuntimeException("Failed to validate password fields", e);    }  }}

使用注解

Controller接口

less 复制代码
@PostMapping("/register")public ResponseEntity<?> register(@Valid @RequestBody UserRegistrationDTO dto, BindingResult result) {  if (result.hasErrors()) {    List<String> errors = result.getAllErrors()        .stream()        .map(err -> err.getDefaultMessage())        .toList() ;    return ResponseEntity.badRequest().body(errors);  }  return ResponseEntity.ok("Registration successful");}

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记 就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

相关推荐
奶糖 肥晨1 分钟前
一次Spring Boot编译报错排查:三元运算符与包装类型的“隐形陷阱”
java·spring boot·后端
To_OC9 分钟前
拼路径读文件总踩坑?我把 Node 的 path 和 fs 彻彻底底捋了一遍
javascript·后端·node.js
卷无止境9 分钟前
Python生成器与惰性求值:从yield说起的一场"暂停魔法"
后端·python
卷无止境18 分钟前
从一个装饰器说起:拆解 Python 的 @property
后端·python
一只小小Java1 小时前
Naocs本地部署&安装3.2.3+Spring boot 3.2.0
java·spring boot·后端·nacos
码兄科技10 小时前
实战:基于Spring Boot + UniApp的地理信息小程序开发
spring boot·后端·uni-app
腾讯云云开发11 小时前
腾讯云 CloudBase 登上 WAIC:我们为 Agent 重新设计了云的生产线
后端
星栈11 小时前
从装一堆工具到看懂 Node 工程化思维:我的项目复盘记录
后端·node.js
65岁退休Coder12 小时前
LangChain v1.3.4 笔记 - 05 Agent 上下文记忆
后端
颜酱12 小时前
04 | 召回前置准备:搭好召回所需的四个数据库
前端·人工智能·后端