SpringBoot引入hibernate.validator参数校验

对前台传来的参数,一般需要进行检验它的值是符合预期。如果使用if()else{},当参数很多时,代码几乎没有可维护性。可以借助hibernate校验工具方便实现这一功能。

添加依赖

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

或者

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.13.Final</version>
     </dependency>

注意第二种依赖的groupId不是org.hibernate,因为这个groupId已经废弃,移至org.hibernate.validator。
在这里插入图片描述

校验@RequestParam参数

  1. 在Controller类上添加注解@Validated注解
  2. 在参数前加上校验注解
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;

@RestController
@Validated
public class ValidController {

    @RequestMapping(method = RequestMethod.GET, value = "valid1")
    public String valid1(@Length(min = 3,max = 10, message = "长度在3到10之间")  @RequestParam String name,
                         @RequestParam @Max(value = 99, message = "不能大于99岁") Integer age) {
        System.out.println(name);
        return "ok";
    }
}

校验@RequestBody参数

Stu实体类

class Stu{
    @NotNull(message = "名字不能为空")
    private String name;
    @Range(min = 18, max = 30, message = "年龄在18到30之间")
    private int age;
    // getter and setter...
}

Controller接口

import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;

@RestController
@Validated
public class ValidController {

    @RequestMapping(method = RequestMethod.POST, value = "valid2")
    public String valid2(@Valid @RequestBody Stu stu) {
        return "ok";
    }
}

注意在实体类参数前加的@Valid注解

嵌套校验

如果实体类中还有实体类,按照上述方法添加@Valid是不会检查内部实体类的约束的。要使内部实体类的约束也生效,可以这样。
在Stu实体类中加入Hobby。

class Hobby {
    @NotNull
    @NotEmpty
    private String name;
    @Range(min = 0, max = 10)
    private double price;
    // getter and setter...
}
class Stu{

    @NotNull(message = "名字不能为空")
    private String name;
    @Range(min = 18, max = 30, message = "年龄在18到30之间")
    private int age;
    @NotEmpty @Valid
    List<Hobby> hobbies;
    // getter and setter...
}

统一处理异常

当传入的参数不满足约束条件时,会抛出异常,可以对这些异常做统一处理。
对@RequestBody参数的校验失败会抛出MethodArgumentNotValidException。
对@RequestParam参数校验失败会抛出ConstraintViolationException,所以两种异常都要捕获。

import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

@ControllerAdvice
public class MyAdvice {
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public String handlerException(MethodArgumentNotValidException ex) {
        final List<ObjectError> allErrors = ex.getBindingResult().getAllErrors();
        if (allErrors.size() > 0) {
            final StringBuilder stringBuilder = new StringBuilder();
            allErrors.forEach(error -> {
                stringBuilder.append(error.getDefaultMessage()).append(",");
            });
            return stringBuilder.toString();
        }
        return "没有错误呀";
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public String handlConstraintViolationException(ConstraintViolationException ex) {
        final Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if (constraintViolations == null || constraintViolations.size() == 0) {
            return "没有异常呀";
        }
        final StringBuilder stringBuilder = new StringBuilder();
        constraintViolations.forEach(e -> {
            stringBuilder.append(e.getMessage()).append(",");
        });
        return stringBuilder.toString();
    }
}

测试

校验@RequestParam参数
在这里插入图片描述
校验@RequestBody参数
1.校验外层实体类
在这里插入图片描述

2.校验内部实体类
在这里插入图片描述

普通方法校验参数

如果我要校验的参数不在Controller里,而在一个service里,配置流程和@RequestParam参数的校验一致。也是先在类上加@Validated,再用校验注解修饰参数。有三点要注意

  1. 校验复杂参数用@Valid
  2. 注意接口与实现类中的注解的一致性
  3. 如果校验不通过,也是抛出ConstraintViolationException异常
//service 接口
public interface HelloService {
    String sayHello(@Valid Stu stu);//注意这里的注解要与实现类一致
}
//service 实现类
@Validated
@Service
public class HelloServiceImpl implements HelloService {
    @Override
    public String sayHello(@Valid Stu stu) {
        return stu.getName() + " sayhello";
    }
}

快速失败

默认情况下会对所有参数进行校验,就像上文对@RequestParam参数的校验,一旦校验不通过,会把所有提示信息返回。如果我们希望只要校验不通过就立马返回,不再进行其他参数校验,可以配置failFast属性为true。

    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(true)
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }

参考

  1. Spring Validation最佳实践及其实现原理,参数校验没那么简单!
  2. springboot 参数校验详解
  3. 原创:全局异常捕获BindException、MethodArgumentNotValidException和ConstraintViolationException @Validated@Valid
  4. spring boot 优雅的参数校验
  5. SpringBoot 使用 JSR303 自定义校验注解
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值