接口参数校验应统一拦截MethodArgumentNotValidException和ConstraintViolationException,结构化返回400响应;使用分组校验(Create/Update)按场景启用规则;封装@ValidMobile等自定义注解提升语义;响应体中文提示、日志记录脱敏上下文,确保准、快、可维护。
接口参数校验失败时,不建议直接抛出原始的 ConstraintViolationException 或让框架默认返回 500 错误页。应统一捕获、结构化响应,并兼顾可读性与调试效率。
用 @ControllerAdvice + @ExceptionHandler 拦截 MethodArgumentNotValidException(用于 @Valid 注解在 DTO 上)和 ConstraintViolationException(用于 @Valid 注解在方法参数上)。
BindingResult,后者需从 Set> 提取字段和消息violation.getPropertyPath().toString())、校验规则(如 @NotBlank)、自定义提示(violation.getMessage()){"code": 400, "message": "参数校验失败", "details": [{"field": "email", "reason": "邮箱格式不正确"}]}
避免一个 DTO 承担所有接口的校验逻辑。通过校验分组(interface 标记)按业务场景启用不同规则。
public interface Create {} 和 public interface Update {}
@Validated(Create.class) @RequestBody UserDTO dto
@NotBlank(groups = Create.class)、@NotNull(groups = Update.class)
对业务强相关的规则(如“手机号必须是 11 位且以 1 开头”),不要堆砌多个基础注解,而是封装为可复用的自定义注解。
@ValidMobile 注解,配合 ConstraintValidator 实现message = "手机号 {value} 不合法",并在校验器中传入上下文值异常响应要对前端友好,但后端日志需保留完整上下文,方便排查。
reason 字段用中文、简洁明确(如“用户名不能为空”),不暴露技术细节
基本上就这些。校验不是越严越好,而是要准、要快、要可维护。把规则收口、分层、可配置,比堆 @NotNull 更重要。