Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring核心——数据校验

Spring核心——数据校验

作者头像
随风溜达的向日葵
发布于 2018-09-19 02:49:10
发布于 2018-09-19 02:49:10
75300
代码可运行
举报
文章被收录于专栏:技术墨客技术墨客
运行总次数:0
代码可运行

Java数据校验详解中详细介绍了Java数据校验相关的功能(简称Bean Validation,涵盖JSR-303、JSR-349、JSR-380),本文将在Bean Validation的基础上介绍Spring框架提供的数据校验功能。

Spring提供的数据校验功能分为2个部分,一个是Spring自定义的数据校验功能(以下称为Spring Validation),一个是符合Bean Validation规范的数据校验功能。

Spring Validation数据校验

Spring的自行开发的数据校验功能由3个部分组成:

  1. 校验器——Validator,他会运行校验代码。
  2. 校验对象,实际上就是一个JavaBean,Validator会对其进行校验。
  3. 校验结果——Errors,一次校验的结果都存放在Errors实例中。

这是Spring在Bean Validation规范制定之前就实现的数据校验功能,ValidationUtils的注释中@since标签是2003年5月6号,而JSR-303定稿时间已经是6年之后(2009年)的事了。

(文中仅为示例代码,可执行代码请到本人gitee库获取,本文代码在chkui.springcore.example.hybrid.springvalidation包中。)

Spring的数据校验功能就是实现检验器、校验对象、校验结果三个对象。先声明个一个校验对象(实体):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package chkui.springcore.example.hybrid.springvalidation.entity;
//车辆信息
public class Vehicle {
	private String name;
	private String type;
	private String engine;
	private String manufacturer;
	private Calendar productionDate; 

    /**Getter Setter*/
}

然后针对这个实体声明一个校验器。校验器要实现org.springframework.validation.Validator接口:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package chkui.springcore.example.hybrid.springvalidation.validator;

public class VehicleValidator implements Validator {
	private List<String> _TYPE = Arrays.asList(new String[] { "CAR", "SUV", "MPV" });

	public boolean supports(Class<?> clazz) {
        //将验证器和实体类进行绑定,如果这里返回false在验证过程中会抛出类型不匹配的异常
		return Vehicle.class.isAssignableFrom(clazz);
	}

	public void validate(Object target, Errors errors) { //验证数据
		Vehicle vehicle = Vehicle.class.cast(target);
		if (null == vehicle.getName()) {
            //使用验证工具绑定结果
			ValidationUtils.rejectIfEmpty(errors, "name", "name.empty", "车辆名称为空");
		}
		if (!_TYPE.contains(vehicle.getType())) {
            //向Error添加验证错误信息
			<2> errors.rejectValue("type", "type.error", "汽车类型必须是" + _TYPE);
		}
        //More validate ......
	}
}

有了验证对象(JavaBean)和对应的验证器(Validator)就完成了一组验证功能。注意VehicleValidator::validate方法传递的errors参数,验证工具会将错误实例传递进来交给开发者去组装验证结果。

代码中的ValidationUtils就是数据校验工具,他提供了2个功能:

  1. 执行校验(接下来会马上介绍)。
  2. 提供错误信息绑定的功能,例如ValidationUtils.rejectIfEmpty这一行代码。会将对应的信息写入到Errors中。

有了验证对象和验证器就可以执行验证:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SpringValidationApp {
	private static void springValidation(ApplicationContext ctx) {
		VehicleValidator vehicleValidator = new VehicleValidator();//创建验证器
		Vehicle vehicle = new Vehicle();//创建验证对象
		<1> ValidationError error = new ValidationError("Vehicle");//创建错误信息
		ValidationUtils.invokeValidator(vehicleValidator, vehicle, error);//执行验证
		List<FieldError> list = error.getFieldErrors();
		int count = 1;
        //输出验证结果
		for(FieldError res : list) {
			print("Error Info ", count++ , ".");
			print("Entity:", res.getObjectName());
			print("Field:", res.getField());
			print("Code:", res.getCode());
			print("Message:", res.getDefaultMessage());
			print("-");
		}
	}
}

