【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对象。

复制代码
  如果喜欢的话,欢迎 🤞关注 👍点赞 💬评论 🤝收藏  🙌一起讨论
  你的支持就是我✍️创作的动力!					  💞💞💞
相关推荐
小码哥_常3 小时前
Spring Boot 牵手Spring AI,玩转DeepSeek大模型
后端
0xDevNull3 小时前
Java反射机制深度解析:从原理到实战
java·开发语言·后端
华洛4 小时前
我用AI做了一个48秒的真人精品漫剧,不难也不贵
前端·javascript·后端
华科易迅4 小时前
MybatisPlus增删改查操作
android·java·数据库
AugustRed4 小时前
基于现有的 Controller 接口 API 暴露 MCP
spring·mcp
WZTTMoon4 小时前
Spring Boot 中Servlet、Filter、Listener 四种注册方式全解析
spring boot·后端·servlet
standovon4 小时前
Spring Boot整合Redisson的两种方式
java·spring boot·后端
Cosolar5 小时前
LlamaIndex RAG 本地部署+API服务,快速搭建一个知识库检索助手
后端·openai·ai编程
IAUTOMOBILE5 小时前
Python 流程控制与函数定义:从调试现场到工程实践
java·前端·python
hutengyi5 小时前
PostgreSQL版本选择
java