SpringMVC 流程 配置 接口


SpringMVC簡介
 
  一 流程介紹
1.角色划分
前端控制器(DispatcherServlet)、請求到處理器映射(HandlerMapping)、處理器適配器(HandlerAdapter)、視圖解析器(ViewResolver)、處理器或頁面控制器(Controller)、驗證器(Validator)、命令對象(Command請求參數綁定到的對象就叫命令對象)、表單對象(Form Object提供給表單展示和提交到的對象就叫表單對象)。
2.流程圖

3.具體步驟:
(1)首先用戶發送請求——>DispatcherServlet,前端控制器收到請求后自己不進行處理,而是委托給其他的解析器進行處理,作為統一訪問點,進行全局的流程控制;
(2)DispatcherServlet——>HandlerMapping, HandlerMapping將會把請求映射為HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象、多個HandlerInterceptor攔截器)對象,通過這種策略模式,很容易添加新的映射策略;
(3)DispatcherServlet——>HandlerAdapter,HandlerAdapter將會把處理器包裝為適配器,從而支持多種類型的處理器,即適配器設計模式的應用,從而很容易支持很多類型的處理器;
(4)HandlerAdapter——>處理器功能處理方法的調用,HandlerAdapter將會根據適配的結果調用真正的處理器的功能處理方法,完成功能處理;並返回一個ModelAndView對象(包含模型數據、邏輯視圖名);
(5)ModelAndView的邏輯視圖名——> ViewResolver, ViewResolver將把邏輯視圖名解析為具體的View,通過這種策略模式,很容易更換其他視圖技術;
(6)View——>渲染,View會根據傳進來的Model模型數據進行渲染,此處的Model實際是一個Map數據結構,因此很容易支持其他視圖技術;
(7)返回控制權給DispatcherServlet,由DispatcherServlet返回響應給用戶,到此一個流程結束。

 

二 重要的接口及其實現

1.DispatcherServlet部分

DispatcherServlet是一個Servlet,所以可以配置多個DispatcherServlet。
DispatcherServlet是前置控制器,配置在web.xml文件中的。攔截匹配的請求,Servlet攔截匹配規則要自已定義,把攔截下來的請求,依據某某規則分發到目標Controller(我們寫的Action)來處理。
“某某規則”:是根據你使用了哪個HandlerMapping接口的實現類的不同而不同。
xml代碼示例1:

<web-app>  
        <servlet>  
            <servlet-name>example</servlet-name>  
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
            <load-on-startup>1</load-on-startup>  
        </servlet>  
        <servlet-mapping>  
            <servlet-name>example</servlet-name>  
            <url-pattern>*.form</url-pattern>  
        </servlet-mapping>  
    </web-app>  

<load-on-startup>1</load-on-startup>是啟動順序,讓這個Servlet隨Servlet容器一起啟動。
 <url-pattern>*.form</url-pattern> 會攔截*.form結尾的請求。    
<servlet-name>example</servlet-name>這個Servlet的名字是example,可以有多個DispatcherServlet,是通過名字來區分的。每一個DispatcherServlet有自己的WebApplicationContext上下文對象。同時保存的ServletContext中和Request對象中。    
在DispatcherServlet的初始化過程中,框架會在web應用的 WEB-INF文件夾下尋找名為[servlet-name]-servlet.xml 的配置文件,生成文件中定義的bean。

xml代碼示例2:

<servlet>  
        <servlet-name>springMVC</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <init-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>classpath*:/springMVC.xml</param-value>  
        </init-param>  
        <load-on-startup>1</load-on-startup>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>springMVC</servlet-name>  
        <url-pattern>/</url-pattern>  
    </servlet-mapping>

指明了配置文件的文件名,不使用默認配置文件名,而使用springMVC.xml配置文件。
其中<param-value>**.xml</param-value> 這里可以使用多種寫法
(1)不寫,使用默認值:/WEB-INF/<servlet-name>-servlet.xml
(2)<param-value>/WEB-INF/classes/springMVC.xml</param-value>
(3)<param-value>classpath*:springMVC-mvc.xml</param-value>
(4)多個值用逗號分隔    

 

