更加灵活的参数校验,Spring-boot自定义参数校验注解

本文介绍在Spring Boot中如何自定义参数校验注解和验证类,以实现复杂校验规则,如密码一致性检查。

上文测试开发专题:如何在spring-boot中进行参数校验,我们讨论了如何使用@Min、@Max等注解进行参数校验,主要是针对基本数据类型和级联对象进行参数校验的演示,但是在实际中我们往往需要更为复杂的校验规则,比如注册用户的密码和确认密码进行校验,这个时候基本的注解就无法满足我们的要求了,需要去按照业务需求去自定义注解进行校验

元注解

在自定义注解之前我们有必要了解一些元注解,元注解就是在注解上的注解,可以对一个注解进行配置,元注解包括@Retention、@Target、@Document、@Inherited四种

  • @Retention,表示注解保留到什么时候,有以下三种模式

    • @Retention(RetentionPolicy.SOURCE) 表示注解仅存在于源码中,在class字节码文件中不包含
    • @Retention(RetentionPolicy.CLASS) 表示 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
    • @Retention(RetentionPolicy.RUNTIME) 表示注解会在class字节码文件中存在,在运行时可以通过反射获取到
  • @Target表示注解的作用目标是什么,只列出下面几个,剩余的大家自行谷歌把

    • @Target(ElementType.TYPE) 表示注解可以应用于接口、类、枚举、注解
    • @Target(ElementType.FIELD) 表示可以应用于字段、成员变量、枚举的常量等
    • @Target(ElementType.METHOD)表示可以作用于方法
  • @Document表示注解包含在javadoc中

  • @Inherited表示注解可以被继承

自定义校验注解

就以用户注册为例,我们需要校验密码和确认密码是否一致以及是否符合密码的规则,先新建一个PasswordEqual注解类

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Constraint(validatedBy = PasswordValidator.class)
public @interface PasswordEqual {

    String message() default "密码不一样";

    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

下面我们来解释一下上面的注解,在PasswordEqual注解上,又标记了四个注解,前三个我们上面已经说过了。

这里说一下@Constraint注解,它表示这个注解是一个验证注解,并且通过validatedBy指定自定义校验注解的关联类,PasswordValidator类就是我们自定义的注解关联的类。

注解里面的groups和payload方法是模板方法,实现自定义注解必须写这么两个方法。

定义验证类

验证类里面包含具体的验证逻辑了,下面是一个简版的:

public class PasswordValidator implements ConstraintValidator<PasswordEqual, BannerCreateDto> {

    @Override
    public boolean isValid(BannerCreateDto dto, ConstraintValidatorContext constraintValidatorContext) {
        
        return false;
    }
}

这里需要对上面的代码进行一下说明,实现自定义校验类必须实现

ConstraintValidator接口,它是一个泛型接口,需要指定两个类型参数,第一个是自定义注解类型,第二个类型指定自定义注解修饰目标的类型,就是准备把自定义注解标记到什么类型上面。

必须重写isValid方法,所有的校验逻辑都在这个方法里面,下面我们简单写一下:

@Override
public boolean isValid(UserDto dto, ConstraintValidatorContext constraintValidatorContext) {
    if (dto.getPassword().equals(dto.getConfirmPassword())){
        return true;
    }
    return false;
}

然后我们将自定义的注解类标记到UserDto类上:

@Builder
@Getter
@Setter
@PasswordEqual
public class UserDto {

    @Length(min = 4, max = 10, message = "用户名长度必须在4-10个字符之间")
    private String name;

    private String password;

    private String confirmPassword;
}

接下来我们在写一个简单的创建用户的接口:

@RestController
public class UserController {


    @PostMapping("/v2/user/create")
    @ResponseBody
    public UserDto createUser(@RequestBody @Validated UserDto dto){
        return dto;
    }
}

注意这里有要使用@ResponseBody能够返回自动序列化自定义对象,并且要写上 @Validated开启校验机制。

我们先输入正确的密码和确认密码一下:

image-20200514233442583

可以看到能够正常的返回数据,这时再把两个密码改的不一样,试试:

image-20200514233522345

这个时候就抛出了异常,这里的异常信息是因为进了全局异常处理器,不清楚的童鞋可以看下之前的文章。我们再来看一下控制台的输出:

image-20200514233648244

控制台已经输出了校验的错误信息。

总结

我们今天介绍了自定义参数校验,并编写了校验注解和校验类,但是最后返回给用户的信息非常不友好,需要针对参数校验错误,能够返回定义的message,能够让有用户明白是哪里错了,下篇文章我们将介绍这块的内容,敬请关注!!

欢迎大家去 我的博客 瞅瞅,里面有更多关于测试实战的内容哦!!

Spring Boot 中,使用 `spring-boot-starter-validation` 实现分组参数校验,主要依赖于 `@Validated` 注解和分组接口的定义。与 `@Valid` 不同,`@Validated` 支持分组校验,可以在不同的业务场景下对参数的不同属性进行有选择的校验。 ### 实现步骤 1. **定义校验分组接口** 创建两个或多个空接口,分别表示不同的校验组。例如,`CreateGroup` 和 `UpdateGroup`。 ```java public interface CreateGroup {} public interface UpdateGroup {} ``` 2. **在实体类中使用分组** 在实体类的字段上使用 Bean Validation 注解(如 `@NotBlank`, `@Min` 等),并通过 `groups` 属性指定该字段属于哪个校验组。 ```java import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; public class User { @NotBlank(message = "用户名不能为空", groups = CreateGroup.class) private String username; @Min(value = 18, message = "年龄必须大于等于18岁", groups = {CreateGroup.class, UpdateGroup.class}) private int age; @NotBlank(message = "邮箱不能为空", groups = UpdateGroup.class) private String email; // Getter and Setter } ``` 3. **在 Controller 中启用分组校验** 使用 `@Validated` 注解标注 Controller 类,并在方法参数上使用 `@Valid` 同时指定分组。注意 `@Validated` 是类级别的注解,而 `@Valid` 用于方法参数。 ```java 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; import javax.validation.Valid; @RestController @Validated public class UserController { @PostMapping("/createUser") public String createUser(@Validated(CreateGroup.class) @RequestBody User user) { return "用户创建成功"; } @PostMapping("/updateUser") public String updateUser(@Validated(UpdateGroup.class) @RequestBody User user) { return "用户更新成功"; } } ``` 4. **异常处理(可选)** 可以通过 `@ControllerAdvice` 或 `@ExceptionHandler` 捕获 `MethodArgumentNotValidException`,统一返回校验失败的信息。 ```java import org.springframework.http.HttpStatus; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class ValidationHandler { @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach((error) -> { String fieldName = ((org.springframework.validation.FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return errors; } } ``` ### 总结 通过上述步骤,可以在 Spring Boot 应用中实现基于 `@Validated` 的分组参数校验机制,从而在不同的业务场景下对参数进行精细化控制,确保数据的完整性与一致性[^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

测试老憨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值