2026/4/18 18:17:03
网站建设
项目流程
厦门网站建设满山红,得到app怎么样,重庆工信部网站,网络营销有什么新的变化视频看了几百小时还迷糊#xff1f;关注我#xff0c;几分钟让你秒懂#xff01;在上一篇中#xff0c;我们讲了 全局异常处理#xff0c;解决了“出错后怎么统一返回”的问题。
但你有没有想过#xff1a;在请求刚进来时#xff0c;就拦截非法参数#xff0c;不让脏数…视频看了几百小时还迷糊关注我几分钟让你秒懂在上一篇中我们讲了全局异常处理解决了“出错后怎么统一返回”的问题。但你有没有想过在请求刚进来时就拦截非法参数不让脏数据进入业务层这就是今天要讲的核心内容——Spring Boot 中的参数校验Bean Validation 全局异常处理。一、需求场景你正在开发一个用户注册接口POST /api/user/register Content-Type: application/json { username: zhangsan, email: invalid-email, age: -5 }业务规则要求username必填长度 2~20email必须是合法邮箱格式age必须 ≥ 18。如果前端传了非法数据不能等业务逻辑执行到一半才发现错误而应该在入口处直接拒绝二、解决方案使用 JSR-303 / Bean Validation Valid✅ 正确做法推荐1. 引入依赖Spring Boot 默认已包含!-- Spring Boot Web 已默认引入 spring-boot-starter-validation -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-validation/artifactId /dependency如果你用的是 Spring Boot 2.3需要显式添加该依赖因为从 2.3 开始 validation 不再默认包含。2. 定义 DTO 并添加校验注解// UserRegisterDTO.java import javax.validation.constraints.*; public class UserRegisterDTO { NotBlank(message 用户名不能为空) Size(min 2, max 20, message 用户名长度必须在2~20之间) private String username; Email(message 邮箱格式不正确) private String email; Min(value 18, message 年龄必须大于等于18岁) private Integer age; // Getter / Setter }3. Controller 中使用 ValidPostMapping(/register) public CommonResultString register(Valid RequestBody UserRegisterDTO dto) { // 如果走到这里说明参数合法 userService.register(dto); return CommonResult.success(注册成功); }⚠️ 注意必须加上Valid或Validated否则校验不会生效4. 全局捕获校验异常配合上一篇的异常处理器// 在 GlobalExceptionHandler.java 中新增 ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntityCommonResultVoid handleValidationException(MethodArgumentNotValidException ex) { // 获取第一个错误信息也可拼接所有 String errorMsg ex.getBindingResult() .getFieldError() .getDefaultMessage(); return ResponseEntity.status(HttpStatus.BAD_REQUEST) .body(CommonResult.error(400, errorMsg)); } 进阶如果想返回所有错误字段可以遍历getFieldErrors()拼成 Map。三、反例千万别这么写❌ 反例1手动 if 判断每个字段PostMapping(/register) public ResponseEntity? registerBad(RequestBody UserRegisterDTO dto) { if (dto.getUsername() null || dto.getUsername().trim().isEmpty()) { return ResponseEntity.badRequest().body(用户名不能为空); } if (dto.getUsername().length() 2 || dto.getUsername().length() 20) { return ResponseEntity.badRequest().body(用户名长度不对); } if (!dto.getEmail().contains()) { return ResponseEntity.badRequest().body(邮箱格式错误); } // ...更多 if }问题代码臃肿可读性差无法复用换个接口又要重写容易漏判维护成本高。❌ 反例2加了 Valid 但没处理异常PostMapping(/register) public String register(Valid RequestBody UserRegisterDTO dto) { return ok; }后果当参数非法时Spring 会抛出MethodArgumentNotValidException但如果没有全局处理默认返回 400 HTML 错误页在 REST API 中完全不可接受。四、注意事项面试高频考点Valid 和 Validated 的区别ValidJSR-303 原生注解支持嵌套校验ValidatedSpring 扩展支持分组校验如注册 vs 修改密码用不同规则。分组校验示例加分项public interface RegisterGroup {} public interface UpdateGroup {} public class UserDTO { NotBlank(groups RegisterGroup.class) private String username; Email(groups {RegisterGroup.class, UpdateGroup.class}) private String email; } // Controller public void update(Validated(UpdateGroup.class) RequestBody UserDTO dto) { ... }自定义校验注解体现深度比如校验手机号Target({ElementType.FIELD}) Retention(RetentionPolicy.RUNTIME) Constraint(validatedBy PhoneValidator.class) public interface Phone { String message() default 手机号格式不正确; Class?[] groups() default {}; Class? extends Payload[] payload() default {}; } public class PhoneValidator implements ConstraintValidatorPhone, String { Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value null) return true; // 非空由 NotBlank 控制 return value.matches(^1[3-9]\\d{9}$); } }路径变量/请求参数校验用 ValidatedRestController Validated // 必须加在类上 public class UserController { GetMapping(/user/{id}) public User getUser(Min(1) PathVariable Long id) { return userService.getById(id); } }注意对PathVariable、RequestParam校验必须用Validated注解在类级别。五、总结能力价值✅ 自动拦截非法请求提升系统健壮性✅ 减少 if 判断代码更简洁✅ 校验规则集中管理易于维护和测试✅ 与 Swagger 集成自动生成文档约束掌握参数校验是你从“能跑就行”迈向“专业工程”的关键一步视频看了几百小时还迷糊关注我几分钟让你秒懂