前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring6 数据校验 Validation

Spring6 数据校验 Validation

原创
作者头像
鱼找水需要时间
发布于 2023-06-22 05:13:35
发布于 2023-06-22 05:13:35
3360
举报
文章被收录于专栏:SpringBoot教程SpringBoot教程

1、Spring Validation概述

在开发中,经常遇到参数校验的需求,比如用户注册的时候,要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式,会把校验的代码和真正的业务处理逻辑耦合在一起,而且如果未来要新增一种校验逻辑也需要在修改多个地方。而spring validation允许通过注解的方式来定义对象校验规则,把校验和业务逻辑分离开,让代码编写更加方便。Spring Validation其实就是对Hibernate Validator进一步的封装,方便在Spring中使用。

在Spring中有多种校验的方式

第一种是通过实现org.springframework.validation.Validator接口,然后在代码中调用这个类

第二种是按照Bean Validation方式来进行校验,即通过注解的方式。

第三种是基于方法实现校验

除此之外,还可以实现自定义校验

2、通过Validator接口实现

第一步 创建模块 spring6-validator

第二步 引入相关依赖

代码语言:html
AI代码解释
复制
<dependencies>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>7.0.5.Final</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>jakarta.el</artifactId>
        <version>4.0.1</version>
    </dependency>
</dependencies>

第三步 创建实体类,定义属性和方法

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method1;

public class Person {
    private String name;
    private int age;

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

第四步 创建类实现Validator接口,实现接口方法指定校验规则

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method1;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class PersonValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return Person.class.equals(clazz);
    }

    @Override
    public void validate(Object object, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors, "name", "name.empty");
        Person p = (Person) object;
        if (p.getAge() < 0) {
            errors.rejectValue("age", "error value < 0");
        } else if (p.getAge() > 110) {
            errors.rejectValue("age", "error value too old");
        }
    }
}

上面定义的类,其实就是实现接口中对应的方法,

supports方法用来表示此校验用在哪个类型上,

validate是设置校验逻辑的地点,其中ValidationUtils,是Spring封装的校验工具类,帮助快速实现校验。

第五步 使用上述Validator进行测试

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method1;

import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;

public class TestMethod1 {

    public static void main(String[] args) {
        //创建person对象
        Person person = new Person();
        person.setName("lucy");
        person.setAge(-1);
        
        // 创建Person对应的DataBinder
        DataBinder binder = new DataBinder(person);

        // 设置校验
        binder.setValidator(new PersonValidator());

        // 由于Person对象中的属性为空,所以校验不通过
        binder.validate();

        //输出结果
        BindingResult results = binder.getBindingResult();
        System.out.println(results.getAllErrors());
    }
}

3、Bean Validation注解实现

使用Bean Validation校验方式,就是如何将Bean Validation需要使用的javax.validation.ValidatorFactoryjavax.validation.Validator注入到容器中。spring默认有一个实现类LocalValidatorFactoryBean,它实现了上面Bean Validation中的接口,并且也实现了org.springframework.validation.Validator接口。

第一步 创建配置类,配置LocalValidatorFactoryBean

代码语言:java
AI代码解释
复制
@Configuration
@ComponentScan("com.example.spring6.validation.method2")
public class ValidationConfig {

    @Bean
    public LocalValidatorFactoryBean validator() {
        return new LocalValidatorFactoryBean();
    }
}

第二步 创建实体类,使用注解定义校验规则

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method2;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;

public class User {

    @NotNull
    private String name;

    @Min(0)
    @Max(120)
    private int age;

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

常用注解说明

  • @NotNull: 限制必须不为null
  • @NotEmpty: 只作用于字符串类型,字符串不为空,并且长度不为0
  • @NotBlank: 只作用于字符串类型,字符串不为空,并且trim()后不为空串
  • @DecimalMax(value): 限制必须为一个不大于指定值的数字
  • @DecimalMin(value): 限制必须为一个不小于指定值的数字
  • @Max(value): 限制必须为一个不大于指定值的数字
  • @Min(value): 限制必须为一个不小于指定值的数字
  • @Pattern(value): 限制必须符合指定的正则表达式
  • @Size(max,min): 限制字符长度必须在min到max之间
  • @Email: 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

第三步 使用两种不同的校验器实现

(1)使用jakarta.validation.Validator校验

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method2;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Set;

@Service
public class MyService1 {

    @Autowired
    private Validator validator;

    public  boolean validator(User user){
        Set<ConstraintViolation<User>> sets =  validator.validate(user);
        return sets.isEmpty();
    }

}

(2)使用org.springframework.validation.Validator校验

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindException;
import org.springframework.validation.Validator;

@Service
public class MyService2 {

    @Autowired
    private Validator validator;

