Spring Boot实现参数校验

前言

在项目开发中,后端对于传参进行校验不可缺少,如何实现呢?除了在代码里面使用if…else…外,本文列举了两种对不同形式的传参进行校验方式,分别是body实体对象(包括map集合)、param参数。

本文项目是基于spring boot开发,版本是2.3.7,pom文件中要先引入spring-boot-starter-validation依赖,如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

如果Spring Boot版本是 2.3 1 之前, spring-boot-starter-web 中,已经包含spring-boot-starter-validation,不需要我们再手动添加!

Body实体对象形式

无论是Body实体对象还是Param参数,都需要在类(controller)上面添加 @Validated注解。

对于有@RequestBody注解的实体对象参数,需要在参数上添加@Valid注解,如果验证失败,它将抛出 MethodArgumentNotValidException异常。默认情况下,Spring 会将此异常转换为 HTTP Status 400(错误请求)。

@RestController
@RequestMapping("/api/person")
@Validated
public class PersonController {

    @PostMapping
    public ResponseEntity<PersonRequest> save(@RequestBody @Valid PersonRequest personRequest) {
        return ResponseEntity.ok().body(personRequest);
    }
}

对于需要校验的参数,在实体类中进行校验,如下

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PersonRequest {

    @NotNull(message = "classId 不能为空")
    private String classId;

    @Size(max = 33)
    @NotNull(message = "name 不能为空")
    private String name;

    @Pattern(regexp = "(^Man$|^Woman$|^UGM$)", message = "sex 值不在可选范围")
    @NotNull(message = "sex 不能为空")
    private String sex;

}

正则表达式说明:

^string : 匹配以 string 开头的字符串
string$ :匹配以 string 结尾的字符串
^string$ :精确匹配 string 字符串
(^Man$|^Woman$|^UGM$) : 值只能在 Man,Woman,UGM 这三个值中选择

Param参数

对于get请求传参,只需要直接在对应参数前面添加校验注解即可。

@Controller
@Validated
public class ValidationController {

    @GetMapping("/validate1")
    @ResponseBody
    public String validate1(
            @Size(min = 1,max = 10,message = "姓名长度必须为1到10")@RequestParam("name") String name,
            @Min(value = 10,message = "年龄最小为10")@Max(value = 100,message = "年龄最大为100") @RequestParam("age") Integer age,
            @Future @RequestParam("birth")@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss") Date birth){
        return "validate1";
    }
}

全局捕获异常

上面已经对参数进行校验,但是对于校验结果需要返回前端,这里就需要创建全局异常捕获类GlobalExceptionHandler,将异常信息封装成前端需要的格式返回,如下。


@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 用来处理validation异常,捕获Param参数校验异常信息
     * @param ex
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public  WebResult resolveConstraintViolationException(ConstraintViolationException ex){
        WebResult errorWebResult = new WebResult(WebResult.FAILED);
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if(!CollectionUtils.isEmpty(constraintViolations)){
            StringBuilder msgBuilder = new StringBuilder();
            for(ConstraintViolation constraintViolation :constraintViolations){
                msgBuilder.append(constraintViolation.getMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if(errorMessage.length()>1){
                errorMessage = errorMessage.substring(0,errorMessage.length()-1);
            }
            errorWebResult.setInfo(errorMessage);
            return errorWebResult;
        }
        errorWebResult.setInfo(ex.getMessage());
        return errorWebResult;
    }

	/**
     * 用来处理validation异常,捕获Body实体属性参数校验异常信息
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public WebResult resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex){
        WebResult errorWebResult = new WebResult(WebResult.FAILED);
        List<ObjectError>  objectErrors = ex.getBindingResult().getAllErrors();
        if(!CollectionUtils.isEmpty(objectErrors)) {
            StringBuilder msgBuilder = new StringBuilder();
            for (ObjectError objectError : objectErrors) {
                msgBuilder.append(objectError.getDefaultMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if (errorMessage.length() > 1) {
                errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
            }
            errorWebResult.setInfo(errorMessage);
            return errorWebResult;
        }
        errorWebResult.setInfo(ex.getMessage());
        return errorWebResult;
    }
}

常用的注解校验:

JSR303 定义了 Bean Validation(校验)的标准, validation-api并没有提供实现。 Hibernate Validation是对这个规范/规范的实现,并且增加了 @Email@Length@Range 等注解。 Spring Validation底层依赖的就是 Hibernate Validation

JSR 提供的校验注解:

@Null 被注释的元素必须为 null
@NotNull 被注释的元素不能为null,接受任何类型。
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式

Hibernate Validator 提供的校验注解:

@NotBlank(message =)   非 null,且长度必须大于 0,只用于验证String类型参数
@Email  被注释的元素必须是电子邮箱地址
@Length(min=,max=)   被注释的字符串的大小必须在指定的范围内
@NotEmpty     String、Collection、Map、数组是不能为null或长度不为0
@Range(min=,max=,message=)   被注释的元素必须在合适的范围内

至此,参数校验就实现了,但是如果官方提供的校验注解不满足业务需要,你也可以自定义校验注解。

自定义校验注解

创建约束注解类
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { FlagValidatorClass.class})
public @interface FlagValidator{

    String message() default "parameter is not correct";

    String[] value() default {"少林","武当"};

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

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

@Constraint(validatedBy = { FlagValidatorClass.class}) 用来指定处理这个注解逻辑的类

创建注解校验类
public class FlagValidatorClass implements ConstraintValidator<FlagValidator, String> {

   private String[] values;

    /**
     * 用于初始化注解上的值到这个validator
     * @param constraintAnnotation
     */
    @Override
    public void initialize(FlagValidator flagValidator) {
        values =flagValidator.value();
    }

    /**
     * 具体的校验逻辑
     * @param value
     * @param context
     * @return
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
    	List<String> list = Arrays.asList(values);
        return list.contains(value);
    }
}

现在你就可以使用@FlagValidator这个注解了,无论是放在Param参数上还是Body实体中。

参考:
https://www.jianshu.com/p/89a675b7c900

https://blog.csdn.net/qq_34337272/article/details/116046544?spm=1001.2014.3001.5501

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中,可以使用Spring Boot Validation来对参数名称进行校验。通过引入spring-boot-starter-validation依赖,可以使用Spring Validator对参数进行校验Spring Validator是对Hibernate Validator的进一步封装,同时支持Spring MVC的自动校验。你可以在Spring官方文档中找到更多关于Spring Boot Validation的详细信息\[2\]。 在使用Spring Boot Validation时,可以使用@Validated注解来标记需要校验的类型、方法和方法参数。@Validated注解属于org.springframework.validation.annotation包,是Spring校验机制之一。它具有分组校验的功能,可以用于类型、方法和方法参数上,但不能用于成员属性(field)\[3\]。 通过使用Spring Boot Validation,你可以简化参数校验的代码,提高代码的可读性和美观性。 #### 引用[.reference_title] - *1* *3* [Spring Boot参数校验](https://blog.csdn.net/qq1929892209/article/details/126133350)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Spring Boot 参数校验校验工具类](https://blog.csdn.net/WEDUEST/article/details/121594610)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值