1. 概述

数据验证是软件开发中的关键环节,确保流入应用的数据正确且一致。验证可基于不同因素应用于任何数据类型。

在Spring中,通过内置工具和注解简化了验证流程,让我们能轻松实现健壮的验证逻辑。

本教程将学习如何在Spring中验证列表值,并探讨只允许特定值的场景。通过结合标准验证和自定义验证,我们能维护数据完整性并保障应用功能无缝运行。

2. 在Spring中配置验证

启用验证需确保在pom.xml中添加以下依赖:

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

该依赖将Hibernate Validator集成到Spring应用中。

3. 验证列表值

假设需要验证员工角色列表,每个角色必须以ROLE_开头。

首先在Employee DTO类中添加角色字段:

@NotEmpty(message = "角色列表不能为空")
@Valid
private List<@Pattern(regexp = "ROLE_[A-Z]+", 
  message = "每个角色必须以'ROLE_'开头且仅包含大写字母") String> roles;

@NotEmpty确保列表非空,@Pattern验证每个角色符合指定格式。

接下来在控制器类添加触发验证的方法:

@PostMapping("/validateListAtService")
public ResponseEntity<String> validateRoles(@RequestBody @Validated Employee request) {
    return ResponseEntity.ok("角色验证通过!");
}

此处@Validated注解确保Spring对Employee对象执行验证。

最后创建全局异常处理器处理验证错误:

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleValidationException(MethodArgumentNotValidException ex) {
    return ex.getBindingResult()
      .getFieldErrors()
      .stream()
      .map(e -> e.getDefaultMessage())
      .collect(Collectors.joining(","));
}

关键注解解析:

  • @ExceptionHandler:指定方法处理的异常类型,此处处理@Valid@Validated验证失败时抛出的MethodArgumentNotValidException
  • @ResponseStatus:设置响应的HTTP状态码,此处返回400 BAD REQUEST表示客户端数据无效
  • MethodArgumentNotValidException:提供验证错误详情,包括失败字段和关联错误消息

现在看一个验证失败场景:

客户端发送无效数据请求:

{
    "roles": ["admin", "ROLE_ADMIN,", ""]
}

根据规则(角色必须以ROLE_开头且非空),响应如下:

每个角色必须以'ROLE_'开头且仅包含大写字母

全局异常处理器的核心优势:确保所有验证错误统一处理,提供用户友好反馈,并消除各控制器中重复的错误处理逻辑。

4. 限制值为预定义列表

前面已学习一种列表值验证方式。现在考虑另一个场景:验证员工所属部门是否在预定义列表中。我们将创建自定义注解实现此功能。

首先创建自定义验证注解:

@Constraint(validatedBy = AllowedValuesValidator.class)
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface AllowedValues {
    String message() default "无效值";
    String[] values();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

代码解析:

  • @Constraint:指定验证逻辑的实现类(AllowedValuesValidator
  • @Target:限制注解应用位置(如字段或方法参数)
  • @Retention:确保注解在运行时可用于验证
  • values:接受预定义的允许值列表
  • message:验证失败时的自定义错误消息
  • groupspayload:分组约束和自定义元数据的可选属性

下一步实现验证器:

public class AllowedValuesValidator implements ConstraintValidator<AllowedValues, List<String>> {
    private List<String> allowedValues;

    @Override
    public void initialize(AllowedValues constraintAnnotation) 
    {
        allowedValues = Arrays.asList(constraintAnnotation.values());
    }

    @Override
    public boolean isValid(List<String> values, ConstraintValidatorContext context) {
        return values != null && values.stream()
          .allMatch(allowedValues::contains);
    }
}

initialize()方法获取注解中定义的允许值并存储为列表,isValid()方法验证输入列表的所有值是否都在允许列表中,并对null输入返回false

最后将自定义注解应用于表示部门的List<String>字段:

@NotEmpty(message = "部门列表不能为空")
@AllowedValues(values = {"Management", "Software Development", "DevOps", "Architect"}, message = "提供的部门无效")
private List<String> department;

@NotEmpty确保列表非空。自定义注解@AllowedValues指定有效部门(如Management、Software Development等),验证失败时返回"提供的部门无效"消息。

5. 总结

本文学习了在Spring中验证列表值的方法,包括限制特定值的场景。通过@Pattern等内置注解和自定义注解,我们能以最小代价确保应用数据完整性。@Pattern的灵活性也使其适用于各种场景下的单个字段验证。


原始标题:Validate List of Values in Spring | Baeldung