springmvc通过@RequestMapping将请求路由到具体的方法体时候,将请求消息中的数据按照一定的方式转化并绑定到方法入参中,在这之间,还会对数据进行转化,格式化并进行数据校验。
使用conversionService自定义入参转化
<mvc:annotation-driven conversion-service="customerConService" />
<bean id = "customerConService" class = "org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class = "com.liuxg.util.converter.String2TaskConverter" />
</list>
</property>
</bean>
在mvc:annotation-driven配置conversion-service,conversion-service关联的是一个ConversionServiceFactoryBean,可以在ConversionServiceFactoryBean这个bean中注册多个转换器,目前spring支持3种类型的转换器分别为:
1.Converter
/** * 将请求参数类似<taskName>,<taskDetail>这样子的字符串封装成实体类 */
public class String2TaskConverter implements Converter<String, Task>{
@Override
public Task convert(String source) {
Task task = new Task();
if(source != null){
String[] items = source.split(",");
task.setTaskName(items[0]);
task.setTaskDetail(items[1]);
}
return task;
}
}
2.如果希望将一种类型的对象转化成另外一种对象极其子类对象,可以用ConverterFactroy
final class StringToNumberConverterFactory implements ConverterFactory<String, Number> {
@Override
public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToNumber<T>(targetType);
}
private static final class StringToNumber<T extends Number> implements Converter<String, T> {
private final Class<T> targetType;
public StringToNumber(Class<T> targetType) {
this.targetType = targetType;
}
@Override
public T convert(String source) {
if (source.length() == 0) {
return null;
}
return NumberUtils.parseNumber(source, this.targetType);
}
}
}
它提供了个将相同系列的多个同质封装在一起,例如StringToInteger,StringToLong以及StringToDouble直接用StringToNumber搞定,Integer,Long和Double都是Number的子类。
3.Converter和ConverterFactory都是简单把一个对象转化成另外一个对象没有考虑宿主类的上下文信息,做不了复杂转化,GenericConverter接口会根据源类对象和目标对象的所在的宿主类的上下文信息进行类型转化工作。
默认已经安装FormattingConversionServiceFactoryBean,用来处理大部分的转化工作,如果你要自定义转化器,只需要实例化Converter,ConverterFactory以及GenericConverter中的一个并注册到ConversionServiceFactoryBean中。
用@InitBinder在方法级别上自定义编辑器
//@InitBinder("name")
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Task.class, new StrDecoderEditor ());
}
/** * 处理一些编码工作 */
class StrDecoderEditor extends PropertiesEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
try {
text = URLDecoder.decode(text, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
super.setAsText(text);
}
}
用WebBindingInitiaLizer自定义全局编辑器
public class CustomerBinder implements WebBindingInitializer {
@Override
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(Task.class, new TaskEditor());
binder.registerCustomEditor(Task.class, new DecoderEditor());
//。。。。
}
}
可以在这里注册多个编辑器,写好自定义类,需要把他注册到AnonotationMethodHandlerAdapter里面去
<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class = "com.liuxg.util.binder.CustomerBinder" />
</property>
</bean>
如果项目中既有@InitBinder,ConversionService还有WebBindingInitializer组成的自定义编辑器,springmvc执行的顺序是
@InitBinder - > ConversionService - > WebBindingInitializer