执行完毕后,ValidationError中记录了所有校验错误信息。错误信息分为4个部分:

  • 验证的对象的名称:在执行验证器的代码中<1>部分创建错误对象时指定。Vehicle就是验证对象的名称。
  • 错误的域、错误code和错误信息:每一个错误都有对应的域、错误编码以及错误信息,在验证器<2>位置的代码就是指定错误信息。

以上错误信息可以通过error.getFieldErrors();来获取。

如果JavaBean有嵌套的结构,可以在校验器中调用其他的校验器来实现嵌套检验。先为Vehicle类增加一个Gearbox(变速箱)域:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package chkui.springcore.example.hybrid.springvalidation.entity;
//车辆信息
public class Vehicle {
	private String name;
	private String type;
	private String engine;
	private String manufacturer;
    private Gearbox gearbox; //Gearbox是另外一个实例
	private Calendar productionDate; 

    /**Getter Setter*/
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//变速箱
public class Gearbox {
	private String name;
	private String manufacturer;

    /**Getter Setter*/
}

在校验器VehicleValidator::validate中增加对Gearbox验证:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class VehicleValidator implements Validator {
	@Autowired
	GearboxValidator gearboxValidator; //用于校验Gearbox的校验器

	@Override
	public void validate(Object target, Errors errors) {
		Vehicle vehicle = Vehicle.class.cast(target);

		//some code ......
        
		}
		if(null == vehicle.getGearbox()) {
			errors.rejectValue("gearbox", "gearbox.error", "变速箱信息为空");
		}else {
            //指定子实体的名称
			errors.pushNestedPath("gearbox");
            //执行对Gearbox的校验
            ValidationUtils.invokeValidator(gearboxValidator, vehicle.getGearbox(), errors);
		}
	}
}

Bean Validation数据校验

Spring现在推荐使用Bean Validation来进行数据校验,而且已经整合到Spring MVC框架中。

在Spring中使用Bean ValidationJava数据校验详解一文中介绍的内容差不多——也是注解和校验器组成一个约束,通过注解来控制校验的过程。

Spring核心部分没有提供Bean Validation相关的实现类,所以需要引入对应的实现框架。本文引入的是Hibernate Validator,他包括验证器和el,详情可以看源码根目录的build.gradle文件。

首先我们向IoC容器中添加全局校验器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
public class SpringValidationConfig {

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

这一段添加Bean的代码非常简单,就是新建了一个LocalValidatorFactoryBean实例。LocalValidatorFactoryBean实现了javax.validation.Validator接口,并且会自动使用已经引入的Bean Validation框架。

然后向Vehicle增加Bean Validation相关的注解:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Vehicle {
	@NotBlank
	private String name;
	@NotBlank
	@VehicleType
	private String type;
	@NotBlank
	private String engine;
	@NotBlank
	private String manufacturer;
	<3> @Valid //@Valid的作用是对嵌套的解构进行校验
	private Gearbox gearbox;
	@Valid
	private Tyre tyre;
	@VehicleProductionDate
	private Calendar productionDate;

    /**Getter Setter*/

}

在上面的代码中,除了常规的@NotBlank等注解,还有@VehicleType这个自定义注解。在代码<3>的位置@Valid是告诉校验器还要对gearbox的实例进行校验,相当于前面介绍的嵌套校验功能。最后我们使用检验器来对Vehicle的实例进行校验:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SpringValidationApp {
	public static void main(String[] args) {
		ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringValidationConfig.class);
		BeanValidation(ctx);//JSR规范验证
	}

	private static void BeanValidation(ApplicationContext ctx) {
		Validator validator = ctx.getBean(Validator.class);//获取校验器
		Vehicle vehicle = new Vehicle();//新建要校验的对象
		validator.validate(vehicle).forEach(err -> { //执行校验
			print("Field: ", err.getPropertyPath());
			print("Error: ", err.getMessage());
		});
	}
}

关于Bean Validation的详细使用方法已经在 Java数据校验详解介绍。

兼容Bean Validation和Spring Validation

