JSR303数据校验指南
一、常用校验注解
注解 | 说明 | 适用场景 |
---|---|---|
@Null | 必须为 null | 新增时 ID 自增字段(需为 null ) |
@NotNull | 不能为 null | 基本数据类型(如 Integer 、Long )的非空校验 |
@NotBlank | 至少有一个非空字符且不含空格 | String 类型参数(如品牌名) |
@NotEmpty | 不能为空或 null | 集合、数组、对象等 |
@URL | 必须为合法 URL | URL 地址字段(如品牌 LOGO 地址) |
@Pattern | 自定义正则校验 | 首字母校验(如 ^[a-zA-Z]$ ) |
@Min | 指定最小值 | 排序字段(如 @Min(value = 0) ) |
@Valid | 开启 SpringMVC 校验 | Controller 层方法参数上 |
@Validated | 补充分组校验功能 | Controller 层方法参数上 |
二、普通校验与结果处理
- 开启校验:在 Controller 方法的
@RequestBody
参数前添加@Valid
或@Validated
。 - 手动处理错误:通过
BindingResult
获取校验结果,遍历错误信息并封装返回。
三、分组校验
作用:针对不同场景(如新增、修改)对同一字段设置不同校验规则。
实现步骤:
- 定义分组接口:创建空接口作为分组标识,如
AddGroup
、UpdateGroup
。 - 字段注解分组:在字段注解中通过
groups
参数指定所属分组。 - Controller 方法分组:在方法参数中使用
@Validated(value = {分组.class})
指定当前校验分组。
注意:未设置分组的注解在 @Validated
场景下不生效,需通过分组明确校验范围。
核心代码示例:
java
/**
* 实体类
*/
@Data
public class BrandEntity {
// 新增时ID必须为null,修改时必须不为null
@Null(message = "新增不能指定id", groups = {AddGroup.class})
@NotNull(message = "修改必须指定品牌id", groups = {UpdateGroup.class})
private Long brandId;
// 品牌名非空(新增/修改场景均需校验)
@NotBlank(message = "品牌名不能为空", groups = {AddGroup.class, UpdateGroup.class})
private String name;
// LOGO地址必须为合法URL(新增/修改场景)
@URL(message = "必须是合法的url地址", groups = {AddGroup.class, UpdateGroup.class})
private String logo;
}
// 分组校验标记
interface AddGroup {}
interface UpdateGroup {}
java
/**
* 分组校验
*/
@RestController
@RequestMapping("/brand")
public class BrandController {
// 新增场景:校验AddGroup分组
@PostMapping("/save")
public R save(
@Validated(value = {AddGroup.class}) @RequestBody BrandEntity brand
) {
brandService.save(brand);
return R.ok();
}
// 修改场景:校验UpdateGroup分组
@PutMapping("/update")
public R update(
@Validated(value = {UpdateGroup.class}) @RequestBody BrandEntity brand
) {
brandService.update(brand);
return R.ok();
}
}
四、统一异常处理
- 全局异常类:使用
@RestControllerAdvice
和@ExceptionHandler
捕获MethodArgumentNotValidException
异常。 - 错误信息封装:从异常中提取
BindingResult
,遍历FieldError
获取字段名和错误信息,统一返回包含错误码、消息和具体错误的响应格式。 - 优势:避免在每个 Controller 中重复处理校验逻辑,提升代码复用性和规范性。
核心代码示例:
java
/**
* 全局异常处理类
*/
//当指定的Controller抛出异常时会被这个类接收并统一处理
@RestControllerAdvice(basePackages = "com.xx.xx.controller")
@Slf4j
public class GulimallExceptionControllerAdvice {
//@ExceptionHandler能指定处理哪些异常类
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e) {
log.error("数据校验异常:{}", e.getMessage());
BindingResult bindingResult = e.getBindingResult();
Map<String, String> errorMap = new HashMap<>();
bindingResult.getFieldErrors().forEach(error -> {
errorMap.put(error.getField(), error.getDefaultMessage());
});
return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg())
.put("data", errorMap);
}
//Throwable类是所有错误和异常的超类
@ExceptionHandler(value = Throwable.class)
public R handleException(Throwable throwable){
return R.error(BizCodeEnum.UNKOWN_EXCEPTION.getCode(), BizCodeEnum.UNKOWN_EXCEPTION.getMsg());
}
}
java
/**
* 公共异常枚举类
*/
public enum BizCodeEnum {
UNKOWN_EXCEPTION(10000,"未知异常"),
VAILDE_EXCEPTIPN(10001,"参数格式校验异常");
private Integer code;
private String msg;
BizCodeEnum(Integer code, String msg){
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
五、关键点总结
- 注解搭配:
@Valid
用于基础校验,@Validated
用于分组校验,需结合groups
参数使用。 - 自定义消息:通过
message
参数自定义错误提示(如@NotBlank(message = "品牌名不能为空")
)。 - 异常处理:通过全局异常类集中处理校验,避免代码冗余,提升用户体验。