悠悠楠杉
SpringBoot接口参数校验的完整指南:从基础到实战
一、为什么需要参数校验?
在Web开发中,客户端传入的参数永远不可信任。我曾经遇到过一个线上事故:由于没有对用户ID做数字类型校验,攻击者传入"1 OR 1=1"
导致数据库被拖库。参数校验不仅是业务需求,更是安全防线。
Spring Boot通过javax.validation
规范和Hibernate Validator实现提供了优雅的校验方案,比手动if-else判断更规范、更高效。
二、基础校验注解实战
2.1 常用内置注解
java
public class UserDTO {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式错误")
private String email;
@Min(value = 18, message = "年龄必须大于18岁")
private Integer age;
@Pattern(regexp = "1[3-9]\\d{9}", message = "手机号格式错误")
private String phone;
}
2.2 校验生效的三大条件
- DTO类添加
@Validated
或@Valid
注解 - Controller方法参数前加
@RequestBody
- 依赖spring-boot-starter-validation
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
三、高级校验技巧
3.1 嵌套对象校验
java
public class OrderDTO {
@Valid // 关键注解
private UserDTO user;
@NotEmpty
private List<@Valid Product> products;
}
3.2 分组校验(多场景验证)
java
public class UserDTO {
interface Create {}
interface Update {}
@Null(groups = Create.class)
@NotNull(groups = Update.class)
private Long id;
}
// 使用方式
@PostMapping
public Result create(@Validated(UserDTO.Create.class) @RequestBody UserDTO dto)
四、自定义校验器开发
4.1 实现密码强度校验
java
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)
public @interface StrongPassword {
String message() default "密码强度不足";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class PasswordValidator implements ConstraintValidator<StrongPassword, String> {
@Override
public boolean isValid(String password, ConstraintValidatorContext context) {
return password.matches("^(?=.[A-Z])(?=.[a-z])(?=.*\d).{8,}$");
}
}
五、全局异常处理最佳实践
5.1 统一返回格式
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleValidException(MethodArgumentNotValidException e) {
return Result.fail(
e.getBindingResult()
.getFieldErrors()
.stream()
.collect(Collectors.toMap(
FieldError::getField,
FieldError::getDefaultMessage
))
);
}
}
5.2 处理国际化消息
在resources目录下创建ValidationMessages.properties
:
user.name.notblank=用户名不能为空
email.invalid=请输入有效的邮箱地址
六、性能优化建议
- 对于List校验,优先在Controller层做size校验
- 复杂校验逻辑考虑使用Spring EL表达式
- 高频接口建议采用JSR-303的快速失败模式:
properties spring.mvc.validator.fail-fast=true
结语
参数校验是API开发的第一道防火墙。通过本文介绍的技术组合,开发者可以构建出:
- 支持多场景的校验规则
- 具备友好提示的异常处理
- 可扩展的自定义验证体系
真正的工程化校验方案应该像洋葱一样分层:基础校验在DTO层完成,业务校验在Service层处理,最终在Controller层统一拦截异常。这种分层防御策略,才是构建健壮API的核心要义。