spring-boot-starter-validation进行参数校验

本文介绍了如何在Spring MVC项目中使用Spring Validation对Controller参数进行校验,包括常用的Hibernate Validator注解、使用场景和错误处理方法。从创建DTO对象、@Validated注解到异常捕获,提供了详尽的步骤和实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:
Java API规范(JSR303)定义了Bean校验的标准validation-api,但没有提供实现。hibernate validation是对这个规范的实现,并增加了校验注解如@Email、@Length等。Spring Validation是对hibernate validation的二次封装,用于支持spring mvc参数自动校验。

引入依赖pom.xml

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

常用注解

注意不用错了类型!

注解限制
@Null限制只能为null
@NotNull限制必须不为null
@AssertFalse限制必须为false
@AssertTrue限制必须为true
@DecimalMax(value)限制必须为一个不大于指定值的数字
@DecimalMin(value)限制必须为一个不小于指定值的数字
@Digits(integer,fraction)限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future限制必须是一个将来的日期
@Max(value)限制必须为一个不大于指定值的数字
@Min(value)限制必须为一个不小于指定值的数字
@Past限制必须是一个过去的日期
@Pattern(value)限制必须符合指定的正则表达式 字符串
@Size(max,min)限制字符长度必须在min到max之间 【不是数字】
@Past验证注解的元素值(日期类型)比当前时间早
@NotEmpty验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
@Length(min = 6, max = 16)指定传入的字符串的长度

使用

对于web服务来说,为防止非法参数对业务造成影响,在Controller层一定要做参数校验的!大部分情况下,请求参数分为如下两种形式:

  1. POSTPUT请求,使用requestBody传递参数;

    这种情况下,后端使用DTO对象进行接收。只要给DTO对象加上@Validated注解就能实现自动参数校验。比如,有一个保存User的接口,要求userName长度是2-10,account和password字段长度是6-20。如果校验失败,会抛出MethodArgumentNotValidException异常,Spring默认会将其转为400(Bad Request)请求。

    DTO表示数据传输对象Data Transfer Object),用于服务器和客户端之间交互传输使用的。在spring-web项目中可以表示用于接收请求参数的Bean对象。

  2. GET请求,使用requestParam/PathVariable传递参数。
    如果参数比较多(比如超过6个),还是推荐使用DTO对象接收。否则,推荐将一个个参数平铺到方法入参中。在这种情况下,必须在Controller类上标注@Validated注解,并在入参上声明约束注解(如@Min等)。如果校验失败,会抛出ConstraintViolationException异常。

