SpringMVC 实现数据绑定

SpringMVC 会根据请求方法签名不同,将请求消息的消息以一定的方式转换并绑定到请求的参数中。在请求消息到达真正处理方法之前的这一段时间内,SpringMVC需要完成请求消息转换,数据转换,格式化,数据校验等

1.数据绑定流程

SpringMVC 框架将ServletRequest 对象(HttpServletRequest 为其子类)以及处理方法的参数对象实例传递给DataBinder,DataBinder 调用Spring web 上下文的ConversionService 数据组件进行数据转换,并将ServletRequest 中消息填充到参数对象中,然后调用Validator组件进行数据合法性验证,最总生成的BindingResult 对象包含已完成转换的参数对象和校验错误对象。

2.数据转换

1.org.springframework.core.convert.ConversionService 是Spring类型转换体系中的核心接口,可以利用org.springframework.context.support.ConversionServiceFactoryBeanzai 在Spring上下文中定义一个ConversionService,Spring 将自动识别上下文中的Conversion Service,并在SpringMVC 处理方法的参数绑定中使用它进行数据转换。实例代码:

<bean id = "conversionService" class ="org.springframework.context.support.ConversionServiceFactoryBean"/>

在ConversionServiceFactoryBean中内置了多种类型转换器,可以完成大多数类型的转换,此外可以通过ConversionServiceFactoryBean中converters属性注册自定义类型转换器.

<!-- 装配自定义类型转换器 -->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--自定义类型转换器-->
<bean id="conversionService" 
	class="org.springframework.context.support.ConversionServiceFactoryBean">
	<property name ="converters">
		<list>
			<!--自己编写的转换器类-->
			<bean class="org...StringtoDataConverter" 
			p:dataPattern="yyyy-MM-dd"></bean>
		</list>
	</property>
</bean>
public class StringToDateConverter implements Converter<String,Date>{
	private String dataPattern;
	@Override
	public Date Convert(String date){
	...
	}

拓展:Spring 3.0.x中使用了mvc:annotation-driven后,默认会帮我们注册默认处理请求,参数和返回值的类,其中最主要的两个类:DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter ,分别为HandlerMapping的实现类和HandlerAdapter的实现类,从3.1.x版本开始对应实现类改为了RequestMappingHandlerMapping和RequestMappingHandlerAdapter。

2.在控制器的任何处理方法中使用这个转换器

3.此外我们可以在Controller 类中新增一个initBinder()方法,并使用@initBinder注解,该注解将在控制器初始化是注册属性编辑器。

//自定义属性编辑器
public class DateEditor extends PropertyEditorSupport{
	@Override
	public void setAsText(String text) throws IllegalArgumentException{
	...
	}
}
@InitBinder
public void initBinder(WebDataBinder binder){
 	binder.registerCustomEditor(Date.class, new DateEditor);
 }
数据校验

输入校验分为客户端校验和服务端校验,客户端校验主要是过来正常用户的误操作,服务器端校验组织非法数据

Spring 拥有自己独立的数据校验框架 位于org.springframework.validation 包中。而位于org.springframework.validation.beanvalidation包中,LocalValidatorFactoryBean类实现了Spring Validator接口同时也实现了JSR 303的validator 接口,因此只需要在Spring容器中定义一个LocalValidatorFactoryBean即可注入到有需要的bean中完成数据校验。spring-boot-starter-web包里面有hibernate-validator包,所以如果开发 web 就不需要重复添加 spring-boot-starter-validation 依赖了。但如果没用 web 依赖时候想要实现 Bean 验证,则只要单单加入 spring-boot-starter-validation 依赖即可。

< mvn:nnotation-driven/>会默认装配好一个LocalValidatorFactoryBean ,所以在实际开发过程中不需要手动配置LocalValidatorFactoryBean。

1.validation 校验框架

位于org.Springframework.validation ,重要接口和类定义如下

