SpringMVC教程之数据绑定流程分析

一、前言

在SpringMVC中会将来自web页面的请求和响应数据与controller中对应的处理方法的入参进行绑定,即数据绑定。流程如下:

  • SpringMVC主框架将ServletRequest对象及目标方法的入参实例传递给WebDataBinderFactory实例,以创建DataBinder实例对象
  • DataBinder对象调用装配在SpringMVC上下文中的ConversionService组件进行数据类型转换,数据格式化工作,将Servlet中的请求信息填充到入参对象中。
  • 调用Validator组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData对象
  • SpringMVC抽取BindingResult中的入参对象和校验错误对象,将它们赋给处理方法的相应入参。

总结起来:大致流程是  数据转换(conversionService)–>校验(validators)–>绑定(bindingResult)

下面我们通过相关代码来梳理一下整个数据绑定流程。

二、案例

♦新建产品录入界面welcome.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试页面</title>
</head>
<body>
	<form action="product/saveProduct" method="Post">
		编码: <input type="text" name="number" value=""/>
		<br>
		库存: <input type="text" name="qty" value=""/>
		<br>
		<input type="submit" value="提交"/>
	</form>
</body>
</html>

♦响应输出界面product.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>success</title>
</head>
<body>
	${product }
</body>
</html>

♦新建控制器处理类ProductHandler

/**
 * @author queen
 * @since 2017-11-12
 */
@RequestMapping("/product")
@Controller
public class ProductHandler {
	//模拟保存产品信息操作
	@RequestMapping(value = "/saveProduct", method = RequestMethod.POST)
	public String saveProduct(Product product) {
		System.out.println("保存产品:" + product);
		return "product";
	}
}

♦新建Product实体类

/**
 * @author queen
 * @since 2017-11-12
 */
public class Product {
	// 编码
	private String number;
	// 库存
	private Integer qty;

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}

	public Integer getQty() {
		return qty;
	}

	public void setQty(Integer qty) {
		this.qty = qty;
	}

	@Override
	public String toString() {
		return "Product [number=" + number + ", qty=" + qty + "]";
	}

}

♦启动服务运行,进入访问界面

SpringMVC教程之数据绑定流程分析的照片 - 1

在ModelAttributeMethodProcessor的resolveArgument方法101行处打上断点,Debug走起

SpringMVC教程之数据绑定流程分析的照片 - 3

继续F8,Debug往下走,这段方法里面我们主要关注的是108行到117行之间的代码,下面对这部分代码进行相关说明

//绑定器工厂根据当前请求,其他信息;创建出数据绑定器;数据绑定器负责将请求中的数据绑定到pojo中
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
	//数据绑定期间进行类型转换以及格式化工作,调用装配在SpringMVC上下文中的
	//ConversionService组件进行数据类型转换、
	//数据格式化工作。将Servlet中的请求信息填充到入参对象中
	bindRequestParameters(binder, webRequest);
	//进行数据校验,调用Validator组件对已经绑定了请求消息的入参对象进行数据合法性校验,
	//并最终生成数据绑定结果到BindingResult组件中封装错误信息;
	validateIfApplicable(binder, parameter);
	//数据校验错误信息处理
	if (binder.getBindingResult().hasErrors()) {
		//如果出错处理
		if (isBindExceptionRequired(binder, parameter)) {
			throw new BindException(binder.getBindingResult());
		}
	}
}

Debug到110行,这时候我们发现product还没有被赋值,这里的product是目标参数,是new出来的一个对象

SpringMVC教程之数据绑定流程分析的照片 - 5

执行完这段方法后,数据被绑定到了实体上

SpringMVC教程之数据绑定流程分析的照片 - 7

在bindRequestParameters方法执行的过程中,会涉及到数据类型转换的问题。默认的SpringMVC上下文中内置了很多转换器,可以完成大多数Java类型的转换工作。默认使用的是DefaultFormattingConversionService转换器

SpringMVC教程之数据绑定流程分析的照片 - 9

默认的转换器有如下:

  • java.lang.Boolean -> java.lang.String : –org.springframework.core.convert.support.ObjectToStringConverter@f874ca
  • java.lang.Character -> java.lang.Number : CharacterToNumberFactory@f004c9
  • java.lang.Character -> java.lang.String : ObjectToStringConverter@68a961
  • java.lang.Enum -> java.lang.String : EnumToStringConverter@12f060a
  • java.lang.Number -> java.lang.Character : NumberToCharacterConverter@1482ac5
  • java.lang.Number -> java.lang.Number : NumberToNumberConverterFactory@126c6f
  • java.lang.Number -> java.lang.String : ObjectToStringConverter@14888e8
  • java.lang.String -> java.lang.Boolean : StringToBooleanConverter@1ca6626
  • java.lang.String -> java.lang.Character : StringToCharacterConverter@1143800
  • java.lang.String -> java.lang.Enum : StringToEnumConverterFactory@1bba86e
  • java.lang.String -> java.lang.Number : StringToNumberConverterFactory@18d2c12
  • java.lang.String -> java.util.Locale : StringToLocaleConverter@3598e1
  • java.lang.String -> java.util.Properties : StringToPropertiesConverter@c90828
  • java.lang.String -> java.util.UUID : StringToUUIDConverter@a42f23
  • java.util.Locale -> java.lang.String : ObjectToStringConverter@c7e20a
  • java.util.Properties -> java.lang.String : PropertiesToStringConverter@367a7f
  • java.util.UUID -> java.lang.String : ObjectToStringConverter@112b07f ……

本案例中,库存qty界面传过来的时候是字符串,但是实体里面接收的是Integer类型的,那么这个过程中使用了StringToNumberConverterFactory该类型转换器,进行了自动转换操作。会调用如下:

SpringMVC教程之数据绑定流程分析的照片 - 11

F8走完,进入111行,进行数据校验,本例子中校验器为空,故没有

SpringMVC教程之数据绑定流程分析的照片 - 13
Spring MVC 通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是
DataBinder,运行机制如下:

SpringMVC教程之数据绑定流程分析的照片 - 15

至此,我们关于SpringMVC教程之数据绑定流程分析介绍完毕。想要了解更多关于SpringMVC开发的教程,请参考http://www.marsitman.com/springmvc
博客地址:http://www.marsitman.com/springmvc/springmvc-databinder-analyse.html
版权声明:本文为博主原创文章,允许转载,但转载必须标明出处。

 

 

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!



点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注