Servlet中的輸入參數為都是string類型,而spring mvc通過data bind機制將這些string 類型的輸入參數轉換為相應的command object(根據view和controller之間傳輸數據的具體邏輯,也可稱為model attributes, domain model objects)。在這個轉換過程中,spring實際是先利用java.beans.PropertyEditor中的 setAdText方法來把string格式的輸入轉換為bean屬性, 亦可通過繼承java.beans.PropertyEditorSupport來實現自定義的PropertyEditors,具體實現方式可參考spring reference 3.0.5 第 5.4節中的 Registering additional custom PropertyEditors部分。 自定義完畢propertyEditor后,有以下幾種方式來注冊自定義的customer propertyEditor.
1:直接將自定義的propertyEditor放到需要處理的java bean相同的目錄下
名稱和java Bean相同但后面帶Editor后綴。 例如需要轉換的java bean 名為User,則在相同的包中存在UserEditor類可實現customer propertyEditor的自動注冊。
2:利用@InitBinder來注冊customer propertyEditor
這個在之前的筆記中已經介紹過了,即在controller類中增加一個使用@InitBinder標注的方法,在其中注冊customer Editor
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(
dateFormat, false));
}
3:繼承 WebBindingInitializer 接口來實現全局注冊 使用@InitBinder只能對特定的controller類生效,為注冊一個全局的customer Editor,可以實現接口WebBindingInitializer 。
public class CustomerBinding implements WebBindingInitializer {
@Override
public void initBinder(WebDataBinder binder, WebRequest request) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(
dateFormat, false));
}
並修改 servlet context xml配置文件
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean
class="net.zhepu.web.customerBinding.CustomerBinding" />
</property>
</bean>
但這樣一來就無法使用mvc:annotation-driven 了。
使用conversion-service來注冊自定義的converter DataBinder實現了PropertyEditorRegistry, TypeConverter這兩個interface,而在spring mvc實際處理時,返回值都是return binder.convertIfNecessary(見HandlerMethodInvoker中的具體處理邏輯)。因此可以使用customer conversionService來實現自定義的類型轉換。
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="net.zhepu.web.customerBinding.CustomerConverter" />
</list>
</property>
</bean>
需要修改spring service context xml配置文件中的annotation-driven,增加屬性conversion-service指向新增的conversionService bean。
<mvc:annotation-driven validator="validator"
conversion-service="conversionService" />
實際自定義的converter如下。
public class CustomerConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
try {
return dateFormat.parse(source);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
對於requestBody或httpEntity中數據的類型轉換 Spring MVC中對於requestBody中發送的數據轉換不是通過databind來實現,而是使用HttpMessageConverter來實現具體的類型轉換。 例如,之前提到的json格式的輸入,在將json格式的輸入轉換為具體的model的過程中,spring mvc首先找出request header中的contenttype,再遍歷當前所注冊的所有的HttpMessageConverter子類, 根據子類中的canRead()方法來決定調用哪個具體的子類來實現對requestBody中的數據的解析。如果當前所注冊的httpMessageConverter中都無法解析對應contexttype類型,則拋出HttpMediaTypeNotSupportedException (http 415錯誤)。 那么需要如何注冊自定義的messageConverter呢,很不幸,在spring 3.0.5中如果使用annotation-driven的配置方式的話,無法實現自定義的messageConverter的配置,必須老老實實的自己定義AnnotationMethodHandlerAdapter的bean定義,再設置其messageConverters以注冊自定義的messageConverter。 在3.1版本中,將增加annotation-driven對自定義的messageConverter的支持 (SPR-7504),具體格式如下
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>