Spring Boot中ObjectMapper映射DTO字段缺失空白未抛校验异常如何解决
问题原因
你在DTO字段上添加的@NotNull、@NotBlank属于Bean Validation(JSR-303/JSR-380)规范的校验注解,而Jackson的ObjectMapper默认只负责类型映射,不会自动触发Bean Validation的校验逻辑,因此映射过程不会感知注解约束,自然不会抛出校验错误。
解决方案
可根据业务场景选择以下两种实现方式:
方式1:映射完成后手动触发校验(通用性最强,无额外扩展依赖)
- 首先引入Bean Validation实现依赖,SpringBoot项目直接引入
spring-boot-starter-validation即可,非Spring项目可引入Hibernate Validator:
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.1.Final</version> </dependency>
- 全局构建单例的Validator实例(避免重复创建造成性能浪费),映射完成后主动执行校验,校验不通过直接抛出对应错误:
import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ConstraintViolation; import java.util.Set; import java.util.stream.Collectors; // 全局单例初始化,不要每次映射都新建 private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator(); // 原有映射逻辑保持不变 StudentDto studentDto = mapper.convertValue(jsonObject, StudentDto.class); // 触发参数校验 Set<ConstraintViolation<StudentDto>> validateResult = VALIDATOR.validate(studentDto); if (!validateResult.isEmpty()) { String errMsg = validateResult.stream() .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage()) .collect(Collectors.joining("; ")); // 可替换为项目自定义的参数异常类型 throw new IllegalArgumentException(errMsg); }
方式2:注册校验模块实现映射时自动校验
如果不想每次映射后重复写校验逻辑,可以给ObjectMapper注册Bean Validation扩展模块,让映射流程自动触发校验:
- 引入Jackson的Bean Validation扩展依赖,版本号和项目中使用的Jackson核心版本保持一致:
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-bean-validation</artifactId> <version>2.15.2</version> </dependency>
- 初始化ObjectMapper时注册校验模块,自定义校验失败的处理逻辑:
ObjectMapper mapper = new ObjectMapper(); // 传入前面初始化好的全局Validator实例 BeanValidationModule validationModule = new BeanValidationModule(VALIDATOR); // 配置校验不通过时的处理逻辑 validationModule.setValidationFailureHandler((violations, context) -> { String errMsg = violations.stream() .map(violation -> violation.getPropertyPath() + ": " + violation.getMessage()) .collect(Collectors.joining("; ")); throw new IllegalArgumentException(errMsg); }); mapper.registerModule(validationModule);
配置完成后,原有的mapper.convertValue(jsonObject, StudentDto.class)调用会自动触发校验,不满足约束时直接抛出异常,不需要额外编写校验代码。
注意事项
@NotBlank本身已包含非null校验,无需额外搭配@NotNull,如果需要区分「字段完全缺失(值为null)」和「字段值为空白」两类错误再同时使用,注意调整对应提示文案,避免null场景下重复抛出两个校验错误。- Validator实例是线程安全的,全局维护一个单例即可,不要每次调用映射逻辑时都新建ValidatorFactory,会造成不必要的性能损耗。
- Spring/SpringBoot环境下直接从容器注入
Validator实例即可,无需手动调用Validation.buildDefaultValidatorFactory()构建,框架已经做好了自动配置。
内容的提问来源于stack exchange,提问作者Siddharth Bhatia
相关产品推荐
相关产品推荐

