Skip to content

JSR303数据校验指南

一、常用校验注解

注解说明适用场景
@Null必须为 null新增时 ID 自增字段(需为 null
@NotNull不能为 null基本数据类型(如 IntegerLong)的非空校验
@NotBlank至少有一个非空字符且不含空格String 类型参数(如品牌名)
@NotEmpty不能为空或 null集合、数组、对象等
@URL必须为合法 URLURL 地址字段(如品牌 LOGO 地址)
@Pattern自定义正则校验首字母校验(如 ^[a-zA-Z]$
@Min指定最小值排序字段(如 @Min(value = 0)
@Valid开启 SpringMVC 校验Controller 层方法参数上
@Validated补充分组校验功能Controller 层方法参数上

二、普通校验与结果处理

  • 开启校验:在 Controller 方法的 @RequestBody 参数前添加 @Valid@Validated
  • 手动处理错误:通过 BindingResult 获取校验结果,遍历错误信息并封装返回。

三、分组校验

作用:针对不同场景(如新增、修改)对同一字段设置不同校验规则。

实现步骤

  1. 定义分组接口:创建空接口作为分组标识,如 AddGroupUpdateGroup
  2. 字段注解分组:在字段注解中通过 groups 参数指定所属分组。
  3. 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 = "品牌名不能为空"))。
  • 异常处理:通过全局异常类集中处理校验,避免代码冗余,提升用户体验。

所有文章版权皆归博主所有,仅供学习参考。