  • Validator 接口:提供两个方法
    Boolean supports(Class< ?> clazz):对clazz 类型的对象进行校验
    void validate(Object targe,Errors errors):对目标类target 进行校验
  • Error接口:存放错误信息
  • LocalValidatorFactoryBean:该类实现了Spring的Validator 接口,也实现了JSR303 的Validator接口,只要在容器中定义一个LcoalValidatorFactorybean ,既可以注册到数据校验的Bean 中。< mvc:annotation-driven/> 默认装配好LocalValidatorFactoryBean.

实例:实现Spring的Validator 接口,生成校验bean完成对象的校验

@Repository("userValidator")
public class UserValidator implements validator{
	public boolean supports(Class<?> clazz){
	...}
	public void validate(Object target,Error errors){
		ValidationUtils.rejectIfEmpty(errors,"loginname",null,"登陆名不能为空")

通过@Repository(“userValidator”)注解将该对象注释为Spring容器中一个bean,名字为”userValidator"

@Autowired
@Qualifier("uservalidator")
private UserValidator userValidator;

@requestmapping(value="/login")
public static login(
	@ModelAttribute User user,
	Model model,
	Errors errors){
	userValidator.validate(user,errors);
	...
	}
2.JSR303

JSR303 是Java 为Bean数据合法性校验提供一个标准规范,用于对java Bean 中字段值进行校验,通过在Bean 属性上标注类似@NotNull 指定校验规则,通过校验接口实现对bean 校验(可以自定义注解)

//constraint 注解
@Documented
@Target({ ANNOTATION_TYPE })
@Retention(RUNTIME)
public @interface Constraint {
    Class<? extends ConstraintValidator<?, ?>>[] validatedBy();

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

//ConstraintValidator 接口
public interface ConstraintValidator<A extends Annotation, T> {
    void initialize(A constraintAnnotation);
    boolean isValid(T value, ConstraintValidatorContext context);

第一个是我们的注解,也就是我们自己定义的注解,第二个是参数的值
ConstraintValidator是一个接口,也就是我们自己定义的校验类要实现这个接口

例如 我们 校验手机号,可以写一个 @Mobile的注解

import java.lang.annotation.Target;
 
import javax.validation.Constraint;
import javax.validation.Payload;
 
import miaosha.validator.MobileValidator;
 
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
 
/**
 * 做一个mobile的注解 注意我们使用的静态导入
 * 
 * @author kaifeng1
 *
 */
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { MobileValidator.class })
public @interface Mobile {
	boolean required() default true;
 
	String message() default "手机号码格式错误";
 
	Class<?>[] groups() default {};
 
	Class<? extends Payload>[] payload() default {};
}

需要自定义一个校验器 MobileValidator,它使用 ValidatorUtil来完成校验的具体逻辑

MobileValidator.java

package miaosha.validator;
 
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
 
import org.apache.commons.lang3.StringUtils;
 
import miaosha.annotation.Mobile;
import miaosha.util.ValidatorUtil;
 
public class MobileValidator implements ConstraintValidator<Mobile, String> {
	private boolean required = false;
	/**
	 * 初始化
	 */
	 @Override
	public void initialize(Mobile constraintAnnotation) {
		required = constraintAnnotation.required();
	}
 
	/**
	 * 校验
	 */
	 @Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
		if (required) {
			return ValidatorUtil.isMobile(value);
		} else {
			if (StringUtils.isEmpty(value)) {
				return true;
			} else {
				return ValidatorUtil.isMobile(value);
			}
		}
	}
 
}


ValidatorUtil.java


package miaosha.util;
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import org.apache.commons.lang3.StringUtils;
 
/**
 * 校验
 * 
 * @author 
 *
 */
public class ValidatorUtil {
 
	private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");
 
	public static boolean isMobile(String src) {
		if (StringUtils.isEmpty(src)) {
			return false;
		}
		Matcher m = mobile_pattern.matcher(src);
		return m.matches();
	}
}

我们使用该注解的时候:

	@Mobile
	private String mobile;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值