ConversionService
一个接口,包含以下方法:
boolean canConvert(Class<?> sourceType, Class<?> targetType);
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType):需转换的类以成员变量的方式出现在宿主类中。TypeDescripter不但描述了需转换类的信息,还描述了从宿主类的上下文信息,如成员变量上的注解,成员变量是否已集合,数组,Map的方式呈现等。类型转换逻辑可以利用这些信息做出各种灵活的控制。
<T> T convert(Object source, Class<T> targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType):将对象从原型对象转换为目标型对象,此时往往会用到所在宿主类的上下文信息。
可以利用ConversionServiceFactoryBean在Spring的上下文中定义一个ConversionService。
<bean id="conversionService"
class="org.springframework.format.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="x.x.x.StringToUserConverter"/>
</list>
</property>
</bean>
spring支持的转换器
3中类型转换器接口:
1. Converter<S,T>
2. GenericConverter
3. ConverterFactory
public interface Converter<S, T> {
T convert(S source);
}
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
GenericConverter可以根据源类对象及目标对象所在宿主类的上下文信息进行类型转换工作。
public interface GenericConverter {
Set<ConvertiblePair> getConvertibleTypes();
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
public static final class ConvertiblePair {
private final Class<?> sourceType;
private final Class<?> targetType;
}
ConditionalGenericConverter扩展了GenericConverter接口,添加了一个方法:
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
返回true时才进行类型转换。
使用conversionService
<mvc:annotation-driven>
会创建一个默认的DefaultAnnotationHandlerMapping和一个RequestMappingHandlerAdapter实例。如果上下文中存在自定义的组件bean,则spring mvc会自动利用自定义的Bean覆盖默认的Bean.此外它还会注册一个默认的ConversionSerivce,即
FormattingConversionServiceFactoryBean。利用自定义的conversionService覆盖默认的:
<mvc:annotation-driven conversion-service="conversionService"/>
装配自定义编译器
可以在控制器中使用@InitBinder添加自定义的编辑器。也可以通过WebBindingInitializer装配在全局范围内使用的编辑器。
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(User.class, new UserEditor());
binder.setValidator(new UserValidator());
}
public class UserEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
User user = new User();
if (text != null) {
String[] items = text.split(":");
user.setUserName(items[0]+"by propertyeEditor");
user.setPassword(items[1]);
user.setRealName(items[2]);
}
setValue(user);
}
}
spring4.0可以使用addCustomFormatter指定格式化程序实现。
@InitBinder
public void initBinder(WebDataBinder binder){
binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
}
如果要在全局范围内使用:
public class MyBindingInitializer implements WebBindingInitializer{
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.registerCustomEditor(User.class, new UserEditor());
}
}
在requestMappingHandlerAdapter装配。
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
p:messageConverters-ref="messageConverters">
<property name="webBindingInitializer">
<bean class="com.smart.web.MyBindingInitializer"/>
</property>
</bean>
数据格式化
spring转换器不提供数据格式化。spring提供了一个Formatter<T>
接口
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
Printer负责对象的格式化输出,Parser负责对象的格式化输入。
注解驱动格式化
为了让注解和格式化的属性类型关联起来,spring提供了AnnotationFormatterFactory接口:
public interface AnnotationFormatterFactory<A extends Annotation>{
Set<Class<?>> getFieldTypes();//注解A的应用范围,即那些属性类可以标注A注解
Printer<?> getPrinter(A annotation, Class<?> fieldType);//注解A获取特定属性类型的Printer
Parser<?> getParser(A annotation, Class<?> fieldType);//根据注解A获取特定属性类型的Parser
spring提供了两个实现类:
- NumberFormatAnnotationFormatterFactory:对应@NumberFormat注解
- JodaDateTimeFormatAnnotationFormatterFactory:对应@DateTimeFormat注解。
启用
FormattingConversionService类实现了GenericConversionService,因此它既有类型转换功能,又具有格式化功能。FormattingConversionService有一个工厂类FormattingConversionServiceFactoryBean。这个类在内部会自动注册NumberFormatAnnotationFormatterFactory和JodaDateTimeFormatAnnotationFormatterFactory。因此装配了这个工厂类,既可以注册自定义的转换器,还可以注册自定的注解驱动逻辑。
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="x.x.x.StringToUserConverter"/>
</list>
</property>
</bean>
mvc:annotation-driven默认创建的ConversionService实例就是一个FormattingConversionServiceFactoryBean
public class User{
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday;
@NumberFormat(pattern="#,###.##")
private long salary;
}