基于ConstraintValidator自定义校验注解

开发中经常会碰到很多校验,如:空校验、长度校验、手机号校验、数值校验等。通过注解去做这些校验能省不少事。

事实上我们也会用这些注解,但有时候自带的注解不能满足我们的业务需求,这时候就需要我们自定义一些注解去使用。

注意:下面代码用到的jar包javax.validation.*来自于SpringBoot。而SpringBoot在2.3.0版本以后就不再引入这个包了。

具体如下:

1.自定义注解


import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

/**
 * 自定义字节长度校验注解
 *
 * @author ChenHol.Wong
 * @create 2020/10/12 21:49
 */
@Documented
@Constraint(validatedBy = ByteLengthValid.class) // 注意这里!
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ByteLength {

    int length() default 0;  // 定义属性值长度

    String message() default "字段长度超长"; // 定义错误提示信息

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

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

2.给自定义注解书写规则,编写一个类实现ConstraintValidator接口,这是个泛型接口,泛型中第一个是自定义的注解,第二个是注解使用的类型。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.io.UnsupportedEncodingException;

/**
 * 注解校验规则
 *
 * @author ChenHol.Wong
 * @create 2020/10/12 21:49
 */
public class ByteLengthValid implements ConstraintValidator<ByteLength, String> {

    private static final Logger logger = LoggerFactory.getLogger(ByteLengthValid.class);

    private int length = 0;

    @Override
    public void initialize(ByteLength constraintAnnotation) {
        length = constraintAnnotation.length(); // 初始化方法,获取注解的属性值
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (length == 0) {
            return false;
        }
        try {
            if (value != null) {
                return value.trim().getBytes("UTF-8").length <= this.length;
            }
        } catch (UnsupportedEncodingException e) {
            logger.error("获取字节长度异常:", e);
        }
        return false;
    }
}

 根据以上定义的规则知道这个注解是校验属性值的字节长度。

使用时在Co'n't'roller的请求中通过@Valid注解开启,如下:

import com.jason.test.project.model.ValidRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

/**
 * @author ChenHol.Wong
 * @create 2020/10/12 21:42
 */
@RestController
@RequestMapping("/valid")
public class TestValidController {


    @PostMapping("/login")
    public Object test(@RequestBody @Valid ValidRequest request) {
        return request.toString();
    }

}

这样每次请求的时候都会去校验带有此注解的属性值。如果校验不通过则会返会异常。下面是我通过postman测试

请求实体类:

public class ValidRequest {

    @NotEmpty
    @ByteLength(length = 5, message = "姓名字段超长")
    private String name;

    @ByteLength(length = 2, message = "账户字段超长")
    private String account;

    @ByteLength(length = 10, message = "密码超长")
    private String password;

    // 省略 getter、setter、toString()
}

 请求信息:

返回信息如下:

{
    "timestamp": "2020-10-12T14:06:48.005+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "ByteLength.validRequest.password",
                "ByteLength.password",
                "ByteLength.java.lang.String",
                "ByteLength"
            ],
            "arguments": [
                {
                    "codes": [
                        "validRequest.password",
                        "password"
                    ],
                    "arguments": null,
                    "defaultMessage": "password",
                    "code": "password"
                },
                10
            ],
            "defaultMessage": "密码超长",
            "objectName": "validRequest",
            "field": "password",
            "rejectedValue": "12345678901234567",
            "bindingFailure": false,
            "code": "ByteLength"
        }
    ],
    "message": "Validation failed for object='validRequest'. Error count: 1",
    "path": "/jason/valid/login"
}

可以通过定义全局异常处理,对MethodArgumentNotValidException异常进行处理,就能得到指定的异常信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中编写自定义校验注解时,可以使用 `@ReportAsSingleViolation` 注解来指定只要有一个校验失败就返回结果,而不是等待所有的校验结果返回。同时,可以使用 `@javax.validation.constraints.Null` 和 `@javax.validation.constraints.NotNull` 注解来判断参数是否为 `null`。 具体来说,你可以按照以下步骤编写一个允许参数为空的自定义校验注解: 1. 定义注解 ```java @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = {MyValidator.class}) @ReportAsSingleViolation public @interface MyAnnotation { String message() default "my message"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } ``` 2. 定义校验器 ```java public class MyValidator implements ConstraintValidator<MyAnnotation, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null) { // 允许参数为空,直接返回 true return true; } // 对非空参数进行校验 boolean isValid = // 校验逻辑 if (!isValid) { context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("my message") .addConstraintViolation(); } return isValid; } } ``` 在校验器中,我们首先判断参数是否为 `null`,如果是,则直接返回 `true`,即认为校验通过。如果参数不为 `null`,则进行校验逻辑,如果校验失败,则使用 `context.buildConstraintViolationWithTemplate()` 方法构建校验失败的信息。 3. 在需要校验的参数上应用注解 ```java public void myMethod(@MyAnnotation String param) { // 方法逻辑 } ``` 在需要校验的参数上使用 `@MyAnnotation` 注解,即可触发自定义校验注解校验逻辑。如果参数为 `null`,则直接返回 `true`,否则进行校验逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值