为什么需要接口参数校验?
在前后端分离、微服务架构下,接口请求往往来自不可信的客户端或第三方系统,因此必须对输入进行严格验证:
❗常见问题包括:
问题 | 描述 |
空值提交 | 导致 NPE 异常 |
非法格式 | 如手机号、邮箱格式错误 |
越界数据 | 如年龄为负数、价格为负等 |
安全loudong | SQL zhuru、XSS gongji等 |
使用 @Valid
可以帮助我们在进入业务逻辑之前就拦截这些非法请求,提升系统健壮性。
🧱 示例目标
我们将构建一个简单的用户注册接口,并实现如下功能:
- 使用
@Valid
对请求体进行字段校验 - 自定义全局异常处理器捕获
MethodArgumentNotValidException
- 返回结构化的错误信息给前端
- 支持多语言国际化提示(可选)
⚙️ 开发环境要求
工具 | 版本建议 |
JDK | Java 8 / 11 / 17 |
IDE | IntelliJ IDEA / VS Code |
构建工具 | Maven |
Spring Boot | 2.6.x / 2.7.x / 3.x |
🛠️ 步骤一:添加依赖(Maven)
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Validation Starter(已包含在 web starter 中,可省略) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
💡 注意:如果你使用的是 spring-boot-starter-web
,则 validation
是默认引入的,无需额外添加。
🧪 步骤二:创建请求 DTO 类
package com.example.demo.dto;
import jakarta.validation.constraints.*;
public class RegisterRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Size(min = 6, max = 20, message = "密码长度应在 6 到 20 个字符之间")
private String password;
@Min(value = 18, message = "年龄必须大于等于 18 岁")
private int age;
// Getter & Setter
}
▶️ 步骤三:编写 Controller 接口并启用校验
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@PostMapping("/register")
public ResponseEntity<String> register(@Valid @RequestBody RegisterRequest request) {
return ResponseEntity.ok("注册成功!");
}
}
🧨 步骤四:统一异常处理(Global Exception Handler)
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}
📊 测试请求示例
请求体:
{
"username": "",
"email": "not-an-email",
"password": "123",
"age": 16
}
返回结果:
{
"username": "用户名不能为空",
"email": "邮箱格式不正确",
"password": "密码长度应在 6 到 20 个字符之间",
"age": "年龄必须大于等于 18 岁"
}