优雅的参数校验@Validated 实战 + 统一异常处理返回前端json 最全解析

数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,使用@Valid和@Validated注解可以很好的避免后端代码满屏if-else。

1 引入依赖

springboot版本小于2.3时spring-boot-starter-web包含了依赖不用再引入
当springboot版本大于2.3时需要手动引入依赖

          <!--第一种方式导入校验依赖:使用springboot时,在org\springframework\spring-context\5.2.1.RELEASE\spring-context-5.2.1.RELEASE.jar-->
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--第二种方式导入校验依赖-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <!--第三种方式导入校验依赖-->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>

2 @Valid和@Validated的用法(区别)

二者主要作用在于 都作为标准JSR-303规范,在检验Controller的入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同:

@Valid注解用于校验,所属包为:javax.validation.Valid。
用在方法入参上无法单独提供嵌套验证功能。**能够用在成员属性(字段)**上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

@Validated是@Valid 的一次封装,是Spring提供的校验机制使用。
用在方法入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

3 常用校验注解

@NotEmpty 被注释的字符串的不能为 null 也不能为空
@NotBlank 被注释的字符串非 null,并且必须包含一个非空白字符
@Null 被注释的元素(数字)必须为 null
@NotNull 被注释的元素(数字)必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Pattern(regex=,flag=)被注释的元素必须符合指定的正则表达式
@Email 被注释的元素必须是 Email 格式。
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素(集合)的大小必须在指定的范围内
@Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内

4 参数校验

4.1 控制器上加校验注解

千万不要忘记在类上加@Validated注解,否则验证注解不生效

@RestController
@Api("阅读记录")
@RequestMapping("/record")
@Validated
public class ReadRecordController {

    @Autowired
    private ReadRecordService readRecordService;

    @PostMapping("/addRecord")
    @ApiOperation("新增阅读记录")
    public ResponseResult addRecord(@RequestBody @Valid ReadRecord readRecord){
        return readRecordService.addRecord(readRecord);
    }

    @ApiOperation("查询阅读记录")
    @GetMapping("/getReadRecord")
    public ResponseResult getReadRecord(@Valid @NotBlank(message = "fileCode不能传空值") String fileCode){
        return readRecordService.getReadRecord(fileCode);
    }
}

4.2 实体类上加校验注解

对接受实体加注解的字段进行校验,如果验证失败,它将抛出MethodArgumentNotValidException异常。

@Data
public class ReadRecord {
    private String id;

    private String companyName;

    private String deleteFlag;

    @NotBlank(message = "loginName不能传空")
    private String loginName;

    @NotBlank(message = "fileCode不能传空")
    private String fileCode;
    }

5 自定义注解

如果在写项目的过程中,参数需要的条件注解满足不上,则我们需要自定义注解来完成

5.1 创建一个自定义的注解类

@Documented
@Constraint(validatedBy = PhoneNumberValidator.class)
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public@interface PhoneNumber {
    String message() default "Invalid phone number";
    Class[] groups() default {};
    Class[] payload() default {};
}

5.2 创建一个逻辑处理数据的方法

publicclass PhoneNumberValidator implements ConstraintValidator<PhoneNumber,String> {
    @Override
    public boolean isValid(String phoneField, ConstraintValidatorContext context) {
        if (phoneField == null) {
            // can be null
            returntrue;
        }
        return phoneField.matches("^1(3[0-9]|4[57]|5[0-35-9]|8[0-9]|70)\\d{8}$") && phoneField.length() > 8 && phoneField.length() < 14;
    }
}

5.3使用自定义注解

@PhoneNumber(message = "phoneNumber 格式不正确")
@NotNull(message = "phoneNumber 不能为空")
private String phoneNumber;

6 统一异常处理

我们使用了@valiated注解,也写了@NotBlank校验,控制台也打印了校验信息,但是前端就是没有收到我们返回的校验信息.是因为我们没有自定义捕获异常后的处理方式,没有返回给前端这些处理信息。

如果要将报错信息返回给前端只需要对信息做统一异常处理就好。

@ControllerAdvice
public class CustomHandle {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseResult methodArgumentNotValidException(MethodArgumentNotValidException e){
        List<ObjectError> allErrors = e.getAllErrors();
        List<String> collect = allErrors.stream()
                .map(error -> error.getDefaultMessage())
                .collect(Collectors.toList());
        return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,collect.toString());
    }
}

至此便可将报错信息返回前端

{
	"token": null,
	"code": 501,
	"message": "[loginName不能传空]",
	"data": null,
	"status": null
}

如果觉得文章对您有用,还请一键三连哦!!!更多实用文章在主页!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值