数据交换
数据绑定流程
- Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinderFactory 实例,以创建 DataBinder 实例对象
- DataBinder 调用装配在 Spring MVC 上下文中的ConversionService 组件进行数据类型转换、数据格式化工作。将 Servlet 中的请求信息填充到入参对象中
- 调用 Validator 组件对已经绑定了请求消息的入参对象进行数据合法性校验,并最终生成数据绑定结果BindingData 对象
- Spring MVC 抽取 BindingResult 中的入参对象和校验错误对象,将它们赋给处理方法的响应入参
- Spring MVC 通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。数据绑定的核心部件是DataBinder,运行机制如下:
Spring MVC 上下文中内建了很多转换器,可完成大多数 Java 类型的转换工作ConversionService converters =
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.Number -> java.lang.Character : NumberToCharacterConverter@1482ac5
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
……
自定义类型转换器
- ConversionService 是 Spring 类型转换体系的核心接口。
- 可以利用 ConversionServiceFactoryBean 在 Spring 的 IOC容器中定义一个 ConversionService. Spring 将自动识别出IOC 容器中的 ConversionService,并在 Bean 属性配置及Spring MVC 处理方法入参绑定等场合使用它进行数据的转换
- 可通过 ConversionServiceFactoryBean 的 converters 属性注册自定义的类型转换器
springmvc.xml加入:
<!--配置conversionService-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="employeeConverter"></ref>
</set>
</property>
</bean>
将自定义的转换器注册到Spring MVC上下文,springmvc.xml继续加入:
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
注意代码:是在我的上一篇博客的基础上写的:
- EmployeeConverter.java
import com.ifox.restful_CRUD.entities.Department;
import com.ifox.restful_CRUD.entities.Employee;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
@Component
public class EmployeeConverter implements Converter<String,Employee> {
@Nullable
@Override
public Employee convert(String s) {
if (s != null){
String val[] = s.split("-") ;
if (val != null && val.length == 4){
String lastName = val[0] ;
String email = val[1] ;
Integer gender = Integer.parseInt(val[2]) ;
Department department = new Department() ;
department.setId(Integer.parseInt(val[3]));
Employee employee = new Employee(null,lastName,email, gender, department) ;
System.out.println(s +"--convert--"+ employee );
return employee ;
}
}
return null ;
}
}
- jsp页面;
<form action="testConversionServiceConverer" method="post">
<%--格式示例: KK-kk@sicnu.com-0-105--%>
Employee: <input type="text" name="employee">
<input type="submit" value="Submit">
</form>
输入[email protected]格式的数据,提交后,会通过我们自定义的转换器转换成Employee。
- Controller类:
import com.ifox.restful_CRUD.dao.EmployeeDao;
import com.ifox.restful_CRUD.entities.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class ConversionServiceConverer {
@Autowired
private EmployeeDao employeeDao ;
@RequestMapping("/testConversionServiceConverer")
public String testConversionService(@RequestParam("employee") Employee employee){
System.out.println("save:"+employee);
employeeDao.save(employee);
return "redirect:/emps" ;
}
}
Spring 支持的转换器
Spring 定义了 3 种类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到ConversionServiceFactroyBean 中:
Converter<S,T>
:将 S 类型对象转为 T 类型对象ConverterFactory
:将相同系列多个 “同质” Converter 封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将 String 转换为 Number 及 Number 子类(Integer、Long、Double 等)对象)可使用该转换器工厂类- GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换
关于 mvc:annotation-driven
<mvc:annotation-driven />
会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean。
还将提供以下支持:- 支持使用 ConversionService 实例对表单参数进行类型转换
- 支持使用 @NumberFormat annotation、@DateTimeFormat注解完成数据类型的格式化
- 支持使用 @Valid 注解对 JavaBean 实例进行 JSR 303 验证
- 支持使用 @RequestBody 和 @ResponseBody 注解
@InitBinder
- 由 @InitBinder 标识的方法,可以对 WebDataBinder 对象进行初始化WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定
- @InitBinder方法不能有返回值,它必须声明为void。
- @InitBinder方法的参数通常是是 WebDataBinder
handler:
@InitBinder
public void initBinder(WebDataBinder binder){
System.out.println("initBinder............");
//不自动绑定lastName属性
binder.setDisallowedFields("lastName");
//这样做会使得表单提交的lastName没有绑定
}