2.配置HandlerMapping、HandlerAdapter
在springMVC.xml中的配置為:

<!-- HandlerMapping -->  
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>        
    <!-- HandlerAdapter -->  
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>  

BeanNameUrlHandlerMapping:表示將請求的URL和Bean名字映射,如URL為 “上下文/hello”,則Spring配置文件必須有一個名字為“/hello”的Bean,上下文默認忽略。
SimpleControllerHandlerAdapter:表示所有實現了org.springframework.web.servlet.mvc.Controller接口的Bean可以作為Spring Web MVC中的處理器。如果需要其他類型的處理器可以通過實現HadlerAdapter來解決。    

 

3.配置ViewResolver

<!-- ViewResolver -->  
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>  
    <property name="prefix" value="/WEB-INF/jsp/"/>  
    <property name="suffix" value=".jsp"/>  
</bean>

InternalResourceViewResolver:用於支持Servlet、JSP視圖解析;
viewClass:JstlView表示JSP模板頁面需要使用JSTL標簽庫,classpath中必須包含jstl的相關jar包;
prefix和suffix:查找視圖頁面的前綴和后綴(前綴[邏輯視圖名]后綴),比如傳進來的邏輯視圖名為hello,則該該jsp視圖頁面應該存放在“WEB-INF/jsp/hello.jsp”; 

 

一個springMVC-mvc.xml配置文件片段:

<?xml version="1.0" encoding="UTF-8"?>  
    <beans  
        xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xmlns:tx="http://www.springframework.org/schema/tx"  
        xmlns:context="http://www.springframework.org/schema/context"    
        xmlns:mvc="http://www.springframework.org/schema/mvc"    
        xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
        http://www.springframework.org/schema/tx   
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
        http://www.springframework.org/schema/context  
        http://www.springframework.org/schema/context/spring-context-3.0.xsd  
        http://www.springframework.org/schema/mvc  
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">  
      
      
        <!-- 自動掃描的包名 -->  
        <context:component-scan base-package="com.app,com.core,JUnit4" ></context:component-scan>  
          
        <!-- 默認的注解映射的支持 -->  
        <mvc:annotation-driven />  
          
        <!-- 視圖解釋類 -->  
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
            <property name="prefix" value="/WEB-INF/jsp/"/>  
            <property name="suffix" value=".jsp"/><!--可為空,方便實現自已的依據擴展名來選擇視圖解釋類的邏輯  -->  
            <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />  
        </bean>  
          
        <!-- 攔截器 -->  
        <mvc:interceptors>  
            <bean class="com.core.mvc.MyInteceptor" />  
        </mvc:interceptors>       
          
        <!-- 對靜態資源文件的訪問  方案一 (二選一) -->  
        <mvc:default-servlet-handler/>  
          
        <!-- 對靜態資源文件的訪問  方案二 (二選一)-->  
        <mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>  
        <mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>  
        <mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"/>  
      
    </beans>   

