【Spring 校验】

校验

主页传送门:📀 传送

🍇 概述


Java API 规范(JSR303)定义了Bean校验的标准validation-api,但没有提供具体的实现方法。hibernate validation是对这个规范的实现,并增加了如@Email@Length等校验注解。Spring Validation是对hibernate validation的二次封装,用于支持spring mvc参数的自动校验。

🍉 使用场景

Spring 校验使用场景

  • Spring 常规校验(Validator)
  • Spring 数据绑定(DataBinder)
  • Spring Web 参数绑定(WebDataBinder)
  • Spring WebMVC/WebFlux 处理方法参数校验

🍉 依赖引入


如果 spring-boot 版本小于 2.3.x,spring-boot-starter-web 会自动传入 hibernate-validator 依赖。如果 spring-boot 版本大于 2.3.x,则需要手动引入依赖:

java 复制代码
<dependency>
  <groupId>org.hibernate.validator</groupId>
  <artifactId>hibernate-validator-parent</artifactId>
  <version>6.2.5.Final</version>
</dependency>

对于 web 服务来说,为防止非法参数对业务造成影响,在 Controller 层一定要做参数校验的!大部分情况下,请求参数分为如下两种形式:

  • POST、PUT 请求,使用 requestBody 传递参数;
  • GET 请求,使用 requestParam/PathVariable 传递参数。

实际上,不管是 requestBody 参数校验还是方法级别的校验,最终都是调用 Hibernate Validator 执行校验,Spring Validation 只是做了一层封装。

🍍 校验示例


🍈(1)在实体上标记校验注解

示例

java 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {

    @NotNull
    private Long id;

    @NotBlank
    @Size(min = 2, max = 10)
    private String name;

    @Min(value = 1)
    @Max(value = 100)
    private Integer age;

}

上述类使用了Lombok库的@Data、@NoArgsConstructor和@AllArgsConstructor注解,分别用于自动生成getter、setter、无参构造方法和全参构造方法

🍒(2)在方法参数上声明校验注解

java 复制代码
@Slf4j
@Validated
@RestController
@RequestMapping("validate1")
public class ValidatorController {

    /**
     * {@link RequestBody} 参数校验
     */
    @PostMapping(value = "save")
    public DataResult<Boolean> save(@Valid @RequestBody User entity) {
        log.info("保存一条记录:{}", JSONUtil.toJsonStr(entity));
        return DataResult.ok(true);
    }

    /**
     * {@link RequestParam} 参数校验
     */
    @GetMapping(value = "queryByName")
    public DataResult<User> queryByName(
        @RequestParam("username")
        @NotBlank
        @Size(min = 2, max = 10)
        String name
    ) {
        User user = new User(1L, name, 18);
        return DataResult.ok(user);
    }

    /**
     * {@link PathVariable} 参数校验
     */
    @GetMapping(value = "detail/{id}")
    public DataResult<User> detail(@PathVariable("id") @Min(1L) Long id) {
        User user = new User(id, "李四", 18);
        return DataResult.ok(user);
    }

}

上述类ValidatorController,使用了Spring框架。它是一个RESTful风格的控制器,用于处理HTTP请求。这个类有三个方法:

  • save方法:使用@PostMapping注解,处理POST请求,路径为"validate1/save"。该方法接收一个User类型的参数entity,使用@Valid和@RequestBody注解进行参数校验。如果校验通过,将记录保存到数据库,并返回一个表示成功的DataResult对象。

  • queryByName方法:使用@GetMapping注解,处理GET请求,路径为"validate1/queryByName"。该方法接收一个名为username的请求参数,使用@NotBlank、@Size注解进行参数校验。如果校验通过,根据name查询用户信息,并返回一个包含用户信息的DataResult对象。

  • detail方法:使用@GetMapping注解,处理GET请求,路径为"validate1/detail/{id}"。该方法接收一个名为id的路径变量,使用@Min注解进行参数校验。如果校验通过,根据id查询用户信息,并返回一个包含用户信息的DataResult对象。

🍏(3)抛异常

如果请求参数不满足校验规则,则会抛出ConstraintViolationExceptionMethodArgumentNotValidException异常。

🥝 异常统一处理

在实际项目开发中,通常会用统一异常处理来返回一个更友好的提示。

java 复制代码
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理所有不可知的异常
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(Throwable.class)
    public Result handleException(Throwable e) {
        log.error("未知异常", e);
        return new Result(ResultStatus.HTTP_SERVER_ERROR.getCode(), e.getMessage());
    }

    /**
     * 统一处理请求参数校验异常(普通传参)
     *
     * @param e ConstraintViolationException
     * @return {@link DataResult}
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({ ConstraintViolationException.class })
    public Result handleConstraintViolationException(final ConstraintViolationException e) {
        log.error("ConstraintViolationException", e);
        List<String> errors = new ArrayList<>();
        for (ConstraintViolation<?> violation : e.getConstraintViolations()) {
            Path path = violation.getPropertyPath();
            List<String> pathArr = StrUtil.split(path.toString(), ',');
            errors.add(pathArr.get(0) + " " + violation.getMessage());
        }
        return new Result(ResultStatus.REQUEST_ERROR.getCode(), CollectionUtil.join(errors, ","));
    }

    /**
     * 处理参数校验异常
     *
     * @param e MethodArgumentNotValidException
     * @return {@link DataResult}
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({ MethodArgumentNotValidException.class })
    private Result handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) {
        log.error("MethodArgumentNotValidException", e);
        List<String> errors = new ArrayList<>();
        for (ObjectError error : e.getBindingResult().getAllErrors()) {
            errors.add(((FieldError) error).getField() + " " + error.getDefaultMessage());
        }
        return new Result(ResultStatus.REQUEST_ERROR.getCode(), CollectionUtil.join(errors, ","));
    }

}

上述全局异常处理器类,用于处理控制器中抛出的异常。这个类有三个方法:

  • handleException方法:使用@ResponseBody、@ResponseStatus和@ExceptionHandler注解,处理所有不可知的异常。如果发生异常,记录错误日志,并返回一个表示服务器错误的Result对象。

  • handleConstraintViolationException方法:使用@ResponseBody、@ResponseStatus和@ExceptionHandler注解,统一处理请求参数校验异常(普通传参)。如果发生ConstraintViolationException异常,记录错误日志,将异常信息转换为字符串列表,并返回一个表示请求错误的Result对象。

  • handleMethodArgumentNotValidException方法:使用@ResponseBody、@ResponseStatus和@ExceptionHandler注解,处理参数校验异常。如果发生MethodArgumentNotValidException异常,记录错误日志,将异常信息转换为字符串列表,并返回一个表示请求错误的Result对象。

  如果喜欢的话,欢迎 🤞关注 👍点赞 💬评论 🤝收藏  🙌一起讨论
  你的支持就是我✍️创作的动力!					  💞💞💞
相关推荐
xmh-sxh-13147 分钟前
jdk各个版本介绍
java
XINGTECODE21 分钟前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
天天扭码26 分钟前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶27 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺31 分钟前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序39 分钟前
vue3 封装request请求
java·前端·typescript·vue
凡人的AI工具箱1 小时前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
陈王卜1 小时前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、1 小时前
Spring Boot 注解
java·spring boot
先天牛马圣体1 小时前
如何提升大型AI模型的智能水平
后端