Spring Boot使用约束注解时如何返回自定义HTTP错误响应给前端
Spring Boot 统一异常返回解决方案
你当前使用的@Pattern、@Size等Bean Validation校验注解是Spring生态下参数校验的标准实现,完全可以满足常规校验需求,无需额外替换方案。以下是实现统一错误返回的具体步骤:
1. 约定统一返回结构
首先约定所有错误的返回格式,示例如下:
{ "code": "PASSWORD_WHITESPACE_ERROR", "message": "Password should not contain whitespaces", "status": 400 }
code:对应你需要的专属错误ID,前端可根据该值做国际化或自定义提示message:面向用户的错误提示文本status:HTTP状态码,统一使用4xx系列
2. 配置校验规则的错误标识
给每个校验注解的message配置为错误ID:错误提示的格式,方便后续解析;同时给数据库唯一键指定约束名,方便后续判断冲突字段:
@Column(name = "password") @Pattern(regexp = "[^\\s]*", message = "PASSWORD_WHITESPACE_ERROR:Password should not contain whitespaces") @Size(min = 8, max = 16, message = "PASSWORD_LENGTH_ERROR:Password should be between 8 and 16 characters") private String userPassword; @Column(name = "email", unique = true, columnDefinition = "VARCHAR(255) CONSTRAINT uk_user_email UNIQUE") @Email(message = "EMAIL_FORMAT_ERROR:Please input a valid email address") private String userEmail;
3. 实现全局异常处理器
Spring Boot 提供@RestControllerAdvice注解实现全局异常拦截,统一处理所有异常并返回规范结构:
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.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.sql.SQLIntegrityConstraintViolationException; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class GlobalExceptionHandler { // 处理@Pattern、@Size等参数校验触发的异常 @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, Object>> handleValidationException(MethodArgumentNotValidException e) { Map<String, Object> resp = new HashMap<>(); // 取第一个错误返回,也可以遍历所有错误返回错误列表 FieldError firstError = e.getBindingResult().getFieldError(); if (firstError != null) { String msg = firstError.getDefaultMessage(); if (msg.contains(":")) { String[] msgParts = msg.split(":", 2); resp.put("code", msgParts[0]); resp.put("message", msgParts[1]); } else { resp.put("code", "INVALID_PARAM"); resp.put("message", msg); } } resp.put("status", HttpStatus.BAD_REQUEST.value()); return new ResponseEntity<>(resp, HttpStatus.BAD_REQUEST); } // 处理数据库唯一键冲突异常(比如邮箱重复注册) @ExceptionHandler(SQLIntegrityConstraintViolationException.class) public ResponseEntity<Map<String, Object>> handleUniqueConstraintException(SQLIntegrityConstraintViolationException e) { Map<String, Object> resp = new HashMap<>(); if (e.getMessage().contains("uk_user_email")) { resp.put("code", "EMAIL_ALREADY_REGISTERED"); resp.put("message", "该邮箱已被注册"); resp.put("status", HttpStatus.CONFLICT.value()); return new ResponseEntity<>(resp, HttpStatus.CONFLICT); } resp.put("code", "DUPLICATE_RESOURCE"); resp.put("message", "资源已存在"); resp.put("status", HttpStatus.CONFLICT.value()); return new ResponseEntity<>(resp, HttpStatus.CONFLICT); } // 处理自定义业务异常 @ExceptionHandler(BusinessException.class) public ResponseEntity<Map<String, Object>> handleBusinessException(BusinessException e) { Map<String, Object> resp = new HashMap<>(); resp.put("code", e.getCode()); resp.put("message", e.getMessage()); resp.put("status", e.getStatus()); return new ResponseEntity<>(resp, HttpStatus.valueOf(e.getStatus())); } }
4. 自定义业务异常类(可选)
如果需要在业务代码中手动抛出异常,可自定义业务异常类:
public class BusinessException extends RuntimeException{ private final String code; private final int status; public BusinessException(String code, String message, int status) { super(message); this.code = code; this.status = status; } public String getCode() { return code; } public int getStatus() { return status; } }
业务代码中使用示例:
if (user == null) { throw new BusinessException("USER_NOT_FOUND", "用户不存在", 404); }
5. 注意事项
- Controller层接收参数时需要添加
@Valid注解才会触发参数校验,示例:@PostMapping("/register") public ResponseEntity<?> register(@RequestBody @Valid User user) { // 业务逻辑 } - 如果需要返回多个参数校验错误,可遍历
e.getBindingResult().getAllErrors()收集所有错误信息后返回。
内容的提问来源于stack exchange,提问作者stathis94
相关产品推荐
相关产品推荐

