springboot项目中@Valid注解的使用-笔记

@Valid是用于Bean验证的注解,支持嵌套校验。文中通过示例展示了如何在SpringBootRESTAPI的方法参数上使用@Valid进行数据验证,并在验证失败时抛出MethodArgumentNotValidException异常。同时,文章还讨论了如何自定义异常处理器来获取并处理验证错误信息,以及如何通过人工干预BindingResult来控制异常的抛出和处理。
摘要由CSDN通过智能技术生成

springboot项目中@Valid注解的使用-笔记

@Vaild介绍

@Valid 是jdk提供的,是jsr-303规范 ,@Valid支持复合bean的嵌套校验,可以用在方法、字段、构造器和参数上

@Valid嵌套校验测试

import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import javax.validation.Valid;
import java.time.LocalDateTime;
import com.alibaba.fastjson.JSONPath;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;



@Slf4j
@RestController
public class Test0529Api {
    @PostMapping("/t123")
    public UserReq test123(@Valid @RequestBody UserReq req){
        log.info("req:{}",req.toString());
        return req;
    }
}

@Data
public class UserReq {
    @NotBlank
    @Size(max = 30,min = 2,message = "长度需要在2-30之间")
    private String account;

    @Email
    private String email;

    @Pattern(regexp = "(?:0|86|\\+86)?1[3-9]\\d{9}",message = "必须是手机号")
    private String phone;

    /**
     * 必须是一个过去的或当前的日期,jdk提供的
     */
    @PastOrPresent
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")  //以特定格式字符串接收请求的日期参数,jackson会自动转为LocalDateTime
    private LocalDateTime  startDt;

    /**
     * 必须是一个将来的或当前的日期,jdk提供的
     */
    @FutureOrPresent  
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime endDt;

    /**
     * 嵌套校验
     */
    @Valid
    private CompanyDTO company;

    /**
     * hibernate.validator包提供的 范围限制注解 @Range ,限制数值的大小
     */
    @Range(min = 1,max = 99)
    private Integer testCount;
}


@Data
public class CompanyDTO {
    @NotNull
    private Integer id;

    @NotBlank
    @Length(max = 30,min=4,message = "长度需要在4-30之间")
    private String name;

    @Pattern(regexp ="(010|02\\d|0[3-9]\\d{2})-?(\\d{6,8})",message = "必须是国内固定电话号码")
    private String tel;
}

测试发现抛MethodArgumentNotValidException异常,经过exceptionHandler处理后,返回

@ExceptionHandler({MethodArgumentNotValidException.class})
    public ResultVO<String> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        log.error("自动抛的MethodArgumentNotValidException",e);
        // 从异常对象中拿到ObjectError对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        log.error("objectError:{}", JSONObject.toJSONString(objectError, true));
        String field = String.valueOf(JSONPath.eval(objectError, "$.field"));
        log.error("field:{}", field);
        String objName = objectError.getObjectName();
        System.err.println(objName);
        // 然后提取错误提示信息进行返回
        return new ResultVO<>(ResultCodeEnum.VALIDATE_FAILED,
                objName + "." + field + objectError.getDefaultMessage());
    }

返回json打印错误提示信息

{
    "code": 9996,
    "msg": "参数校验异常",
    "content": "userReq.testCount需要在1和99之间",
    "timestamp": 1685347134748,
    "traceDateTime": "2023-05-29 15:58:54"
}

@Valid校验,人为干预BindingResult

人为干预BindingResult的,需要人工抛出异常
/**
     * @Valid+BindingResult  人为干预Binding判断
     *
     * @param req
     * @param bindingResult  当增加了BindingResult对象后,参数校验失败时不会自动抛异常,需要人工进行异常处理
     * @return
     */
    @PostMapping("/test003")
    public UserReq test003(@Valid @RequestBody UserReq req, BindingResult bindingResult){
        log.info("req:{}",req.toString());
        //人为干预BindingResult ,人工判断参数是否合法/有错误
        if (bindingResult.hasErrors()){
            //人工抛出异常, 可以对每个参数做特殊的判断
            ObjectError objectError = bindingResult.getAllErrors().get(0);
            String field = String.valueOf(JSONPath.eval(objectError, "$.field"));
            String objName = objectError.getObjectName();
            //这里把bind的参数异常 手动抛出为非法参数异常
            throw new IllegalArgumentException(objName + "." + field + objectError.getDefaultMessage());
        }
        return req;
    }
{
    "code": 9988,
    "msg": "非法参数异常",
    "content": "userReq.testCount需要在1和99之间",
    "timestamp": 1685348120036,
    "traceDateTime": "2023-05-29 16:15:20"
}

手动抛出的异常也要在exceptionHandler里处理

/**
     * 手动抛出的或 Assert断言的 非法参数异常
     *
     * @param e IllegalArgumentException
     * @return ResultVO
     */
    @ExceptionHandler({IllegalArgumentException.class})
    public ResultVO illegalArgumentExceptionHandler(IllegalArgumentException e) {
        log.error("人工抛出异常的IllegalArgumentException",e);
        return new ResultVO<>(ResultCodeEnum.VALIDATE_FAILED,
                e.getMessage());
    }

兜底方案,就是直接捕获处理Exception.class

/**
     * 未知异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler({Exception.class})
    public ResultVO otherExceptionHandle(Exception e) {
        log.error("otherExceptionHandle", e);
        return new ResultVO(ResultCodeEnum.ERROR, e.getMessage());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ThinkPet

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

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

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

打赏作者

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

抵扣说明:

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

余额充值