# 参数校验

# 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

# 举例

package com.base.pre.controller;

import cn.dev33.satoken.util.SaResult;
import cn.dev33.satoken.exception.NotLoginException;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import org.springframework.web.bind.annotation.*;


/**
 * <p>
 *   Demo 控制器,用于触发全局异常处理器
 * </p>
 *
 * @author
 */
@RestController
@RequestMapping("/demo2")
@Tag(name = "异常演示接口")
public class DemoController {

    @GetMapping("/npe")
    @Operation(summary = "触发空指针异常")
    public SaResult npe() {
        String str = null;
        str.length(); // NullPointerException
        return SaResult.ok();
    }

    @GetMapping("/illegal")
    @Operation(summary = "触发非法参数异常")
    public SaResult illegal() {
        throw new IllegalArgumentException("参数值不合法!");
    }

    @PostMapping("/duplicate")
    @Operation(summary = "触发数据库唯一约束异常")
    public SaResult duplicate() {
        throw new org.springframework.dao.DataIntegrityViolationException("唯一约束冲突");
    }

    @PostMapping("/valid")
    @Operation(summary = "触发 @Valid 校验异常(MethodArgumentNotValidException)")
    public SaResult valid(@Valid @RequestBody UserDTO userDTO) {
        return SaResult.ok("校验通过: " + userDTO.getName());
    }

    @GetMapping("/param")
    @Operation(summary = "触发参数校验异常(ConstraintViolationException)")
    public SaResult param(
            @RequestParam(name = "id")
            @NotNull(message = "id 不能为空")
            @Min(value = 1, message = "id 必须大于 0")
            Integer id) {
        return SaResult.ok("收到id=" + id);
    }

    @GetMapping("/needLogin")
    @Operation(summary = "触发未登录异常(NotLoginException)")
    public SaResult needLogin() {
        throw new NotLoginException("未登录","/login","请先登录");
    }

    // DTO 用于 @Valid 测试
    public static class UserDTO {
        @NotNull(message = "用户名不能为空")
        private String name;

        @Min(value = 18, message = "年龄必须大于等于18")
        private Integer age;

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public Integer getAge() { return age; }
        public void setAge(Integer age) { this.age = age; }
    }
}

全局异常处理

package com.base.exception;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.util.SaResult;
import jakarta.validation.ConstraintViolationException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;


/**
 * 全局异常处理器
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 全局异常拦截(兜底)
    @ExceptionHandler(Exception.class)
    public SaResult handleException(Exception e) {
        e.printStackTrace();
        return SaResult.error("服务器内部错误: " + e.getMessage());
    }

    // 空指针异常
    @ExceptionHandler(NullPointerException.class)
    public SaResult handleNullPointerException(NullPointerException e) {
        e.printStackTrace();
        return SaResult.error("出现空指针,请检查参数或对象是否初始化");
    }

    // 非法参数异常
    @ExceptionHandler(IllegalArgumentException.class)
    public SaResult handleIllegalArgumentException(IllegalArgumentException e) {
        e.printStackTrace();
        return SaResult.error("参数错误: " + e.getMessage());
    }

    // 数据唯一性约束异常(用户名已存在等)
    @ExceptionHandler(DataIntegrityViolationException.class)
    public SaResult handleDataIntegrityViolationException(DataIntegrityViolationException e) {
        e.printStackTrace();
        return SaResult.error("用户名被占用");
    }

    // 登录异常(未登录)
    @ExceptionHandler(NotLoginException.class)
    public SaResult handleNotLoginException(NotLoginException e) {
        e.printStackTrace();
        return SaResult.code(401).setMsg("请先登录,再访问");
    }

    // 方法参数校验异常(@Valid 校验失败)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public SaResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        e.printStackTrace();
        String msg = e.getBindingResult().getFieldError().getDefaultMessage();
        return SaResult.error("参数校验失败: " + msg);
    }

    // 单个参数校验异常(@NotNull、@Min 等直接作用在 Controller 参数上)
    @ExceptionHandler(ConstraintViolationException.class)
    public SaResult handleConstraintViolationException(ConstraintViolationException e) {
        e.printStackTrace();
        return SaResult.error("参数校验失败: " + e.getMessage());
    }
}

# 小结

spring-boot-starter-validation = Hibernate Validator + Spring Boot 封装。

核心作用:对数据合法性进行注解式校验

用法:

  • 在 DTO/实体类上加注解。
  • 在 Controller 参数上加 @Valid@Validated
  • 自定义异常处理可返回友好提示。

# 常用校验注解速查

# 🔹 空值/非空校验

  • @NotNull:不能为 null(但可以是空字符串、集合等)。
  • @NotBlank:不能为 null,且字符串必须至少包含一个非空格字符。
  • @NotEmpty:不能为 null,并且长度必须 > 0(适用于字符串、集合、数组)。

# 🔹 数值范围

  • @Min(value):最小值(整数/小数)。
  • @Max(value):最大值。
  • @DecimalMin(value):小数最小值(支持边界可控 inclusive=false)。
  • @DecimalMax(value):小数最大值。
  • @Positive:必须 > 0。
  • @PositiveOrZero:必须 ≥ 0。
  • @Negative:必须 < 0。
  • @NegativeOrZero:必须 ≤ 0。
  • @Digits(integer, fraction):数值位数约束(整数部分 + 小数部分)。

# 🔹 长度与大小

  • @Size(min, max):字符串、数组、集合的长度/大小范围。
  • @Length(min, max):字符串长度限制(Hibernate Validator 扩展)。

# 🔹 字符串格式

  • @Email:邮箱格式校验。
  • @Pattern(regexp):正则表达式校验。
  • @URL:URL 格式校验(Hibernate Validator 扩展)。

# 🔹 时间日期

  • @Future:必须是将来的时间。
  • @FutureOrPresent:必须是现在或将来。
  • @Past:必须是过去的时间。
  • @PastOrPresent:必须是现在或过去。

# 🔹 组合校验

  • @Valid:级联校验(验证嵌套对象里的字段)。
  • @Validated:支持 分组校验(可以在不同场景下应用不同的校验规则)
Last Updated: 10/22/2025, 8:01:43 AM