    public boolean validaPersonByValidator(User user) {
        BindException bindException = new BindException(user, user.getName());
        validator.validate(user, bindException);
        return bindException.hasErrors();
    }
}

第四步 测试

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method2;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestMethod2 {

    @Test
    public void testMyService1() {
        ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
        MyService1 myService = context.getBean(MyService1.class);
        User user = new User();
        user.setAge(-1);
        boolean validator = myService.validator(user);
        System.out.println(validator);
    }

    @Test
    public void testMyService2() {
        ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
        MyService2 myService = context.getBean(MyService2.class);
        User user = new User();
        user.setName("lucy");
        user.setAge(130);
        user.setAge(-1);
        boolean validator = myService.validaPersonByValidator(user);
        System.out.println(validator);
    }
}

4、基于方法实现校验

第一步 创建配置类,配置MethodValidationPostProcessor

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method3;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

@Configuration
@ComponentScan("com.example.spring6.validation.method3")
public class ValidationConfig {

    @Bean
    public MethodValidationPostProcessor validationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}

第二步 创建实体类,使用注解设置校验规则

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method3;

import jakarta.validation.constraints.*;

public class User {

    @NotNull
    private String name;

    @Min(0)
    @Max(120)
    private int age;

    @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$",message = "手机号码格式错误")
    @NotBlank(message = "手机号码不能为空")
    private String phone;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
}

第三步 定义Service类,通过注解操作对象

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method3;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

@Service
@Validated
public class MyService {
    
    public String testParams(@NotNull @Valid User user) {
        return user.toString();
    }

}

第四步 测试

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method3;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestMethod3 {

    @Test
    public void testMyService1() {
        ApplicationContext context = new AnnotationConfigApplicationContext(ValidationConfig.class);
        MyService myService = context.getBean(MyService.class);
        User user = new User();
        user.setAge(-1);
        myService.testParams(user);
    }
}

5、实现自定义校验

第一步 自定义校验注解

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method4;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {CannotBlankValidator.class})
public @interface CannotBlank {
    //默认错误消息
    String message() default "不能包含空格";

    //分组
    Class<?>[] groups() default {};

    //负载
    Class<? extends Payload>[] payload() default {};

    //指定多个时使用
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        CannotBlank[] value();
    }
}

第二步 编写真正的校验类

代码语言:java
AI代码解释
复制
package com.example.spring6.validation.method4;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

public class CannotBlankValidator implements ConstraintValidator<CannotBlank, String> {

        @Override
        public void initialize(CannotBlank constraintAnnotation) {
        }

        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
                //null时不进行校验
                if (value != null && value.contains(" ")) {
                        //获取默认提示信息
                        String defaultConstraintMessageTemplate = context.getDefaultConstraintMessageTemplate();
                        System.out.println("default message :" + defaultConstraintMessageTemplate);
                        //禁用默认提示信息
                        context.disableDefaultConstraintViolation();
                        //设置提示语
                        context.buildConstraintViolationWithTemplate("can not contains blank").addConstraintViolation();
                        return false;
                }
                return true;
        }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
