spring数据校验:Validation

news2024/12/22 12:59:22

目录

Spring Validation概述

通过Validator接口实现

Bean Validation注解实现 

基于方法实现校验

实现自定义校验


Spring Validation概述

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

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

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

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

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

通过Validator接口实现

第一步 创建子模块 spring6-validator

第二步 引入相关依赖

<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>

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

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接口,实现接口方法指定校验规则

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进行测试

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());
    }
}

Bean Validation注解实现 

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

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

@Configuration
@ComponentScan("com.atguigu.spring6.validation.method2")
public class ValidationConfig {

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

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

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校验

@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校验

@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();
    }
}

第四步 测试

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);
    }
}

基于方法实现校验

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

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

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

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

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类,通过注解操作对象

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

}

第四步 测试

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);
    }
}

实现自定义校验

第一步 自定义校验注解

@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();
    }
}

第二步 编写真正的校验类

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;
        }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/543032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从眼中窥视:Google AI 模型如何通过眼睛预测你的年龄

新的模型可以通过分析眼部照片揭示衰老的秘密 近年来&#xff0c;谷歌一直在研究各种人工智能模型&#xff0c;可以分析眼睛&#xff08;内部和外部&#xff09;的图像并监测某些参数。正如之前提到的&#xff0c;开发能够从眼睛中提取信息的 AI 模型意味着能够以经济高效和无创…

Array-Deque-Queue等的区别

&#x1f50e;Deque&#xff08;双端队列&#xff09;: Deque 是 “double-ended queue” 的缩写&#xff0c;表示双端队列。它是一种可以在两端进行插入和删除操作的数据结构。你可以在队列的头部和尾部同时进行插入和删除操作。Deque 接口定义了这些操作的方法&#xff0c;如…

国际博物馆日|科技与文化的碰撞:大势智慧助力博物馆赋能美好生活

近年来&#xff0c;我国博物馆事业蓬勃发展&#xff0c;而科技与文博领域的深度融合&#xff0c;将继续成为博物馆事业高质量发展的助推器。作为连接过去、现在、未来的桥梁和新时代文化交流与传播的窗口&#xff0c;博物馆不仅是保护和传承人类文明的重要殿堂&#xff0c;也是…

网络优化干扰培训讲解

一、系统外干扰 1、信号放大器 1、特征&#xff1a;RB尖峰突起(类似于互调干扰&#xff0c;极少数会形成宽频干扰。信号放大器为目前FDD频段主要干扰源 2、影响范围&#xff1a;周边站点 3、干扰来源&#xff1a;用户私装信号放大器、黑直放站. 4、原因分析&#xff1a;放…

javaIO流之字节流

目录 1、字节输出流&#xff08;OutputStream&#xff09;2、FileOutputStream类2.1FileOutputStrea 的构造方法2.2FileOutputStream 写入字节数据2.3FileOutputStream实现数据追加、换行 3、字节流入流&#xff08;InputStream&#xff09;4、FileInputStream类4.1FileInputSt…

介绍自己的产品时,常犯的那些错

最近的一个轻咨询客户&#xff0c;在“全面提升组织产品能力”的项目中&#xff0c;正处于内部自学的“读书会”环节。 为了“用以致学”&#xff0c;而不是“学以致用”地读书&#xff0c;我给他们出了一道看起来很简单的题——介绍一下自己手头正在负责的产品。 前几天&#…

Java枚举

Java枚举 &#x1f37a;1 背景及定义&#x1f37a;&#x1f9c3;2 使用&#x1f9c3;&#x1f964;3 枚举优点缺点&#x1f964;&#x1f375;4 枚举和反射&#x1f375;&#x1f377;4.1 枚举是否可以通过反射&#xff0c;拿到实例对象呢&#xff1f;&#x1f377; ☕️5 总结…

正负压力精密控制在隐形牙齿矫正器成型机中的应用

摘要&#xff1a;真空压力热成型技术作为一种精密成型工艺在诸如隐形牙套等制作领域得到越来越多的重视&#xff0c;其主要特点是要求采用高精度的正负压力控制手段来抵消重力对软化膜变形的影响以及精密控制成型膜厚度。本文提出了相应的改进解决方案&#xff0c;通过可编程的…

Greenplum数据库系统架构

Greenplum数据库系统架构 Greenplum是一个纯软件的MPP数据库服务器&#xff0c;其系统架构专门用于管理大规模分析型数据仓库或商业智能工作负载。从技术上讲&#xff0c;MPP无共享架构是指具有多个节点的系统&#xff0c;每个节点都有自己的内存、操作系统和磁盘&#xff0c;…

【天线专题】天线(Antenna)的理解

天线,英文名称是(Antenna),本义是指像蚂蚁、蜜蜂这样的小动物头顶上的触角。天线的作用就是将调制到射频频率的数字信号或模拟信号发射到空间无线信道,或从空间无线信道接收调制在射频频率上的数字或模拟信号。简单来说就是有发射和接收电磁波的功能。 所以两只蚂…

chatgpt赋能Python-python3_5怎么用

Python 3.5是什么? Python是一种高级编程语言&#xff0c;非常流行并广泛使用。Python3.5是Python编程语言的一个较新的版本&#xff0c;它具有许多新的功能和改进。Python 3.5已包含许多流行的Python框架。它可以用于各种任务&#xff0c;例如web开发&#xff0c;数据科学&a…

StableDiffusion模型发展历史

参考资料&#xff1a; 相应的github和huggingface LDM [github] StableDiffusion v1.1 ~ v1.4 [github] [huggingface] StableDiffusion v1.5 [huggingface] [github] StableDiffusion v2 v2.1 [github] [huggingface]   首先说一下&#xff0c;这篇文章的目的是让你清晰地了…

Django SQL注入漏洞 CVE-2022-28347

漏洞简介 在Django 2.2 的 2.2.28 之前版本、3.2 的 3.2.13 之前版本和 4.0 的 4.0.4 之前版本中的 QuerySet.deexplain() 中发现了SQL注入问题。这是通过传递一个精心编制的字典&#xff08;带有字典扩展&#xff09;作为**options参数来实现的&#xff0c;并将注入负载放置在…

[golang gin框架] 36.Gin 商城项目-RESTful API 设计指南,允许Cros跨域 ,提供api接口实现前后端分离,以及JWT的使用

一.RESTful API 设计指南 请看:Restful API 的接口规范 二.Gin 中配置服务器端允许跨域 github官方地址: https://github.com/gin-contrib/cors 在 main.go文件中配置跨域请求 代码如下: 在使用cors时,需要 引入该插件,先: import ( "github.com/gin-contrib/cors" )…

Cocos CreatorXR 1.2.0 今日发布,正式支持 WebXR ,并开启 MR 之路

去年九月&#xff0c;Cocos CreatorXR v1.0.1 版本支持了 VR 内容创作&#xff0c;成为率先支持 XR 的国产引擎&#xff0c;今年三月&#xff0c;Cocos CreatorXR v1.1.0 版本实现了对 AR 内容开发的支持。在完成基本功能的建设后&#xff0c;更多开发者开始尝试使用 Cocos Cre…

Linux内核oops panic简析

源码基于&#xff1a;Linux 5.4 0. 前言 内核异常的级别大致分为三个&#xff1a;BUG、oops、panic。 BUG 是指那些不符合内核的正常设计&#xff0c;但内核能够检测出来并且对系统运行不会产生影响的问题&#xff0c;比如在原子上下文中休眠&#xff0c;在内核中用 BUG 标识。…

case

[rootes3 data]# cat case11.sh #!/bin/bash. /etc/rc.d/init.d/functionsdisable_selinux(){sed -i s/SELNUXenforcing/SELINUXdisabled/ /etc/selinux/config action "SELINUX 已经禁用&#xff0c;重启生效" }disable_firewalld(){ systemctl disable --now firew…

chatgpt赋能Python-python3_9_1怎么打开

Python 3.9.1 使用指南&#xff1a;如何打开 Python 3.9.1 Python 3.9.1 是 Python 最新版本的一个分支&#xff0c;包含各种新特性和改进&#xff0c;能够让开发者快速、简单地创建并运行 Python 程序。如果您想要使用 Python 3.9.1&#xff0c;下面是一个简单的指南&#xf…

菜单选择shell

[rootes3 data]# vi action.sh #!/bin/bash . /etc/init.d/functionsecho -en "\E[$[RANDOM%731];1m"cat <<EOF请选择&#xff1a;1) 备份数据库2)清理日志3)软件升级4)软件回滚5)删库跑路EOFecho -en \E[0mread -p "请选择上面的项对应的数字1-5&#xf…

Spring Boot-如何让你的 bean 在其他 bean 之前完成加载

今天有个小伙伴给我出了一个难题&#xff1a;在 SpringBoot 中如何让自己的某个指定的 Bean 在其他 Bean 前完成被 Spring 加载&#xff1f;我听到这个问题的第一反应是&#xff0c;为什么会有这样奇怪的需求&#xff1f;Talk is cheap&#xff0c;show me the code&#xff0c…