JSR303参数校验

1.给Bean添加校验注解:javax.validation.constraints,并定义自己的message提示

例如:

    @NotNull(message = "修改必须指定ID", groups = {UpdateGroup.class})
	@Null(message = "新增不能指定ID", groups = {AddGroup.class})
	@TableId
	private Long brandId;

    @NotBlank(message = "名称不能为空", groups = {AddGroup.class, UpdateGroup.class})
	private String name;

    @Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须是一个字母")
    private String firstLetter;

NotNull和Null是校验类下规则,message指定校验失败时的报错信息。groups是指定分组(UpdateGroup和AddGroup是自定义的接口类),需要配合参数注解指定分组来确定是否需要校验。

2.开启校验功能,可以使用java规范(javax.validation.Valid)@Valid,但是该注解没有任何属性。我们可以使用Spring自带的(org.springframework.validation.annotation.Validated)@Validated可以支持分组功能。

@RequestMapping("/update")
public RespData update(@Validated({UpdateGroup.class}) @RequestBody BrandEntity brand)

UpdateGroup.class指定这是更新操作,只有上面1中属于UpdateGroup分组的字段才需要校验,

@RequestBody 自动将传递的json参数映射为BrandEntity实体对象。

注意:默认没有指定分组的校验注解,在分组校验情况下不生效,只会在@Validated生效;

3.获取校验结果:

        方式一通过参数后紧跟BindingResult对象:        

public RespData save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand, BindingResult result){
	if(result.hasErrors()){
	    Map<String, String> map = new HashMap<>();
	    //获取校验的错误结果
	    result.getFieldErrors().forEach((item) -> {
	        //FieldError获取错误提示
	        String message = item.getDefaultMessage();
	        //获取错误的属性的名字
	        String field = item.getField();
	        map.put(field, message);
	    });
	    return RespData.error(400, "提交的数据不合法").put("data", map);
	}
}

方式二统一处理异常,自定义异常处理类:

/**
 * 集中处理所有异常
 */
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.example.controller")
@RestControllerAdvice(basePackages = "com.example.controller")
public class ExampleExceptionControllerAdvice {

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public RespData handleValidException(MethodArgumentNotValidException e){
        log.error("数据校验出现问题{},异常类型{}", e.getMessage(), e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        Map<String, String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError) -> {
            errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
        });
        return RespData.error(BizCodeEnume.VALID_EXCEPTION.getCode(), BizCodeEnume.VALID_EXCEPTION.getMsg()).put("data", errorMap);
    }

    @ExceptionHandler(value = Throwable.class)
    public RespData handleException(Throwable throwable){
        return RespData.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(), BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }
}

错误类型枚举类:

public enum BizCodeEnume {

    UNKNOW_EXCEPTION(10000, "系统未知异常"),
    VALID_EXCEPTION(10001, "参数格式校验失败");

    private int code;
    private String msg;

    BizCodeEnume(int code, String msg){
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

@RestControllerAdvice是@ResponseBody和@ControllerAdvice的合并效果,

basePackages指定处理该包下的异常。

@ExceptionHandler指定处理的异常

以上即可实现基本的数据校验功能,但有时候需要我们自定义校验方法,创建自定义校验器

例如我们要实现一个字段只能是指定值中的一个:

@ListValue(vals= {0, 1}, message = "必须是指定的值")
private Integer status;

首先需要导入依赖:

<dependency>
   <groupId>jakarta.validation</groupId>
   <artifactId>jakarta.validation-api</artifactId>
   <version>2.0.2</version>
   <scope>compile</scope>
</dependency>

然后我们可以参考@NotBlank编写:

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

@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class})
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {

    String message() default "{com.example.valid.ListValue.message}";

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

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

    int[] vals() default {};
}

message对应错误消息,可以在resources文件夹下创建ValidationMessages.properties文件,在文件中编写对应的错误消息:

com.example.valid.ListValue.message=必须是指定的值

也可以在写注解时指定message。

@Constraint(validatedBy = {ListValueConstraintValidator.class})确定注解的校验器:

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;

public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {

    private Set<Integer> set = new HashSet<>();
    //初始化方法
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        for (int val : vals){
            set.add(val);
        }
    }

    /**
     *
     * @param value 需要校验的值
     * @param constraintValidatorContext
     * @return
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
        return set.contains(value);
    }
}

至此完成了ListValue的自定义校验功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值