SpringBoot整合Validation实现参数校验

1.springboot已经整合Validation
jar包坐标

 <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

2.定义相关的异常处理类(并配置快速校验失败返回结果,可选)

import lombok.extern.slf4j.Slf4j;
import loss.reduction.utils.Result;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.stream.Collectors;

/**
 * 定义全局处理异常
 */
@RestControllerAdvice
@Slf4j
@Configuration
public class ExceptionHandlerConfig {

    /**
     * 全局处理异常
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Result handlerException(Exception e){
        e.printStackTrace();
        log.error(e.getMessage());
        return new Result().error(e.getMessage());
    }

    /**
     * 处理 form data方式调用接口校验失败抛出的异常
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    public Result handlerException(BindException e){
        BindingResult bindingResult = e.getBindingResult();
        String result = bindingResult.getFieldErrors().stream().map(o -> o.getDefaultMessage()).collect(Collectors.joining(","));
        return new Result().error(result);
    }

    /**
     * 处理 json 请求体调用接口校验失败抛出的异常
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handlerException(MethodArgumentNotValidException e){
        BindingResult bindingResult = e.getBindingResult();
        String result = bindingResult.getFieldErrors().stream().map(o -> o.getDefaultMessage()).collect(Collectors.joining(","));
        return new Result().error(result);
    }

    /**
     * 处理requestParam/PathVariable参数校验的异常
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result handlerException(ConstraintViolationException e){
        String result = e.getConstraintViolations().stream().map(o -> o.getMessage()).collect(Collectors.joining(","));
        return new Result().error(result);
    }

    /**
     * spring Validation默认校验完所有参数才会返回结果,可将failFast设置为true,一旦校验失败就会结果校验并返回结果
     * @return
     */
    @Bean
    public Validator validator(){
        ValidatorFactory factory=Validation.byProvider(HibernateValidator.class).
                configure().failFast(true).buildValidatorFactory();
        return factory.getValidator();
    }
}

3.requestBody参数校验(json格式参数校验)
3.1.实体类

@ApiModel
@Data
public class TestValidationDto {

    @NotNull(message = "id不能为空")
    @ApiModelProperty("id")
    private Integer id;

    @NotBlank(message = "name不能为空")
    @Length(max = 10,min = 2,message = "姓名长度2-10")
    @ApiModelProperty("姓名")
    private String name;

    @Min(value = 1,message = "年龄不能小于1")
    @Max(value = 100,message = "年龄不能大于100")
    @ApiModelProperty("年龄")
    @NotNull(message = "年龄不能为空")
    private Integer age;
}

3.2.controller层

@RestController
@RequestMapping("/test")
public class TestController {
	@ApiOperation("测试")
    @PostMapping ("update")
    public Result update(@RequestBody @Validated TestValidationDto dto) {
        return new Result().ok("11");
    }
}

这种情况下,使用@Valid和@Validated都可以。

4.requestParam/PathVariable参数校验
GET请求一般会使用requestParam/PathVariable传参。如果参数比较多 (比如超过 5 个),还是推荐使用DTO对象接收。否则,推荐将一个个参数平铺到方法入参中。在这种情况下,必须在Controller类上标注@Validated注解,并在入参上声明约束注解 (如@Min等)。如果校验失败,会抛出ConstraintViolationException异常。代码示例如下:

@RestController
@RequestMapping("/test")
//对get请求的参数生效
@Validated
@Slf4j
public class TestController {
	@GetMapping("test1")
    public Result test1(@RequestParam @NotBlank(message = "name不能为空") String name, @RequestParam @Max(value = 100,message = "id不能大于100") Integer id) {
        log.info("name:{}",name);
        return new Result().ok("1111");
    }

    @GetMapping("test2/{id}")
    public Result test2(@PathVariable @Max(value = 100,message = "id不能大于100") Integer id) {
        log.info("id:{}",id);
        return new Result().ok("1111");
    }
}

5.分组校验
5.1.实体类

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.groups.Default;

@ApiModel
@Data
public class TestValidationDto {

