8.Spring服务器端数据校验(JSR-303)

目录


Spring MVC专栏目录(点击进入…)



数据校验(服务端数据校验)

数据校验:①客户端校验、②服务器端校验

在Spring MVC 框架中有两种方法可以验证输入数据,一种是利用Spring自带的验证框架,另一种是利用JSR 303实现验证,推荐使用JSR 303验证。
1.前端校验要做,目的是为了提高用户体验
2.后端校验也要做,目的是为了数据安全

(1)客户端校验

主要是通过过滤正常用户的误操作,是第一道防线,一般使用JavaScript代码实现。但是只有客户端校验是不够的,攻击者可以绕过客户端验证直接进行非法输入,这样可能会引起系统异常,为了确保数据的合法性,防止用户通过非正常手段提交错误信息,必须加上服务器端验证

(2)服务器端校验

整个应用阻止非法数据的最后一道防线,通过应用中的编程实现。服务器端验证对于系统的安全性、完整性、健壮性起到了至关重要的作用。在Spring MVC 框架中可以利用Spring自带的验证框架验证数据,也可以利用JSR 303实现数据验证

服务端校验
(1)控制层Conroller:校验页面请求的参数的合法性。在服务端控制层Controller校验,不区分客户端类型(浏览器、手机客户端、远程调用)
(2)业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数
(3)持久层dao:一般是不校验的


Spring MVC服务器端校验方式

在Spring MVC中有两种方式可以验证输入
(1)利用Spring自带的验证框架
(2)利用JSR 303实现


JSR 303介绍

JSR 303(Java Specification Requests)是Java为Bean数据合法性校验所提供的标准框架。JSR 303通过在Bean属性上标注类似于@NotNull、@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证。

Bean Validation为JavaBean验证定义了相应的元数据模型和API。缺省的元数据是Java Annotations,通过使用XML可以对原有的元数据信息进行覆盖和扩展。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint(约束),例如 @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。

JSR 303 的发布使得在数据自动绑定和验证变得简单,使开发人员在定义数据模型时不必考虑实现框架的限制。当然 Bean Validation 还只是提供了一些最基本的 constraint,在实际的开发过程中,用户可以根据自己的需要组合或开发出更加复杂的constraint。

下载http://jcp.org/en/jsr/detail?id=303
官网下载http://hibernate.org/validator

注意:Spring本身没有提供对JSR 303的实现,Hibernate Validator实现了JSR 303,所以必须在加入来自Hibernate Validator库的jar文件

导入其中三个即可,Spring将会自动加载并装配

hibernate-validator-版本.Final
jboss-logging-版本.CR
validator-api版本.GA

JSR 303内置约束
JSR 303不需要编写验证器,它定义一套可标注在成员变量、属性方法上的校验注解。

约束说明
@Null被注释的元素必须为null
@NotNull被注释的元素必须不为null
@AssertTrue被注释的元素必须为true
@AssertFalse被注释的元素必须为false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimaMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimaMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max,min)被注释的元素大小必须在指定的范围内
@Digits(integer,fraction)被注释的元素必须是一个数字,其值必须在课街火速的范围内
@Past被注释的元素必须是一个过去的日期
@Futrue被注释的元素必须是一个将来的日期
@Pattern(value)被注释的元素必须符合指定的正则表达式

Spring MVC支持JSR 303标准的校验框架,Spring的DataBinder在进行数据绑定时,可同时调用数据校验框架来完成数据校验工作,非常简单方便。在Spring MVC中,可以直接通过注解驱动的方式来进行数据校验。


Hibernate Validator附加的constraint

约束(constraint)说明
@Email被注释的元素必须是电子邮箱地址
@Length被注释的字符串的大小必须在指定的范围内
@NotEmpty被注释的字符串的必须非空
@Range被注释的元素必须在合适的范围内

一个constraint通常由annotation和相应的constraint validator组成,它们是一对多的关系。也就是说可以有多个constraint validator对应一个annotation。在运行时,Bean Validation框架本身会根据被注释元素的类型来选择合适的constraint validator对数据进行验证。

有些时候,在用户的应用中需要一些更复杂的constraint。Bean Validation提供扩展constraint的机制。可以通过两种方法去实现。
(1)一种是组合现有的constraint来生成一个更复杂的constraint
(2)另外一种是开发一个全新的constraint


