SpringMVC從入門到精通(二)

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>

然後進行檢測即可。可以用來做登錄檢測、性能檢測等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章