Springboot使用@Valid注解,对其参数错误异常的统一处理

       在我们使用springboot作为微服务框架进行敏捷开发的时候,为了保证传递数据的安全性,需要对传递的数据进行校验,但是在以往的开发中,开发人员花费大量的时间在繁琐的if else 等判断语句来对参数进行校验,这种方式不但降低了我们的开发速度,而且写出来的代码中带有很多冗余代码,使得编写的代码不够优雅,为了将参数的验证逻辑和代码的业务逻辑进行解耦,Java给我们提供了@Valid注解,用来帮助我们进行参数的校验,实现了将业务逻辑和参数校验逻辑在一定程度上的解耦,增加了代码的简洁性和可读性。springboot中自带了spring validation参数校验框架,其使用上和@valid差不多,在这里就不累述了,本文主要讲解@valid的使用对其参数校验失败后的错误一样的统一处理。

       首先,简介对微服务开发中异常的统一处理,spring中的@RestControllerAdvice注解可以获取带有@controller注解类的异常,通过@ExceptionHandler(MyException.class)注解来共同完成对异常进行处理。示例如下:

/**
 * 通用异常拦截处理类(通过切面的方式默认拦截所有的controller异常)
 */
@Slf4j
@RestControllerAdvice
public class CommonExceptionHandler {

    /**
     * 对运行时异常进行统一异常管理方法
     * @param e
     * @return
     */
    @ExceptionHandler(FlyException.class) // FlyException类继承于RuntimeException
    public ResponseEntity<Map<String, Object>> handlerException(FlyException e) {
        Map<String, Object> result = new HashMap<>(1);
        result.put("message", e.getMessage());
        return ResponseEntity.status(e.getCode()).body(result);
    }

通过注解@RestControllerAdvice和注解@ExceptionHandler的联合使用来实现对异常的统一处理,然后在前端以友好的方式显示。

使用@Valid注解的示例如下:

