参数校验

157 阅读4分钟

本文就来介绍一下在 SpringBoot 应用中怎么进行参数校验。

1.pom.xml依赖

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

在 SpringBoot 项目中可以引用 spring-boot-starter-validation 实现数据验证。 spring-boot-starter-validation 不仅支持 JSR-303(Bean Validation 1.0)规范,还提供了对 JSR-380(Bean Validation 2.0)规范的全面支持。可以利用 Bean Validation 2.0 的新特性,更灵活地定义验证规则,包括对集合、嵌套对象的验证等。

2.@Validated 和@Valid 的区别

来源

@Validated:Spring 框架特有的注解,是标准 JSR-303 的一个变种,提供了一个分组功能

@Valid:标准 JSR-303 规范的标记型注解。

注解位置

@Validated:作用在类上、方法上、方法参数上,不能作用于成员属性上。

@Valid:方法、构造函数、方法参数、成员属性上。

分组

@Validated:支持分组验证。

@Valid:支持标准的 Bean 验证功能,不支持分组验证。

嵌套验证

@Validated:不支持嵌套验证。

@Valid:支持嵌套验证。

3.常用的参数校验注解以及相关例子

image.png

1.1、基本用法 1.@NotNull:校验元素值不能为空,如果为空,则校验失败。

@NotNull(message = "名字不能为空")
private String userName;

2.@NotBlank:校验字符串值不能为null和空字符串,必须包含至少一个非空字符即执行trim(之后不为’‘)。如果元素为null或者’',则验证失败。

    @NotBlank(message = "昵称不能为null和空字符串")
    private String nickName;

3.@NotEmpty:校验集合或者数组或者字符串是否非空,通常用于集合和数组字段,需要集合和数组元素个数大于0。也可以作用于字符串,此时校验字符串不能为null或空串(可以是一个空格)。

    @NotEmpty(message = "postIds不能为空")
    private Long[] postIds;

4.@Max:校验数字元素最大值。

    @Max(value=100,message = "年龄最大100")
    private String age;

5.@Min:校验数字元素最小值。

    @Min(value=18,message = "年龄最小100")
    private String age;

6.@Past:校验日期或时间元素是否在当前时间之前。即是否是过去时间。作用于Date相关类型的字段。

    @Past(message = "")
    private Date createTime;

7.@Future:校验日期或时间元素是否在当前时间之前。即是否是过去时间。作用于Date相关类型的字段。

    @Future(message = "")
    private Date createTime;

8.@Email:校验字符串元素是否为有效的电子邮件地址。

    @Email(message = "")
    private String email;

9.@Pattern:根据正则表达式校验字符串元素的格式。

    @Pattern(regexp = "[a-zA-Z0-9]+")
    private String userName;

10.@Size:校验集合元素个数或字符串的长度在指定范围内。

@Size(min = 3, max = 10, message = "长度在3到10之间")
private String username;

11.@Length:校验字符串元素的长度。作用于字符串。

@Length(min = 3, max = 10, message = "长度在3到10之间")
private String username;

以上只是部分注解和他们的功能,需要详细的了解需要查看源码。

具体代码实现

全局异常处理器 捕获参数校验异常

package com.itheima.exception;

import com.itheima.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.sql.SQLIntegrityConstraintViolationException;
import java.util.Objects;

/**
 * 全局异常处理器,处理项目中抛出的业务异常
 */
@RestControllerAdvice // 标识当前类是一个全局异常处理器
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 捕获参数校验异常
     */
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handle(MethodArgumentNotValidException e) {
        return Result.error(Objects.requireNonNullElse(e.getBindingResult().getFieldError(), new FieldError("target", "field", "参数验证错误")).getDefaultMessage());
    }
    /**
     * 捕获业务异常
     */
    @ExceptionHandler
    public Result exceptionHandler(BaseException ex){
        log.error("通用异常信息:{}", ex.getMessage());
        return Result.error(ex.getMessage());
    }

    /**
     * 捕获SQL异常
     */
    @ExceptionHandler
    public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
        log.error("SQL异常信息:{}", ex.getMessage());
        String message = ex.getMessage();
        if (message.contains("Duplicate entry")){//如果异常消息中包含 "Duplicate entry" 字样
            return Result.error("已存在");
        }else {
            return Result.error("UNKNOWN_ERROR");
        }
    }

    /**
     * 捕获算法异常
     */
    @ExceptionHandler
    public Result exceptionHandler(ArithmeticException ex){
        log.error("计算异常信息:{}", ex.getMessage());
        return Result.error(ex.getMessage());
    }
}

统一公共返回类

package com.itheima.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Integer code;//响应码,1 代表成功; 0 代表失败
    private String msg;  //响应信息 描述字符串
    private Object data; //返回的数据

    //增删改 成功响应
    public static Result success(){
        return new Result(1,"success",null);
    }
    //查询 成功响应
    public static Result success(Object data){
        return new Result(1,"success",data);
    }
    //失败响应
    public static Result error(String msg){
        return new Result(0,msg,null);
    }
}

控制器

package com.itheima.controller;

import com.itheima.pojo.Result;
import com.itheima.pojo.vo.SysUserVO;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author wuJiaWei
 * @version 1.0
 */
@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    public Result add(@Validated @RequestBody SysUserVO sysUserVO) {
        userService.AddUser(sysUserVO);
        return Result.success();
    }
}

视图传输数据类

package com.itheima.pojo.vo;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;

@Data
public class SysUserVO {

    @ApiModelProperty("部门ID")
    private Long deptId;

    @NotBlank(message = "名字不能为空")
    @ApiModelProperty("用户名")
    private String userName;

    @NotBlank(message = "昵称不能为null和空字符串")
    @ApiModelProperty("昵称")
    private String nickName;

    @ApiModelProperty("密码")
    private String password;

    @ApiModelProperty("用户性别(0男,1女")
    private Integer gender;


    @ApiModelProperty("手机号码")
    private String phone;

    @Email(message = "请填写正确的邮箱地址")
    @ApiModelProperty("邮箱")
    private String email;

    @ApiModelProperty("头像地址")
    private String avatarName;

    @ApiModelProperty("用户类型(0管理员,1普通用户")
    private Integer userType;

    @ApiModelProperty("状态:1启用、0禁用")
    private Integer status;

    @ApiModelProperty("备注")
    private String remark;
}

嵌套对象验证、分组验证、自定义验证注解 就不写了。