SpringBoot服务端数据校验

在 Web 应用程序中,为了防止客户端传来的数据引发程序异常,常常需要对数据进行验证。

数据验证分为:

  • 客户端验证

    • 客户端验证主要通过 JavaScript 脚本进行。
  • 服务端验证

    • 服务端验证主要通过 Java 代码进行验证。

在Spring Boot 3中,参数校验是通过Bean Validation API实现的,这个API是JSR 380规范的一部分。Spring Boot集成了Hibernate Validator作为默认的校验器。

1、spring常用校验注解

a、JSR 303 的注解
注解说明
@Null被注解的元素必须为 null
@NotNull被注解的元素必须不为 null
@AssertTrue被注解的元素必须为 true
@AssertFalse被注解的元素必须为 false
@Min被注解的元素必须是一个数字,其值必须小于指定值。
@Max被注解的元素必须是一个数字,其值必须大于指定值。
@DecimalMin被注解的元素必须是一个数字,其值必须小于指定值。
@DecimalMax被注解的元素必须是一个数字,其值必须大于指定值。
@Size(min, max)被注解的数组和集合型元素的长度是必须给定的范围之内
@Digits(integer, fraction)要求字符串必须是数字型字符串,且整数部分有 interger 位,小数部分有 fraction 位。
@Past要求必须是一个过去日期。用于 Date 和 Calendar
@Future要求必须是一个未来日期。用于 Date 和 Calendar
@Pattern(regexp, flag)要求字符串内容必须符合正则表达式的规则
@Valid要求递归检查数组和容器中关联对象。

所有的这些注解都有 message 属性,用于设置错误提示信息(如果没有设置,则会有默认的错误提示信息)。

b、Hibernate Validator注解

Hibernate Validator 实现了 JSR 303,它除了支持所有标准的校验注解外,还支持一些『额外』的注解:

注解说明
@NotBlank要求字符串必须不为 NULL,且执行 trim() 后必须为非空字符串
@Null要求字符串必须为 NULL
@AssertTrue注释的元素必须为 true
@AssertFalse注释的元素必须为 false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min)被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future被注释的元素必须是一个将来的日期
@Pattern(value)被注释的元素必须符合指定的正则表达式
@Email要求字符串内容必须符合邮箱格式。但是 null 会放过
@Length(min, max)要求字符串的长度必须在指定范围内
@NotEmpty备注解的字符串必须为非空
@Range(min, max)检查数字是否介于 min 和 max 之间
c、spring校验注解
注解说明
@NotNull注解的参数不能为 null
@Size被注解的参数的大小必须在指定的范围内(包括最小值和最大值)
@Min被注解的参数的最小值,适用于整数
@Max被注解的参数的最大值,适用于整数
@DecimalMin注解的参数的最小值,适用于浮点数、BigDecimal 或 BigInteger 类型的参数。
@DecimalMax注解的参数的最大值,适用于浮点数、BigDecimal 或 BigInteger 类型的参数。
@Digits被注解的参数必须是一个数字,并且整数位和小数位的位数不能超过指定的值(默认整数位 2 位,小数位 0 位)。
@Email被注解的参数必须是一个合法的电子邮件地址。
@Pattern注解的参数必须符合指定的正则表达式模式 @Pattern(regexp =“^lld{4}-\ld{1,2}-\df1,2}$”)

2、入门案例

a、添加依赖

<properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>3.0.2</spring-boot.version>
    </properties>
    <dependencies>
        <!--数据校验依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

b、创建vo实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVo implements Serializable {
    private String username;
    private String sex;
    private Integer age;
    private String address;

    @Override
    public String toString() {
        return "UserVo{" +
                ", username='" + username + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}'+"\n";
    }
}

c、创建controller

@RestController
public class UserController {

    /**
     * 完成用户添加
     */
    @PostMapping("user/add")
    public String saveUser(@RequestBody UserVo userVo){
        return "ok";
    }
}