使用步骤

(1)导包

在这里插入图片描述

<!-- JSR 303 -->
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-validator</artifactId>
	<version>5.4.3.Final</version>
</dependency>

(2)配置校验器到处理器适配器

<!-- 校验器注入到处理器适配器中 -->
<mvc:annotation-driven validator="validator"/>

<!-- 校验器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
	<!-- Hibernate校验器 -->
	<property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
	<!-- 指定校验使用的资源文件,在文件中配置校验错误信息,如果不指定则默认使用classpath下的ValidationMessages.properties -->
	<property name="validationMessageSource" ref="messageSource"></property>
</bean>

<!-- 校验外置配置文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
	<!-- 资源文件名 -->
	<property name="basenames">
		<list>
			<value>classpath:ValidationMessages.properties</value>
		</list>
	</property>
	<!-- 资源文件编码格式 -->
	<property name="fileEncodings" value="utf-8"></property>
	<!-- 对资源文件内容缓冲时间,单位秒 -->
	<property name="cacheSeconds" value="120"></property>
</bean>

(3)增加校验规则

public class User {
	@Length(min = 2, max = 5,message = "长度大于等于2小于等于5!")
	private Integer id;
	@NotNull(message = "{user.error.name.NotNull}")
	private String name;
	private String address;
	private String email;
}

(4)ValidationMessages(文件编码格式跟JSP页面一致)

user.error.name.NotNull=姓名不能为空

(5)Handler控制器测试

@Controller
public class UserController {
	@RequestMapping("/user")
	public String UserTest(Model model, @Valid User user, BindingResult bindingResult) {
		if (bindingResult.hasErrors()) { //有错误信息
			List<ObjectError> allErrors = bindingResult.getAllErrors();
			for (ObjectError objError : allErrors) {
				// 输出错误信息
				System.out.println(objError.getDefaultMessage());
			}
			model.addAttribute("allErrors", allErrors);  //发送至页面
			return "message";
		}
		// 没有错误信息,省略……
		return "逻辑视图名";
	}
}

Controller相关设置,model前添加@Valid注解;Controller的方法中@valid对应的@ModelAttribute参数与bindingResult之间不能有参数,它们必须紧挨在一起,否则报错;

需要在Handler(Controller)中加入BindingResult对象,接收校验出错信息;否则会直接报错。

@Valid是javax.validation里的。@Validated是@Valid的一次封装,是Spring提供的校验机制使用。

相比@Valid;@Validated提供了几个新功能
(1)可以通过groups对验证进行分组
(2)按照序列组来验证
(3)验证多个实体


分组校验

1.校验规则(增加组标识)

public class User {
	private int id;
	
	@NotEmpty(message = "{user.error.name.NotNull}", groups = UserVov1.class)
	private String name;
	
	@NotEmpty(message = "{user.error.address.NotNull}")
	private String address;
	
	@Email(message = "必须是邮箱!")
	private String email;
	
	// 省略getter/setter方法...
	public interface UserVov1{};
	public interface UserVov2{};
	public interface UserVov3{};
	
}

2.定义一个接口类(增加分组)

@GroupSequence(value = {User.UserVov1.class,User.UserVov2.class})
public interface GroupbyName {
	// 不需要定义任何方法,仅对校验进行分组
	//目的:在pojo类中定义了校验规则;只校验部分内容
}

3.Handler(Controller)中使用

@RequestMapping("/groups")
public String groups(@Validated(value = GroupbyName.class) User user) {
	return "groups_ok";
}

自定义验证类

(1)自定义注解

至少需要包含message()、groups()、payload()

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = { IsRightValidator.class })
public @interface IsRight {
	boolean right() default true;
	String message() default "这是验证失败的提示信息";
	Class<?>[] groups() default {};
	Class<? extends Payload>[] payload() default {};
}

(2)自定义注解校验器类

继承ConstraintValidator类<注解类,注解参数类型> ,重写两个方法(initialize:初始化操作、isValid:逻辑处理)

IsRight注解校验类

public class IsRightValidator implements ConstraintValidator<IsRight, String> {
	private boolean right= false;
	
	@Override
	public void initialize(IsRight constraintAnnotation) {
		right = constraintAnnotation.right();
	}
	
	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
		if (right) {
			return true;
		} else {
			return false;
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值