POST 请求大多接收 JSON / Form / Multipart 表单数据,数据验证核心目标:拦截非法输入、保证业务合法性、返回友好错误、避免后续逻辑报错。下面从通用思路、分层校验、Java (SpringBoot) 示例、常见坑、错误响应规范完整说明。
一、POST 常见数据来源
application/json:请求体 JSON(最常用)application/x‑www‑form‑urlencoded:表单编码multipart/form‑data:文件上传 + 表单字段
注意:SpringBoot 中
@RequestBody读取 JSON;@ModelAttribute/@RequestParam读取表单;文件用@RequestPart。
二、验证分层思想(重要)
❌ 不要全部写在 Controller 的 if‑else,维护灾难。
原则:格式校验放 DTO,业务校验放 Service,数据库做兜底防护。
三、SpringBoot 完整实战(Java17 + SpringBoot3)
1. 引入依赖
SpringBoot3 使用 jakarta.validation
xml
<!-- validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2. 定义 POST 请求 DTO,加上校验注解
java
运行
import jakarta.validation.constraints.*;
import lombok.Data;
@Data
public class UserCreateDTO {
// 不为null,字符串不能全空格
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 20, message = "用户名长度2‑20位")
private String username;
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误")
private String phone;
@NotNull(message = "年龄不能为空")
@Min(value = 1, message = "年龄不能小于1")
@Max(value = 150, message = "年龄不能大于150")
private Integer age;
@Email(message = "邮箱格式不正确")
private String email;
}
常用注解:
@NotNull:不能为 null(允许空字符串)
@NotBlank:字符串不能 null、不能空白串
@NotEmpty:集合 / 字符串不能 null 且长度 > 0
@Size:字符串、集合长度
@Min/@Max:数字大小
@Pattern:自定义正则
3.Controller 开启校验:@Valid
java
运行
import jakarta.validation.Valid;
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping("/create")
public R<?> createUser(@Valid @RequestBody UserCreateDTO dto){
// @Valid 触发DTO校验,校验失败抛出 MethodArgumentNotValidException
userService.create(dto);
return R.success();
}
}
区别:
@Valid:jakarta,触发嵌套对象校验;
@Validated:spring,支持分组校验,可写在类上。
4. 全局异常处理器统一捕获校验异常
不要把原生异常堆栈抛给前端,统一返回标准错误 JSON。
java
运行
@RestControllerAdvice
public class GlobalExceptionHandler {
// JSON请求体校验失败
@ExceptionHandler(MethodArgumentNotValidException.class)
public R<?> handleValidException(MethodArgumentNotValidException e){
Map<String,String> errMap = new HashMap<>();
e.getBindingResult().getFieldErrors().forEach(err->{
errMap.put(err.getField(), err.getDefaultMessage());
});
return R.fail(400, "参数校验失败", errMap);
}
// Form表单校验异常
@ExceptionHandler(BindException.class)
public R<?> handleBindException(BindException e){
Map<String,String> errMap = new HashMap<>();
e.getBindingResult().getFieldErrors().forEach(err->{
errMap.put(err.getField(), err.getDefaultMessage());
});
return R.fail(400, "表单参数错误", errMap);
}
}
返回示例:
json
{
"code":400,
"msg":"参数校验失败",
"data":{
"username":"用户名不能为空",
"phone":"手机号格式错误"
}
}
5. 分组校验(场景:新增 / 更新复用同一个 DTO)
同一个 DTO,新增 id 不能为空;更新 id 必须不为空。
java
运行
// 分组标记接口
public interface Create {}
public interface Update {}
@Data
public class UserDTO{
@Null(groups = Create.class, message = "新增时不能传id")
@NotNull(groups = Update.class, message = "更新必须传入id")
private Long id;
@NotBlank(groups = {Create.class, Update.class}, message = "用户名不能为空")
private String username;
}
Controller 使用@Validated指定分组:
java
运行
@PostMapping("/add")
public R<?> add(@Validated(Create.class) @RequestBody UserDTO dto){...}
@PostMapping("/update")
public R<?> update(@Validated(Update.class) @RequestBody UserDTO dto){...}
6. 自定义校验注解(复杂业务格式,比如身份证)
实现ConstraintValidator,自定义注解,适合通用格式规则。
7.Service 层业务校验
Bean Validation 只做格式;业务逻辑校验写在 Service。
java
运行
@Service
public class UserService {
public void create(UserCreateDTO dto){
// 业务校验:手机号是否已注册
if(userMapper.existsByPhone(dto.getPhone())){
throw new BusinessException(400,"该手机号已注册");
}
// 其他业务规则……
}
}
四、Multipart/form‑data 文件上传 POST 校验
文件大小、格式校验:
application.yml 配置全局文件限制
yaml
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MB
DTO 搭配
@Validated校验文件对象,判断文件后缀、mime 类型。
五、通用 API 校验规范(所有语言通用)
HTTP 状态码
参数非法:
400 Bad Request,不要返回 200;认证失败:401;无权限 403;
返回格式:把字段名 + 错误信息返回,前端可以直接对应表单提示;
拒绝超大输入:限制字符串最大长度,防止大 JSON 攻击;
防止空对象:POST 请求体不能为 null,
@RequestBody(required=true);数值校验:防止负数、超大数字,避免数据库溢出;
集合校验:校验集合内每一项(开启嵌套校验,字段上加
@Valid)
嵌套示例:
java
运行
@Data
public class OrderDTO{
@NotEmpty(message="订单明细不能为空")
@Valid // 触发集合内部每一个ItemDTO校验
private List<OrderItemDTO> itemList;
}
六、常见踩坑点
❌
@NotNull用于字符串,空字符串""会放行,应该用@NotBlank;❌ 忘记写
@Valid / @Validated,注解完全不生效;❌ DTO 内部集合对象,不加
@Valid,集合内部字段校验失效;❌ 业务校验写在 Controller,代码臃肿,无法复用;
❌ 直接返回原生校验异常栈给前端,泄露内部信息;
❌ 只做应用层校验,数据库不加非空、唯一索引,并发场景产生脏数据。
七、其他语言简单参考
Node.js(Express):
joi/zod;Python(Django/FastAPI):Pydantic;
Go:go‑playground/validator。
核心思想一致:入参先校验,再执行业务;格式校验用框架,业务校验手写,全局统一错误输出。
本文原创作者:易君召,详见:https://www.yijunzhao.cn/authors/yijunzhao,转载请注明出处。
原文链接
欢迎访问 小易撩挨踢