计算机网络(一)计算机网络概述
网络核心的关键功能:路由 + 转发 路由:用路由算法确定分组从源到目的传输路径 转发:将分组从路由器的输入端口交换至正确的输出端口
星辉
2019/01/15
7240
计算机网络学习笔记--计算机网络概述
为了更好的理解Internet(互联网)这个概念,先从简单的网络概念说起:通俗的理解网络,就是由许多节点和边组成的系统。当我们把这些节点和边具象化之后,计算机网络以及Internet的概念就更容易理解了。
花猪
2022/02/16
2.5K0
计算机网络学习笔记--计算机网络概述
计算机网路概述(上)
cheese
2023/10/25
3520
计算机网路概述(上)
【计算机网络】计算机网络(谢希仁-第八版)课后习题-第一章习题全解
1)连通性:互联网用户之间,不管距离多远,都可以便捷、经济地交换各种信息,好像这些用户彼此都相互连通一样。 2)资源共享:可以是信息共享、软件共享、硬件共享等。
程序员洲洲
2024/06/17
5K0
计算机网络 | 关键知识点与习题集锦(上)
这个就是笔者【计算机网络】的绩点截图啦,一般般算还行 大佬们看到就当这边班门弄斧、贻笑大方啦~ 当时卷面是空了一个填空题,丢了两分,平时分有一次有事情请假了一节课,就分数比较低啦 好啦那话不多说,笔者经此一着,决定把当时总结整理的知识点和题集再次整理上来,同各位互联网道友一道分享,无论是学生在读 还是已入职场 或是在准备面试的朋友老铁亲们,想来应是很有帮助的。 这波主要是【计算机网络】的一些知识点和题目,分上、下两篇博客发布,每篇应该是有好几千字叭, 收集整理不易,若亲们觉着有用,便请亲们自取啦~ 笔者在此感谢亲们支持~
凌川江雪
2020/12/07
7920
计算机网络 | 关键知识点与习题集锦(上)
【计算机网络】计算机网络概述 : 总结 ( 概念 | 组成 | 功能 | 分类 | 性能指标 | OSI 七层参考模型 | TCP/IP 模型 | 五层参考模型 )★★★
参考博客 : 【计算机网络】计算机网络 相关概念 ( 计算机网络概念 | 计算机网络功能 | 组成 | 工作方式 | 功能组成 | 分类 )
韩曙亮
2023/03/28
1.6K0
计算机网络 1 -因特网概述
internet 是一个通用名词, 泛指多个计算机网络互连而成的网络. 在这些网络之间的通信协议可以是任意的
Rikka
2022/01/19
1.7K0
计算机网络 1 -因特网概述
计算机网络复习
h3110_w0r1d
2024/04/11
1370
计算机网络复习
从零开始的计网学习——计算机网络概述(计网入门就看这篇!)
以上都是本从零开始系列的计网学习其他几个章节,各位想学习计网的其他内容的可以关注一下。
全栈程序员站长
2022/09/02
6330
从零开始的计网学习——计算机网络概述(计网入门就看这篇!)
【计算机网络】第一章 概述
注意:互联网 ≠互连网。互连网:局部范围互连起来的计算机网络。 互联网的 2 个重要基本特点
SarPro
2024/03/16
1390
【计算机网络】第一章 概述
计算机网络
因特网现已发展成为世界上最大的国际性计算机互联网,网络(network)由若干结点(node)和连接这些结点的链路(link)组成。 互联网是“网络的网络”(network of networks)。 连接在因特网上的计算机都称为主机(host)网络把许多计算机连接在一起。因特网把许多网络连接在一起。
十二惊惶
2024/02/28
1690
计算机网络
计算机网络(一)—— 概述
单个分组(这只是整个报文的一部分)传送到相邻节点,存储下来后查找转发表,转发到下一个节点
繁依Fanyi
2023/05/07
4510
计算机网络(一)—— 概述
计算机网络概述(下)
cheese
2023/10/25
6140
计算机网络概述(下)
计算机网络笔记之第一章概述
  如今计算机网络早已融入生活中的方方面面,”互联网+“充斥着我们的生活。那么我们就有必要了解一下网络。  课本:谢希仁《计算机网络(第六版)》  首先,从总体上了解计算机网络,走进计算机网络的大门。 在学习之前,总会有一些疑问。  1在生活中,计算机网络扮演着什么角色呢?计算机网络有什么作用?  2什么是计算机网络?什么是互联网?什么是因特网?  3为什么叫课本叫计算机网络,而不是叫互联网或者因特网呢?   4因特网的历史,它是怎样发展变化的?建立的初衷是什么?  5因特网是怎样组成的?  6日常生活中的
用户1631856
2018/04/12
1.2K0
计算机网络笔记之第一章概述
计算机网络学习--概述
第一章 概述 第二章 物理层 第三章 数据链路层 第四章 网络层 第五章 传输层 第六章 应用层
shimeath
2020/08/02
4910
计算机网络和因特网
本篇是第一章计算机网络和因特网的读书笔记,从整体上粗线条地勾勒岀计算机网络的概貌,并给出一个端到端吞吐量和时延的简单定量模型
中龙技术
2022/09/30
1.3K0
计算机网络和因特网
计算机网络--概论
对于网络,我觉得就是打CS,开个玩笑(反恐精英玩过吧//滑稽),就是在一个不跟外界连接的网吧里面,有好多电脑,然后通过交换机我们可以实现信息共享。请看图(当然,当交换机上的接口足够多的话,我们可以连接尽可能多的机子)
杨鹏伟
2020/09/10
8010
计算机网络(谢希仁第八版)第一章:概述
Internet(译名:因特网,目前使用最广泛的译名为:==互联网==(不是互连网internet))采用TCP/IP协议族作为通信规则,其前身为美国的ARPANET。
roydonGuo
2022/11/02
1.8K0
计算机网络(谢希仁第八版)第一章:概述
【计算机网络】概述
【计算机网络】-复习篇(含习题及答案 1. 第一章 概述 1.1 计算机网络在信息时代中的作用 1.2 互联网概述 1.3 互联网的组成 1.4 计算机网络在我国的发展 1.5 计算机网络的定义 1.6 计算机网络的性能 1.7 计算机网络体系结构 1. 第一章 概述 1.1 计算机网络在信息时代中的作用 计算机网络是互连、自治的计算机集合 网络包含 【电信网络、有线电视网络、计算机网络】 Internet 译名两种 (因特网、互联网) 互联网的两个基本特点 (连通性、共享性) 连通性: 距离上连通 共
司六米希
2022/11/15
4760
【计算机网络】概述
1-计算机网络和因特网
如果ISDN的带宽为 128kbps,OC-48的带宽为 2.488 Gbps,如果用ISDN传输一张装满数据的1.44M软盘,用OC-48传输装满10G的硬盘数据,问哪一种传输所用的时间更少?
Ywrby
2022/10/27
2.3K0
1-计算机网络和因特网
推荐阅读
相关推荐
计算机网络(一)计算机网络概述
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档