一些相对比较久远的项目可能会遇见在Spring Validation的基础上新增Bean Validation功能的情况。可以使用SpringValidatorAdapter适配器来解决这个问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SpringValidationApp {

	private static void adapterValidation(ApplicationContext ctx) {
		// 获取校验器
		// LocalValidatorFactoryBean继承了SpringValidatorAdapter
        // 所以这里就是获取LocalValidatorFactoryBean
		SpringValidatorAdapter adapter = ctx.getBean(SpringValidatorAdapter.class);

		Vehicle vehicle = new Vehicle();// 检验对象
		ValidationError error = new ValidationError("Vehicle");
		
		// Spring Validation
		ValidationUtils.invokeValidator(adapter, vehicle, error);//执行校验
		List<FieldError> list = error.getFieldErrors();//检验信息

		// Bean Validation 校验
		adapter.validate(vehicle).forEach(err -> { // 执行检验&输出校验结果
			print("Field: ", err.getPropertyPath());
			print("Error: ", err.getMessage());
		});
	}
}

上面的代码使用SpringValidatorAdapter分别执行了Bean ValidationSpring Validation。可以将SpringValidatorAdapter看作一个org.springframework.validation.Validator的实现类用ValidationUtils来执行校验,而验证的过程完全是按照Bean Validation的规范来执行的。

方法参数校验

除了校验一个实体类,Spring在Bean Validation的基础上使用后置处理器和AOP实现了方法参数的检验。例如下面的方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface PersonService {
	public @NotBlank String execute(@NotBlank(message = "必须设置人员名称") String name,
			@Min(value = 18, message = "年龄必须大于18") int age);
}

他表示返回数据不能为空字符串,传入的2个参数name不能为空字符串、age必须大于18。

要启用方法参数校验关键点是引入MethodValidationPostProcessor并在需要验证的Bean上增加一个@Validated注解。

先通过@Configuration引入后置处理器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Configuration
@ComponentScan("chkui.springcore.example.hybrid.springvalidation.service")
public class SpringValidationConfig {
	@Bean("validator")
	public Validator validator() {
		return new LocalValidatorFactoryBean();
	}

	@Bean
	public MethodValidationPostProcessor methodValidationPostProcessor(Validator validator) {
		MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
		postProcessor.setValidator(validator);
		return postProcessor;
	}
}

然后实现上面的PersonService接口并标记@Validated表示这个类中的方法要进行参数校验:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Service
@Validated
public class PersonServiceImpl implements PersonService {

	@Override
	public String execute(String name, int age) {
		return "I'm " + name + ". " + age + " years old.";
	}
}

最后使用这个Service:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class SpringValidationApp {

	public static void main(String[] args) {
		ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringValidationConfig.class);
		methodValidation(ctx);//方法参数校验
	}
	
	private static void methodValidation(ApplicationContext ctx) {
		//对方法进行参数校验
		try {
			PersonService personService = ctx.getBean(PersonService.class);
			personService.execute(null, 1);//传递参数
		} catch (ConstraintViolationException error) {
			error.getConstraintViolations().forEach(err -> {//输出校验错误信息
				print("Field: ", err.getPropertyPath());
				print("Error: ", err.getMessage());
			});
		}
	}
}

在运行的过程中,如果参数或返回数据不符合验证规则会抛出ConstraintViolationException异常,可以从中获取校验错误的信息。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring官网阅读(十七)Spring中的数据校验
从官网中的截图我们可以看到,Bean Validation 2.0的唯一实现就是Hibernate Validator,对应版本为6.0.1.Final,同时在2.0版本之前还有1.1(JSR 349)及1.0(JSR 303)两个版本,不过版本间的差异并不是我们关注的重点,而且Bean Validation 2.0本身也向下做了兼容。
程序员DMZ
2020/07/06
2K0
【Spring】掌握 Spring Validation 数据校验
      在开发中,我们经常遇到参数校验的需求,比如用户注册的时候,要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。       如果使用普通方式,我们会把校验的代码和真正的业务处理逻辑耦合在一起,而且如果未来要新增一种校验逻辑也需要在修改多个地方。       而spring validation允许通过注解的方式来定义对象校验规则,把校验和业务逻辑分离开,让代码编写更加方便。       Spring Validation其实就是对Hibernate Validator进一步的封装,方便在Spring中使用。