  @PostMapping
    public ResponseEntity save(@Valid BrandCreateRequestDto dto, BindingResult bindingResult) {
        // 判断是否含有校验不匹配的参数错误
        if (bindingResult.hasErrors()) {
            // 获取所有字段参数不匹配的参数集合
            List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
            Map<String, Object> result = new HashMap<>(fieldErrorList.size());
            fieldErrorList.forEach(error -> {
                // 将错误参数名称和参数错误原因存于map集合中
                result.put(error.getField(), error.getDefaultMessage());
            });
            return ResponseEntity.status(HttpStatus.BAD_REQUEST.value()).body(result);
        }

        brandService.save(dto);
        return ResponseEntity.status(HttpStatus.CREATED.value()).build();
    }

@Valid注解确实将我们原来的参数校验的问题进行了简化,但是,如果我们有多个handler需要处理,那我们岂不是每次都要写这样的冗余代码。通过查看@valid的实现机制(这里就不描述了),当参数校验失败的时候,会抛出MethodArgumentNotValidException异常(当用{@code @Valid}注释的参数在验证失败时,将引发该异常):

/**
 * Exception to be thrown when validation on an argument annotated w
<think>首先,用户的问题是关于SpringBoot中@JsonFormat和@Valid注解的交互:他们想知道@JsonFormat注解是否会因为@Valid注解而被触发,用于验证数据格式。回顾系统指令:-所有行内数学表达式必须使用$...$格式,但这里没有数学内容,所以可能不适用。-独立公式使用$$...$$,但同样不适用。-LaTeX语法正确:确保任何技术术语或代码正确格式化。-使用中文回答。-生成相关问题:在回答后添加相关问题。-回答中引用的段落末尾自然地添加引用标识,如[^1]。用户可见层:-回答结构清晰,帮助用户逐步解决问题。-尽量保证回答真实可靠。参考站内引用:-引用[1]:关于SpringBoot的默认异常处理,当@Valid与@RequestBody结合使用时,触发MethodArgumentNotValidException。-引用[2]:使用@Sign注解的示例。-引用[3]:关于日志依赖的配置。-引用[4]:@Autowired注解使用。这些引用中,引用[1]最相关,因为它涉及@Valid注解校验行为。引用[2][3][4]似乎不直接相关。核心问题:-@JsonFormat注解:用于序列化和反序列化JSON数据时指定日期格式。-@Valid注解:用于触发BeanValidation(如HibernateValidator),执行数据校验。交互:-@JsonFormat主要是Jackson库的一部分,用于JSON处理,而@Valid是用于验证的。-在SpringBoot中,当使用@RequestBody和@Valid时,Spring会先反序列化JSON到对象,然后执行验证。-@JsonFormat在反序列化过程中被Jackson处理,以解析日期字段。-验证(@Valid)发生在反序列化之后:先Jackson处理JSON(包括@JsonFormat),然后如果字段有约束注解(如@NotNull,@Pattern),@Valid会触发校验。所以,回答:-@JsonFormat本身不触发校验逻辑;它只影响数据格式的解析。-@Valid会触发校验,但校验逻辑依赖于其他约束注解。-如果@JsonFormat用于日期字段,但没有约束注解@Valid不会校验格式;它只校验显式的约束。-如果字段有约束如@NotNull或@Past,@Valid校验这些,但格式解析是Jackson的责任。逐步回答:1.解释@JsonFormat的作用:指定日期格式,在JSON序列化/反序列化中使用。2.解释@Valid的作用:触发BeanValidation。3.描述交互:在SpringMVC中,当请求体被反序列化时,Jackson先处理@JsonFormat;然后@Valid触发验证。4.结论:@JsonFormat不会直接被@Valid触发校验校验只针对验证注解。确保回答真实可靠:基于SpringBoot文档和常见实践。生成相关问题:-例如:1.如何在SpringBoot中自定义日期格式的反序列化?2.@Valid注解可以组合使用哪些其他校验注解?3.如何处理日期格式校验失败时的异常?引用标识:在回答中,如果引用站内内容,添加引用标识。用户提供的引用[1]中提到@Valid触发异常,可以自然地引用。回答结构:-先简要解释两个注解。-然后讨论交互。-最后结论。-添加相关问题。</think>### Spring Boot 中 @JsonFormat 注解@Valid 注解的交互分析 在 Spring Boot 应用中,`@JsonFormat` 和 `@Valid` 注解的作用域和触发机制不同,它们的交互主要体现在数据处理流程中。下面我将逐步解释两者的行为及其交互逻辑,确保回答基于 Spring Boot 的官方文档和常见实践。 #### 1. **注解的基本作用** - **`@JsonFormat` 注解**: - 属于 Jackson 库(Spring Boot 默认的 JSON 处理器),用于控制字段的序列化(Serialization)和反序列化(Deserialization)格式,例如日期、时间或数字格式。 - 示例:指定日期字段的格式,如 `@JsonFormat(pattern = "yyyy-MM-dd")`。**它本身不触发任何校验逻辑**,仅负责数据格式的转换。 - 在反序列化过程中(如处理 HTTP 请求的 JSON 数据时),Jackson 会优先使用注解解析字段值。如果格式不匹配(如日期字符串不符合 `pattern`),Jackson 会抛出 `JsonParseException` 或类似异常,但这属于解析错误,而非验证错误。 - **`@Valid` 注解**: - 属于 Bean Validation 规范(如 Hibernate Validator),用于触发对象属性的校验逻辑。 - 需结合其他约束注解(如 `@NotNull`、`@Size` 或 `@Pattern`)使用。例如,在控制器方法中标注 `@RequestBody @Valid` 时,Spring Boot 会在反序列化后自动执行校验。 - 如果校验失败,会抛出 `MethodArgumentNotValidException`,Spring Boot 的默认异常处理机制会生成包含错误详情的响应[^1]。 #### 2. **交互机制:是否触发校验逻辑?** - **`@JsonFormat` 不会因 `@Valid` 被直接触发进行校验**: - 数据处理流程分为两步: 1. **反序列化阶段**:Jackson 处理 JSON 数据,应用 `@JsonFormat` 进行格式转换。例如,将字符串解析为 `Date` 对象。如果格式错误(如日期字符串无效),此阶段会失败,抛出 Jackson 异常。 2. **校验阶段**:仅在反序列化成功后,`@Valid` 触发 Bean Validation。此阶段只检查字段值是否符合约束注解(如 `@NotNull`),但 **`@JsonFormat` 本身不是约束注解,因此不会被 `@Valid` 视为校验目标**。 - 示例场景: - 若字段仅标注 `@JsonFormat` 无约束注解:即使格式错误,`@Valid` 也不会校验或报告该错误,因为校验逻辑未定义。 - 若字段同时标注 `@JsonFormat` 和约束注解(如 `@Past` 用于日期校验):`@Valid` 会校验约束(如日期是否在过去),但格式解析仍由 Jackson 独立处理。 - **关键结论**: - `@JsonFormat` 负责**数据格式解析**,属于反序列化过程。 - `@Valid` 负责**业务规则校验**,属于后置验证过程。 - 两者无直接交互:`@JsonFormat` 不会增强 `@Valid` 的校验能力。格式错误在反序列化阶段处理校验错误在验证阶段处理[^1]。 #### 3. **如何实现日期格式的校验?** - 如果需要验证日期格式,应结合约束注解而非依赖 `@JsonFormat`: - 使用 `@Pattern` 注解:适用于字符串字段,通过正则表达式验证格式。 ```java @Pattern(regexp = "\\d{4}-\\d{2}-\\d{2}", message = "日期格式必须为 yyyy-MM-dd") private String dateString; ``` - 使用 `@DateTimeFormat` + `@Past`/`@Future`:适用于日期类型字段,但需注意 `@DateTimeFormat` 是 Spring 特有注解,用于绑定请求参数,而非 JSON 处理。 - 最佳实践:在 DTO 类中同时使用 `@JsonFormat`(确保解析正确)和约束注解(触发 `@Valid` 校验)。 ```java public class UserDTO { @JsonFormat(pattern = "yyyy-MM-dd") @Past(message = "日期必须在过去") // @Valid校验此约束 private Date birthDate; } ``` #### 4. **异常处理** - **格式错误**:由 Jackson 抛出,如 `JsonParseException`,可通过 `@ControllerAdvice` 自定义异常处理。 - **校验错误**:由 `@Valid` 触发 `MethodArgumentNotValidException`,Spring Boot 默认返回包含错误列表的响应体[^1]。 - 建议统一处理:在全局异常处理器中捕获两类异常,提供一致的用户体验。 ### 总结 - **`@JsonFormat` 注解不会因为 `@Valid` 被触发执行校验逻辑**。它仅在反序列化阶段处理数据格式,而校验由 `@Valid` 和约束注解独立完成。 - 要验证数据格式,需显式添加 Bean Validation 约束注解。两者协同工作可提升数据完整性和错误处理能力[^1]。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值