Spring中函数返回对象前的@Valid校验失效问题求助
问题分析与解决方案
问题根源
- Jackson反序列化不自动触发Bean Validation:你在
ReadXML.read方法和局部变量上添加的@Valid注解完全无效——Jackson的XmlMapper/ObjectMapper仅负责将XML/JSON字符串转成POJO,不会主动触发JSR-380(Bean Validation)的校验逻辑,@Valid仅在Spring MVC参数绑定、或手动调用校验器时才会生效。 - /read接口无校验逻辑:反序列化得到
Book对象后,你直接将其放入Model返回页面,没有执行任何校验,导致无效数据被正常接收展示。
解决方案
1. 确保Bean Validation依赖存在
如果项目是Spring Boot,确认pom.xml中已引入校验依赖:
<!-- Maven --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
2. 手动调用校验器校验反序列化对象
在ReadXML和ReadJSON服务中注入Validator,反序列化完成后手动校验对象:
修改ReadXML类:
import javax.validation.ConstraintViolationException; import javax.validation.Validator; import org.springframework.beans.factory.annotation.Autowired; import com.fasterxml.jackson.databind.JsonProcessingException; import com.fasterxml.jackson.dataformat.xml.XmlMapper; public class ReadXML { @Autowired @Qualifier("XmlMapper") XmlMapper xmlMapper; @Autowired private Validator validator; public Book read(String xml) { try { Book book = xmlMapper.readValue(xml, Book.class); // 执行校验 var violations = validator.validate(book); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); } return book; } catch (JsonProcessingException e) { e.printStackTrace(); return new Book(); } catch (ConstraintViolationException e) { // 可根据业务需求处理,比如抛出自定义异常或返回空对象 e.printStackTrace(); return new Book(); } } }
ReadJSON类做相同修改即可。
3. 在Controller中处理校验异常
修改/read接口,捕获校验异常并返回表单页面展示错误:
@PostMapping("/read") public String read(@RequestParam(value = "convertFrom") String convertFrom, String text, Model model){ try { Book newBook; if("json".equals(convertFrom)){ newBook = readJSON.read(text); } else if("xml".equals(convertFrom)){ newBook = readXML.read(text); } else { return "read"; } model.addAttribute("result", newBook); return "converted"; } catch (ConstraintViolationException e) { // 将错误信息传入页面,在Thymeleaf中展示 model.addAttribute("errors", e.getConstraintViolations()); return "read"; } }
4. (可选)全局统一处理校验异常
用@ControllerAdvice全局捕获ConstraintViolationException,避免重复代码:
import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.ModelAndView; import javax.validation.ConstraintViolationException; @ControllerAdvice public class ValidationExceptionHandler { @ExceptionHandler(ConstraintViolationException.class) public ModelAndView handleValidationError(ConstraintViolationException e) { ModelAndView mav = new ModelAndView("read"); mav.addObject("errors", e.getConstraintViolations()); return mav; } }
补充说明
- 你在
/print接口中使用的@Valid Book book, Errors errors是有效的,因为这是Spring MVC参数绑定场景,框架会自动触发校验并将错误存入Errors对象;但/read是手动反序列化,必须手动调用校验器。 - 确认
Book类中的@NotEmpty注解导入的是javax.validation.constraints.NotEmpty(或Jakarta版本对应类),导错包也会导致校验失效。
内容的提问来源于stack exchange,提问作者xX Ultimejta Xx
相关产品推荐
相关产品推荐