    @NotNull(message = "id不能为空",groups ={Update.class} )
    @ApiModelProperty("id")
    private Integer id;

    @NotBlank(message = "name不能为空",groups = {Insert.class,Update.class})
    @Length(max = 10,min = 2,message = "姓名长度2-10")
    @ApiModelProperty("姓名")
    private String name;

    @Min(value = 1,message = "年龄不能小于1")
    @Max(value = 100,message = "年龄不能大于100")
    @ApiModelProperty("年龄")
    @NotNull(message = "年龄不能为空")
    private Integer age;
 
	 /**
     * 更新组
     * 继承Default接口的好处:校验组内的属性的同时,也会校验未分组的属性
     */
    public interface Update extends Default{

    }
	
	 /**
     * 新增组
     * 继承Default接口的好处:校验组内的属性的同时,也会校验未分组的属性
     */
    public interface Insert extends Default {

    }
}

5.2.controller

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
	@ApiOperation("测试更新")
    @PostMapping ("update")
    public Result update(@RequestBody @Validated(TestValidationDto.Update.class) TestValidationDto dto) {
        return new Result().ok("11");
    }

    @ApiOperation("测试新增")
    @PostMapping ("insert")
    public Result insert(@RequestBody @Validated(TestValidationDto.Insert.class) TestValidationDto dto) {
        return new Result().ok("11");
    }
}

6.嵌套校验/递归校验
前面的示例中,DTO类里面的字段都是基本数据类型和String类型。但是实际场景中,有可能某个字段也是一个对象,这种情况先,可以使用嵌套校验。
比如,上面保存TestValidationDto信息的时候同时还带有Student信息。需要注意的是,此时DTO类的对应字段必须标记@Valid注解(对于集合同样适用)。

6.1.实体类

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.groups.Default;

@ApiModel
@Data
public class TestValidationDto {

    @NotNull(message = "id不能为空",groups ={Update.class} )
    @ApiModelProperty("id")
    private Integer id;

    @NotBlank(message = "name不能为空",groups = {Insert.class,Update.class})
    @Length(max = 10,min = 2,message = "姓名长度2-10")
    @ApiModelProperty("姓名")
    private String name;

    @Min(value = 1,message = "年龄不能小于1")
    @Max(value = 100,message = "年龄不能大于100")
    @ApiModelProperty("年龄")
    @NotNull(message = "年龄不能为空")
    private Integer age;

    @ApiModelProperty("学生对象")
    @Valid
    private Student student;

    /**
     * 更新组
     * 继承Default接口的好处:校验组内的属性的同时,也会校验未分组的属性
     */
    public interface Update extends Default{

    }

    /**
     * 新增组
     * 继承Default接口的好处:校验组内的属性的同时,也会校验未分组的属性
     */
    public interface Insert extends Default {

    }

    @Data
    public static class Student{

        @ApiModelProperty("性别")
        @NotBlank(message = "性别不能为空")
        private String sex;
    }
}

controller层

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
	@ApiOperation("测试更新")
    @PostMapping ("update")
    public Result update(@RequestBody @Validated(TestValidationDto.Update.class) TestValidationDto dto) {
        return new Result().ok("11");
    }

    @ApiOperation("测试新增")
    @PostMapping ("insert")
    public Result insert(@RequestBody @Validated(TestValidationDto.Insert.class) TestValidationDto dto) {
        return new Result().ok("11");
    }
}

7.自定义校验
7.1.自定义注解


```java
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
//标明由哪个类执行校验逻辑
@Constraint(validatedBy = {MyConstraintValidator.class })
public @interface ISBLANK {

    String message() default "格式不对";

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

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

7.2.校验逻辑类

import org.apache.commons.lang3.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class MyConstraintValidator implements ConstraintValidator<ISBLANK,String> {

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (StringUtils.isBlank(value)) {
            return true;
        }
        return false;
    }
}

7.3.使用

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@ApiModel
@Data
public class TestValidationDto {
    @ISBLANK(message = "班级必须为空")
    private String class1;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值