首先在实体类里面加入校验的注解

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User implements Serializable {

    private static final long serialVersionUID = -5577261004651495987L;

    @TableId(type = IdType.AUTO)
    private Integer userId;


    @NotEmpty
    @Length(min = 6, max = 16, message = "密码不能为空") //@Length本身就不允许为空
    private String password;
    
    private Integer role;

    private String salt;
    /**
     * 通过邮箱来登录
     */
    @Email(regexp = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$")
    @NotNull
    private String email;

    private Date registerTime;

    @Override
    public String toString() {
        String ret = null;
        ObjectMapper mapper = new ObjectMapper();
        try {
            ret = mapper.writeValueAsString(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }
}

然后在接收User对象的时候加入@Valid或者@Validated注解:

注意:
spring提供的验证:org.springframework.validation.annotation.Validated;
javax提供的验证:javax.validation.Valid;
@Valid 和 @Validated 都用来触发一次校验, @Valid 是 JSR 303规范的注解, @Validated 是Spring 加强版的注解, 加强的地方有:
@Validated 支持组序列, 该特性用的较少 推荐使用 @Validated 注解.

有几种方法都可以捕获到出现的不匹配情况:

方法一:全局异常捕获
@PostMapping("/login")
 public RetJson<Object> login(@Valid @RequestBody User user){
	...
 }

使用全局异常返回错误信息(就是写在实体类上面的message信息)

@RestControllerAdvice
@Slf4j
public class ExceptionResolver {
	/**
     * 参数不匹配异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = { MethodArgumentNotValidException.class})
    public RetJson methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        log.error("------->MethodArgumentNotValidException参数异常-------- ", e);
        return RetJson.fail(ResultCode.VALIDATE_FAILED.getCode(), "参数异常"+e.getBindingResult().getFieldError().getDefaultMessage());
        //getDefaultMessage()会返回message信息
    }
}

第二种:在方法上直接处理

在实体类传参时加上BindingResult注解:

同时注意BindingResult必须紧跟@ModelAttribute的后面
例如:必须写成这种方式:
public String add(@Valid RoleBO role, BindingResult binding,
Map<String, Object> request)

写成如下方式,
public String add(@Valid RoleBO role, Map<String, Object> request),BindingResult result)
会抛出异常:java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply:

其实过程就是:

  1. 在 Pojo 类的字段上, 加上 Hibernate validator 注解
  2. 在Controller 函数的形参前加上 @Valid 或 @Validated 注解, 触发一次validation.
  3. 在每个 @Valid 或 @Validated 注解参数后, 紧跟一个 BindingResult 类型的参数. 如果没有提供对应的 BindingResult 参数, Spring MVC 将抛出异常.
  4. 在Controller 函数中, 通过 BindingResult 类型的参数获取检验的结果.
@PostMapping("/login")
 public RetJson<Object> login(@Valid @RequestBody User user, BindingResult result){
	if (result.hasErrors()) {
          log.error("[login]参数错误:User={}", user);
           String s = result.getFieldError().getDefaultMessage();
           throw new BaseException(ResultCode.VALIDATE_FAILED.getCode(), s);
     }
        ...
 }

这样也可以直接返回message错误的信息。

方法三:工具类

写一个工具类判断有没有不匹配的情况:

public class ValidatedUtil {
    private static Validator validator=
            Validation.byProvider(HibernateValidator.class).configure().failFast(true).buildValidatorFactory().getValidator();

    public static<T> Boolean validate(T v){
        Set<ConstraintViolation<T>> set= validator.validate(v);
        return set.size() == 0;
    }

 	public static void validData(BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            StringBuilder sb = new StringBuilder();
            for (ObjectError error : bindingResult.getAllErrors()) {
                sb.append(error.getDefaultMessage());
            }
            throw new BaseException(ResultCode.VALIDATE_FAILED.getCode(), sb.toString());
        }
    }
}
当然单个参数也可以直接使用
    @GetMapping("/getEmailCode")
	public RetJson<Object> getEmailCode(
			@RequestParam("email") @Valid 
			@Email(regexp = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$", message = "邮箱格式不对") String email) {
		//使用全局异常拦截MethodArgumentNotValidException 可以拦截到这个信息	
}

拓展链接:Spring Validation最佳实践及其实现原理,参数校验没那么简单!

<think>嗯,用户想下载Spring Boot Starter Validation的Maven依赖。我记得之前处理过类似的问题,需要先确定正确的依赖坐标。首先,Spring Boot的官方starter通常都是以spring-boot-starter-开头,所以这个依赖应该是org.springframework.boot组下的。 用户提到的引用[1]中给出的版本是2.5.14,但可能他们需要的是最新的稳定版。不过最好确认用户是否需要特定版本。如果用户项目中的Spring Boot版本是2.x,那么应该对应使用相同版本的starter-validation。比如,如果用的是Spring Boot 2.5.x,那么依赖版本应该是2.5.14,如引用中所示。如果是Spring Boot 3.x,则需要用3.x的版本,因为3.x的包名可能有变化,比如jakarta替代了javax。 接下来,正确的Maven依赖格式应该是groupId、artifactId和version。用户示例中的依赖写法是正确的,但要注意版本号是否需要显式声明。在Spring Boot项目中,通常推荐使用父POM来管理版本,这样就不用单独指定版本号了。所以需要建议用户检查是否继承了spring-boot-starter-parent,如果是的话,可以省略版本号,否则需要明确指定。 另外,用户可能对如何验证依赖是否正确下载有疑问,可能需要指导他们运行mvn clean install或者检查IDE中的依赖树。还有,引用[2]提到自定义校验注解的封装,可能需要进一步说明如何使用这个starter进行参数校验,比如在VO类中添加注解,以及在Controller中使用@Valid等。 用户的问题集中在如何下载依赖,但可能后续会涉及到配置和使用的问题。所以回答时需要涵盖基本的依赖添加方法,同时预见到用户可能需要版本兼容性的帮助,或者如何实际使用这个依赖进行参数校验。需要确保提供的代码示例正确,特别是XML中的依赖格式是否正确,比如是否闭合了标签,版本号是否合适。 总结下来,回答应该分步骤:1. 添加Maven依赖,2. 验证父POM的版本管理,3. 基本使用示例。同时提醒版本匹配的重要性,避免因为版本不一致导致的问题。如果有必要,可以提到引用中的例子,说明用户之前可能在使用旧版本,或者需要升级到新版本的情况。</think>要下载Spring Boot Starter Validation依赖,需按照以下步骤操作: ### 1. 添加Maven依赖 在项目的`pom.xml`文件中添加以下依赖声明: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>2.5.14</version> </dependency> ``` 若项目已继承Spring Boot父POM(例如`spring-boot-starter-parent`),可省略`<version>`标签,版本号将自动与Spring Boot版本对齐[^1]。 ### 2. 验证依赖配置 - 对于Spring Boot 2.x系列,直接使用上述依赖即可 - 对于Spring Boot 3.x系列,需更新版本号为3.x(例如`3.1.5`)并注意包路径变化(`jakarta.validation`替代`javax.validation`) ### 3. 基本使用示例 在VO类中添加校验注解: ```java public class UserVO { @NotBlank(message = "用户名不能为空") private String username; @Min(value = 18, message = "年龄必须大于18岁") private Integer age; } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值