Spring MVC
Spring MVC數據類型轉換
Spring3引入了更加通用的類型轉換系統,其定義了SPI接口(Converter等)和相應的運行時執行類型轉換的API(ConversionService等)。該類型轉換系統是Spring通用的,其定義在org.springframework.core.convert包中,提供無狀態、強類型且可以在任意類型之間轉換的類型轉換系統,可以用於任何需要的地方,如SpEL、數據綁定。
類型轉換器有如下三種接口
(1 )、Converter:類型轉換器,用於轉換S類型到T類型,此接口的實現必須是線程安全的且可以被共享。
package org.springframework.core.convert.converter;
public interface Converter<S, T> { //① S是源類型 T是目標類型
T convert(S source); //② 轉換S類型的source到T目標類型的轉換方法
}
Converter接口實現只能轉換一種類型到另一種類型,不能進行多類型轉換,如將一個數組轉換成集合,如(String[] ----> List<String>、String[]----->List<PhoneNumberModel>等)
(2 )、GenericConverter和ConditionalGenericConverter:GenericConverter接口實現能在多種類型之間進行轉換,ConditionalGenericConverter是有條件的在多種類型之間進行轉換。
package org.springframework.core.convert.converter;
public interface GenericConverter {
//getConvertibleTypes:指定了可以轉換的目標類型對;
Set<ConvertiblePair> getConvertibleTypes();
//convert:在sourceType和targetType類型之間進行轉換
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
package org.springframework.core.convert.converter;
public interface ConditionalGenericConverter extends GenericConverter {
//matches:用於判斷sourceType和targetType類型之間能否進行類型轉換
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
對於我們大部分用戶來說一般不需要自定義GenericConverter, 如果需要可以參考內置的GenericConverter來實現類型轉換。
(3 )、ConverterFactory:工廠模式的實現,用於選擇將一種S源類型轉換爲R類型的子類型T的轉換器的工廠接口。
package org.springframework.core.convert.converter;
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
S:源類型;R目標類型的父類型;T:目標類型,且是R類型的子類型;
getConverter:得到目標類型的對應的轉換器。
如org.springframework.core.convert.support.NumberToNumberConverterFactory用於在Number類型子類型之間進行轉換,如Integer--->Double, Byte---->Integer, Float--->Double等。
對於我們大部分用戶來說一般不需要自定義ConverterFactory,如果需要可以參考內置的ConverterFactory來實現類型轉換。
類型轉換器註冊器、類型轉換服務有如下兩種接口
類型轉換器註冊器、類型轉換服務:提供類型轉換器註冊支持,運行時類型轉換API支持。
(1 )、ConverterRegistry:類型轉換器註冊支持,可以註冊/刪除相應的類型轉換器
public interface ConverterRegistry {
void addConverter(Converter<?, ?> converter);
void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter);
void addConverter(GenericConverter converter);
void addConverterFactory(ConverterFactory<?, ?> converterFactory);
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}
可以註冊:Converter實現,GenericConverter實現,ConverterFactory實現。
(2 )、ConversionService:運行時類型轉換服務接口,提供運行期類型轉換的支持。
package org.springframework.core.convert;
public interface ConversionService {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(Object source, Class<T> targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
convert:將源對象轉換爲目標類型的目標對象。
Spring提供了兩個默認實現(其都實現了ConverterRegistry、ConversionService接口):
DefaultConversionService:默認的類型轉換服務實現;
DefaultFormattingConversionService:帶數據格式化支持的類型轉換服務實現,一般使用該服務實現即可。
Spring內建的類型轉換器
自定義類型轉換
我們將頁面傳遞的字符串轉換爲標準化日期格式。
1.先實現類型轉換器
public class DateConverter implements Converter<String, Date> {
//將傳入的字符串轉換爲日期
public Date convert(String source) {
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = format.parse(source);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
2.在springmvc配置文件中註冊ConversionService實現和自定義的類型轉換器
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!--可以自定義很多類型轉換器-->
<property name="converters">
<list>
<bean class="cn.cad.converter.DateConverter"></bean>
</list>
</property>
</bean>
FormattingConversionServiceFactoryBean:是FactoryBean實現,默認使用DefaultFormattingConversionService轉換器服務實現;
3.通過ConfigurableWebBindingInitializer註冊ConversionService
<bean id="customBinder" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"/>
</bean>
4.註冊ConfigurableWebBindingInitializer到RequestMappingHandlerAdapte
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer" ref="customBinder"></property>
</bean>
上面的方法看起來太過繁瑣,SpringMVC提供瞭如下更簡單的配置。
<!--前面說過使用<mvc:annotation-driven>就不用再配置映射器和適配器-->
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="cn.cad.converter.DateConverter"></bean>
</list>
</property>
</bean>
如上就完成了類型轉換,我們程序頁面輸入的日期一定要符合format的格式,才能完成轉換,否則就會出異常。
Controller返回類型
ModelAndView
controller方法中定義ModelAndView對象並返回,對象中可添加model數據、指定view。
void
有的時候我們並不需要返回值,例如ajax請求時。不過我們也可以在方法參數列表上添加request等來進行頁面跳轉等操作。
String
controller方法返回字符串可以指定邏輯視圖名,通過視圖解析器解析爲物理視圖地址。
至於數據,我們可以通過默認的Model或者ModelMap來傳遞參數。
通過 return "redirect:/xxx.jso" 來重定向或者轉發
SpringMVC異常處理
在SpringMVC中,系統的dao、service、controller出現都通過throws Exception向上拋出,最後由springmvc前端控制器交由異常處理器進行異常處理。springmvc提供全局異常處理器(一個系統只有一個異常處理器)進行統一異常處理。
這裏有篇關於SpringMVC異常處理的文章寫的很棒,我就不再重複。
http://blog.csdn.net/eson_15/article/details/51731567
SpringMVC文件上傳
1.首先需要加入jar包
2.配置上傳解析器
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 設置文件上傳大小 -->
<property name="maxUploadSize" value="5000000" />
</bean>
3.表單一定要設置enctype="multipart/form-data"
然後接收文件的方法 添加一個參數
//通過MultipartFile 接收上傳的文件
public ModelAndView updateItem(Items item,MultipartFile pictureFile) throws IllegalStateException, Exception {
String picName = UUID.randomUUID().toString();
// 獲取文件名
String oriName = pictureFile.getOriginalFilename();
System.out.println(oriName);
// 開始上傳文件
pictureFile.transferTo(new File("F:\\upload\\" + picName + extName));
itemService.updateItemById(item);
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("forward:/itemEdit");
return modelAndView;
}
這篇博客詳細介紹了SpringMVC的上傳下載。
http://blog.csdn.net/evankaka/article/details/45826697/
SpringMVC攔截器
Spring Web MVC的處理器攔截器類似於Servlet開發中的過濾器Filter,用於對處理器進行預處理和後處理。
攔截器接口
package org.springframework.web.servlet;
public interface HandlerInterceptor {
boolean preHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler)
throws Exception;
void postHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex)
throws Exception;
}
preHandle:處理器前執行的方法,實現處理器的預處理(如登錄檢查),第三個參數爲響應的處理器(如我們上一章的Controller實現);
返回值:true表示繼續流程(如調用下一個攔截器或處理器);
false表示流程中斷(如登錄檢查失敗),不會繼續調用其他的攔截器或處理器,此時我們需要通過response來產生響應;
postHandle:處理器後回調方法,實現處理器的後處理(但在渲染視圖之前),此時我們可以通過modelAndView(模型和視圖對象)對模型數據進行處理或對視圖進行處理,modelAndView也可能爲null。
afterCompletion:整個請求處理完畢回調方法,即在視圖渲染完畢時回調,如性能監控中我們可以在此記錄結束時間並輸出消耗時間,還可以進行一些資源清理,類似於try-catch-finally中的finally,但僅調用處理器執行鏈中preHandle返回true的攔截器的afterCompletion。
有時候我們可能只需要實現三個回調方法中的某一個,如果實現HandlerInterceptor接口的話,三個方法必須實現,不管你需不需要,此時spring提供了一個HandlerInterceptorAdapter適配器,允許我們只實現需要的回調方法。
public abstract class HandlerInterceptorAdapter implements HandlerInterceptor {
//省略代碼 此處所以三個回調方法都是空實現,preHandle返回true。
}
案例
1.編寫攔截器
public class HandlerInterceptor1 extends HandlerInterceptorAdapter {//此處一般繼承HandlerInterceptorAdapter適配器即可
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("===========攔截器 preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("===========攔截器 postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("===========攔截器 afterCompletion");
}
2.編寫處理器
@Controller
public class TestController {
@RequestMapping("/test")
public ModelAndView test() {
System.out.println("===========TestController");
return new ModelAndView("test");
}
}
3.配置攔截器
<mvc:interceptors>
<!--可以配置很多攔截器-->
<mvc:interceptor>
<!-- 所有的請求都進入攔截器 -->
<mvc:mapping path="/**" />
<!-- 配置具體的攔截器 -->
<bean class="cn.cad.HandlerInterceptor1" />
</mvc:interceptor>
</mvc:interceptors>
然後進行檢測即可。可以用來做登錄檢測、性能檢測等。