注意:
(1)這里使用了<mvc:annotation-driven/>注解,這是一種簡寫形式,完全可以手動配置替代這種簡寫形式,簡寫形式可以讓初學都快速應用默認配置方案。<mvc:annotation-driven/> 會自動注冊DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter兩個bean,是springMVC為@Controllers分發請求所必須的。並提供了:數據綁定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,讀寫XML的支持(JAXB),讀寫JSON的支持(Jackson)。
(2)<mvc:interceptors/>是一種簡寫形式。我們可以配置多個HandlerMapping。<mvc:interceptors/>會為每一個HandlerMapping,注入一個攔截器。其實我們也可以手動配置為每個HandlerMapping注入一個攔截器。
(3)<mvc:default-servlet-handler/> 使用默認的Servlet來響應靜態文件。
(4)<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>
匹配URL /images/**的URL被當做靜態資源,由Spring讀出到內存中再響應http。

 

4.訪問靜態文件
如何你的DispatcherServlet攔截"*.do"這樣的有后綴的URL,就不存在訪問不到靜態資源的問題。
如果你的DispatcherServlet攔截"/",為了實現REST風格,攔截了所有的請求,那么同時對*.js,*.jpg等靜態文件的訪問也就被攔截了。
方案一:激活Tomcat的defaultServlet來處理靜態文件

<servlet-mapping>   
    <servlet-name>default</servlet-name>  
    <url-pattern>*.jpg</url-pattern>     
</servlet-mapping>    
<servlet-mapping>       
    <servlet-name>default</servlet-name>    
    <url-pattern>*.js</url-pattern>    
</servlet-mapping>    
<servlet-mapping>        
    <servlet-name>default</servlet-name>       
    <url-pattern>*.css</url-pattern>      
</servlet-mapping>    

要配置多個,每種文件配置一個。
要寫在DispatcherServlet的前面, 讓 defaultServlet先攔截請求,這樣請求就不會進入Spring了,應該性能是最好的吧。

方案二: 在spring3.0.4以后版本提供了mvc:resources
<mvc:resources mapping="/images/**" location="/images/" />  
/images/**映射到ResourceHttpRequestHandler進行處理,location指定靜態資源的位置.可以是web application根目錄下、jar包里面,這樣可以把靜態資源壓縮到jar包中。cache-period 可以使得靜態資源進行web cache
使用<mvc:resources/>元素,把mapping的URI注冊到SimpleUrlHandlerMapping的urlMap中,key為mapping的URI pattern值,而value為ResourceHttpRequestHandler,
這樣就巧妙的把對靜態資源的訪問由HandlerMapping轉到ResourceHttpRequestHandler處理並返回,所以就支持classpath目錄,jar包內靜態資源的訪問。

 

5.攔截器
自定義一個攔截器,要實現HandlerInterceptor接口

public class MyInterceptor implements HandlerInterceptor {
 
    @Override
    public void afterCompletion(HttpServletRequest arg0,
            HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("afterCompletion");
    }
 
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
            Object arg2, ModelAndView arg3) throws Exception {
        System.out.println("postHandle");
    }
 
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
            Object arg2) throws Exception {
        System.out.println("preHandle");
        return true;
    }
 
}

在spring MVC的配置文件中配置有三種方法:
方案一,(近似)總攔截器,攔截所有url

<mvc:interceptors>  
    <bean class="com.app.mvc.MyInteceptor" />  
</mvc:interceptors>

<mvc:interceptors/>會為每一個HandlerMapping,注入一個攔截器。總有一個HandlerMapping是可以找到處理器的,最多也只找到一個處理器,所以這個攔截器總會被執行的。起到了總攔截器的作用。如果是REST風格的URL,靜態資源也會被攔截。
方案二, (近似) 總攔截器, 攔截匹配的URL

<mvc:interceptors >    
      <mvc:interceptor>    
            <mvc:mapping path="/user/*" /> <!-- /user/*  -->    
            <bean class="com.mvc.MyInteceptor"></bean>    
        </mvc:interceptor>    
    </mvc:interceptors>  

就是比 方案一多了一個URL匹配。如果是REST風格的URL,靜態資源也會被攔截。
方案三,HandlerMappint上的攔截器

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">       
     <property name="interceptors">       
         <list>       
             <bean class="com.mvc.MyInteceptor"></bean>      
         </list>       
     </property>       
 </bean>   

如果是REST風格的URL,靜態資源就不會被攔截。因為我們精准的注入了攔截器。
如果使用了<mvc:annotation-driven />, 它會自動注冊DefaultAnnotationHandlerMapping 與AnnotationMethodHandlerAdapter 這兩個bean,所以就沒有機會再給它注入interceptors屬性,就無法指定攔截器。
當然我們可以通過人工配置上面的兩個Bean,不使用 <mvc:annotation-driven />,就可以 給interceptors屬性 注入攔截器了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM