Spring Boot中REST服务校验实现及通用@ControllerAdvice错误处理
Spring Boot实现REST服务校验的通用@ControllerAdvice处理方案
我来帮你搞定这个全局校验异常处理的需求,完全贴合你的返回格式要求,一步步来:
第一步:确保基础配置就绪
- 如果你用的是Spring Boot 2.3及以上版本,得单独引入校验模块依赖(因为这版本把校验组件从web starter里拆分出来了),Maven的话在pom.xml里加:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
- 然后在你的REST接口里,给DTO参数加上
@Valid注解,这样Spring才会触发校验逻辑:
@PostMapping("/users") public ResponseEntity<UserDTO> createUser(@Valid @RequestBody UserDTO userDTO) { // 这里写你的业务逻辑 return ResponseEntity.ok(userDTO); }
第二步:实现全局异常处理类
用@ControllerAdvice创建全局异常处理器,专门捕获校验失败抛出的MethodArgumentNotValidException,把错误转换成你要的格式:
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @ControllerAdvice public class GlobalValidationExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<List<Map<String, String>>> handleValidationErrors(MethodArgumentNotValidException ex) { // 把所有校验错误转换成[{field: message}]的格式 List<Map<String, String>> errorList = ex.getBindingResult() .getAllErrors() .stream() .map(error -> { String fieldName = ((FieldError) error).getField(); String errorMsg = getCustomMessage(error.getCode(), fieldName); return Map.of(fieldName, errorMsg); }) .collect(Collectors.toList()); // 返回422状态码和错误列表 return new ResponseEntity<>(errorList, HttpStatus.UNPROCESSABLE_ENTITY); } // 自定义错误消息,也可以用配置文件管理(后面会说) private String getCustomMessage(String errorCode, String field) { return switch (errorCode) { case "Email" -> "it's not a valid mail"; case "NotEmpty" -> "required field"; // 如果phone传了但长度不符合@Size要求,也可以单独处理 case "Size" -> field.equals("phone") ? "required field" : "invalid length"; default -> errorCode; }; } }
更优雅的消息管理方式(可选)
如果不想在代码里硬编码消息,也可以用ValidationMessages.properties配置文件来统一管理,放在src/main/resources目录下:
# 对应@NotEmpty注解的提示语 javax.validation.constraints.NotEmpty.message=required field # 对应@Email注解的提示语 javax.validation.constraints.Email.message=it's not a valid mail # 对应phone的@Size注解提示语(因为要求固定11位,没传时其实先触发NotEmpty,传错长度时用这个) javax.validation.constraints.Size.message=required field
这时候上面的getCustomMessage方法就可以删掉,直接用error.getDefaultMessage()即可:
.map(error -> { String fieldName = ((FieldError) error).getField(); String errorMsg = error.getDefaultMessage(); return Map.of(fieldName, errorMsg); })
测试效果
当你发送请求:
{ "name": "John Lennon", "email": "jonnlennon" }
系统会触发两个校验错误:
- email不符合@Email规则,返回
"it's not a valid mail" - phone未传,触发@NotEmpty规则,返回
"required field"
最终返回的响应完全符合你的要求:
[{ "email": "it's not a valid mail" }, { "phone": "required field" }]
状态码为422(UNPROCESSABLE_ENTITY)。
内容的提问来源于stack exchange,提问作者Luciano Borges
相关产品推荐
相关产品推荐