d、使用Spring校验注解对数据校验

  • 在实体类中添加校验规则

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserVo implements Serializable {
        @NotEmpty(message = "姓名不能为空") //用户名非空校验
        @Length(min = 4,max = 6,message = "姓名必须在4-6个字符之间") //用户名长度必须在4-6位之间
        private String username;
        @NotBlank(message = "性别不能为空") //性别非空校验
        private String sex;
        @NotNull(message = "年龄不能为空") //年龄非空校验
        @Range(min = 0,max = 100,message = "年龄必须在0-100岁之间") //年龄必须在0-100之间
        private Integer age;
        @NotBlank(message = "请输入家庭住址") //地址非空校验
        private String address;
    }
    
  • 创建自定义异常类

    /**
     * Validator自定义异常类
     */
    public class ValidatorException extends  Exception{
        //保存异常信息
        private BindingResult result;
        public BindingResult getResult() {
            return result;
        }
        
        public ValidatorException(BindingResult result) {
            this.result = result;
        }
    }
    
  • 在全局异常类中添加表单验证异常

    /**
     * 全局异常处理类,检测controller中是否发生了异常,根据异常的类型输出不同的提示
     */
    @ControllerAdvice  //将当前类,配置为controller的代码增强类
    public class GlobalException {
    
        @ExceptionHandler(NumberFormatException.class)
        @ResponseBody
        public ResponseResult<Void> getNumberFormatException(NumberFormatException e){
            return new ResponseResult<>(4003,"转换数值类型出错!"+e.getMessage());
        }
    
        /**
         * 400 - Bad Request
         */
        @ExceptionHandler(HttpMessageNotReadableException.class)
        @ResponseBody
        public ResponseResult<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
            return new ResponseResult<>(400,"参数解析失败"+e.getMessage());
        }
    
        /**
         * 405 - Method Not Allowed
         */
        @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
        @ResponseBody
        public ResponseResult<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
            return new ResponseResult<>(405,"不支持当前请求的方法"+e.getMessage());
        }
    
        /**
         * 415 - Unsupported Media Type
         */
        @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
        @ResponseBody
        public ResponseResult<Void> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
            return new ResponseResult<>(415,"不支持当前媒体类型"+e.getMessage());
        }
    
        /**
         * 500 - Internal Server Error
         */
        @ExceptionHandler(HttpServerErrorException.class)
        @ResponseBody
        public ResponseResult<Void> handleServerErrorException(HttpServerErrorException e) {
            return new ResponseResult<>(500,"服务器异常"+e.getMessage());
        }
    
        /**
         * 表单验证异常
         */
        @ExceptionHandler(ValidatorException.class)
        @ResponseBody
        public ResponseResult<Object> handleValidatorException(ValidatorException e) {
            //取出BindingResult中的异常信息并保存到错误对象中返回给页面
            Map<String,String> beanError=new HashMap<String,String>();
            List<FieldError> list = e.getResult().getFieldErrors();
            for (FieldError error : list) {
                beanError.put(error.getField(),error.getDefaultMessage());
            }
            //将错误对象发送到页面
            return new ResponseResult<>(416,"表单不符合验证规则",beanError);
        }
    }
    
  • 在Controller中开启验证

    提示:使用验证框架时,controller中法的参数对象必须用 @Valid 注解修饰,并且处理方法要多出一个 BindingResult 参数对象。

    @RestController
    public class UserController {
    
        /**
         * 完成用户添加
         * 提示:BindingResult对象只能放在形参的最后一位
         */
        @PostMapping("user/add")
        public UserVo saveUser(@Validated @RequestBody UserVo userVo,BindingResult result) throws ValidatorException {
            // 如果User对象校验失败,将抛出MethodArgumentNotValidException异常
            if(result.hasErrors()){
                //表单不符合验证规则时抛出自定义异常
                throw  new ValidatorException(result);
            }
            return userVo;
        }
    }
    
  • 13
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值