参数校验 
POM依赖 
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>注解说明 
| 注解 | 说明 | 
|---|---|
| @AssertTrue | 可以为null,如果不为null的话必须为true | 
| @AssertFalse | 可以为null,如果不为null的话必须为false | 
| @DecimalMax | 设置不能超过最大值,适用于浮点数 | 
| @DecimalMin | 设置不能超过最小值,适用于浮点数 | 
| @Max | 最大不得超过此最大值,适用于整数 | 
| @Min | 最小不得小于此最小值,适用于整数 | 
| @NotNull | 不能为null | 
| @Null | 必须为null | 
| @NotBlank | 字符串不能为null,字符串trim()后也不能等于“” | 
| @Length | 长度必须在指定范围内,一般用于限定字符串的长度 | 
| @NotEmpty | 不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于“” | 
| @URL | 必须是一个URL | 
| 必须是email格式 | |
| @Size | 集合、数组、map等的size()值必须在指定范围内 | 
| @Pattern | 必须满足指定的正则表达式 | 
使用方式 
- 将注解写在实体类的字段上
java
@Data
public class UserVO implements Serializable {
 
    @Serial
    private static final long serialVersionUID = 1L;
 
    @NotNull(message = "用户ID不能为空")
    private Long userId;
 
    @NotBlank(message = "用户账号不能为空")
    private String username;
 
    @NotEmpty(message = "角色不能为空")
    private Set<Long> roleIds;
 
}- 在Controller上增加校验注解
java
@RestController
@RequestMapping("/basic/user")
@Tag(name = "用户管理")
public class UserController {
 
    @PostMapping("/addUser")
    @Operation(summary = "添加用户")
    public ResponseEntity<Void> addUser(@RequestBody @Validated UserVO userVO) {
        userService.addUser(userVO);
        return ResponseEntity.ok().build();
    }
 
}Controller单参数校验 
java
//注意:单参数校验需要在controller类上添加@Validated注解才能生效
@Validated
@RestController
@RequestMapping("/basic/user")
@Tag(name = "用户管理")
public class UserController {
 
    @DeleteMapping("/deleteUserByUserId")  
    @Operation(summary = "删除用户 -> 根据用户ID删除")
    public ResponseEntity<Void> deleteUserByUserId(@RequestParam("userId") @NotNull(message = "用户ID不能为空") Long userId) {
        userService.deleteUserByUserId(userId);
        return ResponseEntity.ok().build();
    }
 
}分组校验 
说明:新增的时候不需要传ID,修改的时候才传ID,但新增和修改用了同一个实体类,这时候就需要对id字段做分组校验。
- 定义分组标记
java
//自定义新增校验,写一个空接口标识即可
public interface Add {
}
 
//自定义修改校验
public interface Update {
}- 实体类中增加分组校验注解
java
@Data
public class UserVO implements Serializable {
 
    @Serial
    private static final long serialVersionUID = 1L;
 
    //修改时不能为空
    @NotNull(message = "用户ID不能为空", groups = {Update.class})
    private Long userId;
    //新增和修改时不能为空
    @NotBlank(message = "用户账号不能为空", groups = {Add.class, Update.class})
    private String username;
 
    @NotEmpty(message = "角色不能为空")
    private Set<Long> roleIds;
 
}- Controller中添加分组校验注解 需要注意:如果Controller加了@Validated(Add.class)分组校验,那么实体类中参数校验注解的groups就必须对应,否则就不会校验,包括没加groups的。比如这里指定的是Add.class,那么上面UserVO实体中的roleIds字段虽然加了@NotEmpty注解但没加groups属性,所以不会被校验。
java
@PostMapping("/addUser")
@PreAuthorize("hasAuthority('basic:user:add')")
@Operation(summary = "添加用户")
public ResponseEntity<Void> addUser(@RequestBody @Validated(Add.class) UserVO userVO) {
    userService.addUser(userVO);
    return ResponseEntity.ok().build();
}手工校验 
java
public class ValidateUtil {
    public static <T> void valid(T t) {
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        Validator validator = validatorFactory.getValidator();
        Set<ConstraintViolation<T>> errors = validator.validate(t);
        List<String> errorMsg = errors.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(errorMsg)) {
            StringJoiner sj = new StringJoiner(",");
            errorMsg.forEach(sj::add);
            throw new BusinessException(sj.toString());
        }
    }
}参数校验的异常处理 
java
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     * 参数异常
     * @param e 异常
     * @return 响应
     */
    @ExceptionHandler(value = {IllegalArgumentException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class})
    public ResponseEntity<Object> paramsException(Exception e) {
        if (e instanceof IllegalArgumentException) {
            log.warn(e.getMessage(), e);
            return ResponseEntity.status(RespEnum.PARAM_ERROR.getCode()).body(RespEnum.PARAM_ERROR.getDesc());
        } else if (e instanceof MethodArgumentNotValidException) {
            //参数异常处理
            log.warn(e.getMessage(), e);
            BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
            List<FieldError> errors = bindingResult.getFieldErrors();
            StringJoiner sj = new StringJoiner(",");
            errors.forEach(error -> sj.add(error.getDefaultMessage()));
            return ResponseEntity.status(RespEnum.PARAM_ERROR.getCode()).body(sj.toString());
        } else if (e instanceof ConstraintViolationException) {
            //参数异常处理
            log.warn(e.getMessage(), e);
            Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) e).getConstraintViolations();
            StringJoiner sj = new StringJoiner(",");
            constraintViolations.forEach(c -> sj.add(c.getMessageTemplate()));
            return ResponseEntity.status(RespEnum.PARAM_ERROR.getCode()).body(sj.toString());
        } else {
            return exception(e);
        }
    }
 
    /**
     * 未知异常
     * @param e 异常
     * @return 响应
     */
    @ExceptionHandler(value = {Exception.class})
    public ResponseEntity<Object> exception(Exception e) {
        //记录日志
        log.error(e.getMessage(), e);
        //响应 系统异常
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(RespEnum.FAILED.getDesc());
    }
 
}