.29.
2023/10/17
5770
【Spring】掌握 Spring Validation 数据校验
spring数据校验:Validation
在开发中,我们经常遇到参数校验的需求,比如用户注册的时候,要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式,我们会把校验的代码和真正的业务处理逻辑耦合在一起,而且如果未来要新增一种校验逻辑也需要在修改多个地方。而spring validation允许通过注解的方式来定义对象校验规则,把校验和业务逻辑分离开,让代码编写更加方便。Spring Validation其实就是对Hibernate Validator进一步的封装,方便在Spring中使用。在Spring中有多种校验的方式
一个风轻云淡
2023/10/15
3220
spring数据校验:Validation
Spring6 数据校验 Validation
在开发中,经常遇到参数校验的需求,比如用户注册的时候,要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式,会把校验的代码和真正的业务处理逻辑耦合在一起,而且如果未来要新增一种校验逻辑也需要在修改多个地方。而spring validation允许通过注解的方式来定义对象校验规则,把校验和业务逻辑分离开,让代码编写更加方便。Spring Validation其实就是对Hibernate Validator进一步的封装,方便在Spring中使用。
鱼找水需要时间
2023/06/22
3410
Spring6 数据校验 Validation
详述Spring对Bean Validation支持的核心API:Validator、SmartValidator、LocalValidatorFactoryBean...【享学Spring】
浩浩荡荡的把一般程序员都不太关注的Bean Validation话题讲了这么久,期间小伙伴wx我说一直还没看到他最想看到的内容,我问最想看到啥?他说显然是数据校验在Spring中的使用啊。我想若不出意外,这应该是众多小伙伴的共同心声吧,但路漫漫其修远兮,也得上下求索,本文将切入到最关心的Spring中来~
YourBatman
2019/09/03
3.5K0
详述Spring对Bean Validation支持的核心API:Validator、SmartValidator、LocalValidatorFactoryBean...【享学Spring】
Java数据校验详解
一个健壮的系统都要对外部提交的数据进行完整性、合法性的校验。即使开发一个不面对最终用户的工具包,也需要对传入的数据进行缜密的校验来防止引发底层难以追踪的问题。各路大神当然也会注意到这个问题,所以在“元编程”(见JSR250与资源控制)提出之后相续提交了JSR-303、JSR-349以及JSR-380来完善使用注解进行数据校验的机制,这三个JSR也被称为Bean Validation 1.0、Bean Validation 1.1和Bean Validation 2.0,后文统称为Bean Validation。
随风溜达的向日葵
2018/08/22
1.2K0
Spring方法级别数据校验:@Validated + MethodValidationPostProcessor优雅的完成数据校验动作【享学Spring】
你在书写业务逻辑的时候,是否会经常书写大量的判空校验。比如Service层或者Dao层的方法入参、入参对象、出参中你是否都有自己的一套校验规则?比如有些字段必传,有的非必传;返回值中有些字段必须有值,有的非必须等等~
YourBatman
2019/09/03
2.7K0
Spring方法级别数据校验:@Validated + MethodValidationPostProcessor优雅的完成数据校验动作【享学Spring】
SpringMVC的架构有什么优势?——表单和数据校验(四)
Spring MVC提供了一种方便的机制来将表单数据绑定到JavaBean对象上,以便进行验证和处理。 表单数据绑定是Spring MVC框架中一种非常重要的机制,它允许开发者将HTTP请求中的表单数据自动绑定到JavaBean对象上,并进行验证和处理。这使得开发者能够更加方便地编写Web应用程序,同时减少了重复代码的数量。
一只
2024/06/26
1630
详解java参数校验之:顺序校验、自定义校验、分组校验(@Validated @GroupSequence)
当使用 @Validated、@GroupSequence 和自定义校验规则时,可以实现对实体类属性的分组校验
公众号:码到三十五
2024/03/19
1.4K0
SpringMVC笔记(10):数据校验
Spring MVC提供了两种数据校验的方式:1.基于Validator接口,2.使用Annotaion JSR-303标准进行校验。
南风
2018/12/27
1K1
两种方式实现Spring 业务验证
验证在任何时候都非常关键。考虑将数据验证作为业务逻辑开发有利也有弊,Spring 认为,验证不应该只在Web 端进行处理,在服务端也要进行相应的处理,可以防止脏数据存入数据库中,从而避免为运维同学和测试同学造成更大的困扰,因为数据造成的bug会更加难以发现,而且开发人员关注点也不会放在数据本身的问题上,所以做服务端的验证也是非常有必要的。考虑到上面这些问题,Spring 提供了两种主要类型的验证:
cxuan
2019/09/19
8270
两种方式实现Spring 业务验证
让Controller支持对平铺参数执行数据校验(默认Spring MVC使用@Valid只能对JavaBean进行校验)【享学Spring】
我们知道Spring MVC层是默认可以支持Bean Validation的,但是我在实际使用起来有很多不便之处(相信我的使用痛点也是小伙伴的痛点),就感觉它是个半拉子:只支持对JavaBean的验证,而并不支持对Controller处理方法的平铺参数的校验。
YourBatman
2019/09/03
1.1K0
让Controller支持对平铺参数执行数据校验(默认Spring MVC使用@Valid只能对JavaBean进行校验)【享学Spring】
Spring:全面拥抱 Jakarta Bean Validation 规范
随着JSR-303、JSR-349和JSR-380提案的相继问世,Bean Validation 规范已经从初出茅庐的 1.0 版本发展到渐入佳境的 2.0 版本。在 Eclipse 基金会接管 Java EE 之后,Bean Validation 规范成为了 Jakarta EE 的一部分,Jakarta Bean Validation 自然也就成为 Bean Validation 的新标准,目前 Jakarta Bean Validation 最新版为 3.0。Jakarta Bean Validation 目前由 Hibernate 实现,Apache BVal 感觉有些掉队了。
程序猿杜小头
2023/09/02
2.6K0
Spring:全面拥抱 Jakarta Bean Validation 规范
使用spring validation完成数据后端校验
前言 数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,如果数据库中出现一个非法的邮箱格式,也会让运维人员头疼不已。我在之前保险产品研发过程中,系统对数据校验要求比较严格且追求可变性及效率,曾使用drools作为规则引擎,兼任了校验的功能。而在一般的应用,可以使用本文将要介绍的validatio
kirito-moe
2018/04/27
3.2K0
使用spring validation完成数据后端校验
Spring MVC各组件近距离接触--中--03
前面一节,我们已经把自由挥洒派的两个类进行了详细的介绍,下面我们来看看规范操作派。
大忽悠爱学习
2022/08/23
4110
Spring MVC各组件近距离接触--中--03
聊聊springboot项目如何优雅进行数据校验
在我们日常开发中,数据校验是我们绕不开的一环,而用Spring Validation进行校验,基本上成为我们进行数据校验的首选组件,今天的话题就来聊下如何利用Spring Validation进行优雅校验
lyb-geek
2024/12/31
2050
聊聊springboot项目如何优雅进行数据校验
Spring Security(使用hibernate-validator)
hibernate-validator是Hibernate项目中的一个数据校验框架,是Bean Validation 的参考实现。使用hibernate-validator能够将数据校验从业务代码中脱离出来,增加代码可读性,同时也让数据校验变得更加方便、简单。如果参数不能通过校验,报400错误,请求格式不正确。
用户7386338
2020/05/29
1.1K0
springmvc之如何对表单数据进行校验
2、spring在进行数据绑定时,可同时调用校验框架完成数据校验工作。在springmvc中,可直接通过注解驱动的方式进行数据校验。
西西嘛呦
2020/08/26
7500
springmvc之如何对表单数据进行校验
SpringBoot整合JSR303实现参数校验
不知不觉Spring Boot专栏文章已经写到第十四章了,无论写的好与不好,作者都在尽力写的详细,写的与其它的文章不同,每一章都不是浅尝辄止。如果前面的文章没有看过的朋友,点击这里前往。
爱撒谎的男孩
2020/10/29
3.1K0
Spring MVC框架:第十四章:数据校验
在Web应用三层架构体系中,表述层负责接收浏览器提交的数据,业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理,我们需要在表述层对数据进行检查,将错误的数据隔绝在业务逻辑层之外。
Java廖志伟
2022/09/28
4470
Spring MVC框架:第十四章:数据校验
推荐阅读
相关推荐
Spring官网阅读(十七)Spring中的数据校验
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验