1. 程式人生 > >spring配置詳解

spring配置詳解

springmvc的配置檔案,也不是固定命名的,而是同spring配置檔案一樣,在web.xml中指定的:

    <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>
下面我們還是老規矩,一步步的來分析spring mvc配置檔案
一.root標籤
跟spring配置一樣,root標籤是beans,畢竟springmvc是spring的一個模組

二.自動掃描

這部分我們在spring也講過。在springmvc裡,自動掃描主要是配置controller:

<context:component-scan base-package="com.xxx.controller"/>

三.解析器Resolver

解析器有很多種,比較重要的是ViewResolver

ViewResolver也有很多種,其中比較重要和常用的是InternalResourceViewResolver(內部資源檢視解析器)

先上程式碼再說明:

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="order" value="1" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
如果沒有檢視解析器,我們在controller裡面的程式碼是這樣的:
@Controller
public class LoginActionController {
    @RequestMapping("/index")
    public String toIndex(HttpServletRequest request, ModelMap map, HttpSession session) {
            return "/WEB-INF/jsp/index.jsp";
    }

而使用了檢視解析器,我們的程式碼是這樣的:
@Controller
public class LoginActionController {
    @RequestMapping("/index")
    public String toIndex(HttpServletRequest request, ModelMap map, HttpSession session) {
            return "index";
    }
區別在最後一句,我們不需要給出目標檢視的全路徑了。
InternalResourceViewResolver的主要作用也在於此,給出內部資源的路徑和前後綴。

當然還有其他的檢視解析器,比如XmlViewResolver,UrlBasedViewResolver等,不再鋪開解釋。

也還有別的解析器,比如處理檔案上傳的解析器CommonsMultipartResolver,統一處理異常的解析器SimpleMappingExceptionResolver。

這裡多說兩句SimpleMappingExceptionResolver,程式碼如下:


    <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="warnLogCategory" value="warn" />
        <property name="defaultStatusCode" value="500"/>
        <property name="defaultErrorView" value="/error/500"/>
        
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.Exception">/error/500</prop>
            </props>
        </property>
        
        <property name="statusCodes">
            <props>
                <prop key="/error/404">404</prop>
                <prop key="/error/404">400</prop>
                <prop key="/error/500">500</prop>
            </props>
        </property>
    </bean>


四.對靜態資源的處理

在web.xml裡面,我們配置了springmvc的DispatcherServlet:

    <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
注意看servlet-mapping部分,這部分的url-pattern是"/",這表明,DispatcherServlet會幫我們截獲所有的url請求,並將請求傳送給對應的controller。
對,是所有的請求!也包括靜態檔案,比如.js檔案,圖片檔案,css檔案的請求。

顯然這是有問題的,因為沒有controller會去處理靜態檔案,這會導致靜態檔案查詢不到。

這也是為什麼我們在一些早期的文章或者書籍中,看到的servlet-mapping是下面這樣的:


 <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
    </servlet-mapping>
然後在controller裡面,我們會這麼寫:

@Controller
public class LoginActionController {
    @RequestMapping("/index.do")
    public String toIndex(HttpServletRequest request, ModelMap map, HttpSession session) {
            return "index";
    }
注意這裡的RequestMapping的value是index.do
通過這種方式,等於是我們只讓DispatcherServlet去處理了.do字尾的請求,controller也只會處理.do字尾的請求。

對應的,我們的url是這樣的:www.test.com/index.do

很顯然這樣看著很奇怪,而且不符合REST風格。

所以spring團隊給出了2種解決方案:

方案一:

你可以在springmvc的配置檔案裡面加上這麼一句:

<mvc:default-servlet-handler />
這表示,如果發現是靜態資源的請求,就將該請求轉由Web應用伺服器預設的Servlet處理,如果不是靜態資源的請求,才由DispatcherServlet繼續處理。
方案二:

<mvc:resources />
<mvc:default-servlet-handler />將靜態資源的處理經由Spring MVC框架交回Web應用伺服器處理。而<mvc:resources />更進一步,由Spring MVC框架自己處理靜態資源,並新增一些有用的附加值功能:
首先你可以把你的靜態檔案放到專案的任何地方,比如/WEB-INF下面,classpath下面。而傳統的方案,我們只能把靜態檔案放到web應用的根目錄下面。然後通過location屬性告訴spring我們的靜態資源放在哪裡

PS:補充一個知識,什麼叫做web應用部署的根目錄:http://blog.csdn.net/l00149133/article/details/78984083

其次依據當前著名的Page Speed、YSlow等瀏覽器優化原則對靜態資源提供優化。你可以通過cacheSeconds屬性指定靜態資源在瀏覽器端的快取時間,一般可將該時間設定為一年,以充分利用瀏覽器端的快取。在輸出靜態資源時,會根據配置設定好響應報文頭的Expires 和 Cache-Control值。在接收到靜態資源的獲取請求時,會檢查請求頭的Last-Modified值,如果靜態資源沒有發生變化,則直接返回303相應狀態碼,提示客戶端使用瀏覽器快取的資料,而非將靜態資源的內容輸出到客戶端,以充分節省頻寬,提高程式效能。

另外,通過mapping屬性我們還可以指定靜態資源的訪問路徑。

舉例說明:

<mvc:resources location="/,/WEB-INF/js,classpath:/resource" mapping="resource/**"/>
這裡,我們把web部署的根目錄"/",以及WEB-INF下的js目錄,還有build路徑下的resource目錄都設定成了靜態資源目錄,並且對映成resource路徑。

假設我們:

在根目錄下有個image資料夾,裡面有個icon.png檔案

在WEB-INF下的js目錄下有個test.js檔案

在build路徑下的resource目錄裡有個css/test.css檔案

我們可以分別通過:

www.test.com/resource/iamge/icon.png
www.test.com/resource/js/test.js

www.test.com/resource/css/test.css

來訪問。

五.<mvc:annotation-driven />

這個有點像是我們之前講的註解裝配<context:annotation-config>,兩者都是用來隱式的註冊註解所需的bean。

比如你想要用@Autowired註解,如果沒有<context:annotation-config>,那你需要手動去宣告AutowiredAnnotationBeanPostProcessor的Bean:

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor "/> 
而<context:annotation-config>的作用,就是隱式的幫你聲明瞭這些註解的bean。包括AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及 RequiredAnnotationBeanPostProcessor 這 4 個BeanPostProcessor。
這樣你就可以使用諸如@Required, @Autowired, @PostConstruct這些註解。

但是!<context:annotation-config>並沒有幫我們宣告controller所用的註解,比如@RequestMapping, @Controller。所以我們需要<mvc:annotation-driven />。

實際上<mvc:annotation-driven />註冊了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter兩個bean,配置一些messageconverter。即解決了@Controller註解的使用前提配置。


六.mvc:message-converters訊息轉換器

這實際上是mvc:annotation-driven的一個子標籤,可以看到它主要處理的是response返回的值,比如預設編碼,比如支援Fastjson,當然你可以可以加入對其他返回型別的支援,比如gson,protobuf等等


    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <!-- @ResponseBody亂碼問題,將StringHttpMessageConverter的預設編碼設為UTF-8 -->
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="UTF-8"/>
            </bean>
            <!-- 配置Fastjson支援 -->
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                <property name="charset" value="UTF-8"/>
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json</value>
                        <value>text/html;charset=UTF-8</value>
                    </list>
                </property>
                <property name="features">
                    <list>
                        <value>WriteMapNullValue</value>
                        <value>QuoteFieldNames</value>
                        <value>WriteDateUseDateFormat</value>
                        <value>WriteEnumUsingToString</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
七.springmvc攔截器mvc:interceptors

mvc:interceptors用來攔截url請求。

正常的流程,應該是DispatcherServlet先獲取所有的URL請求,然後依據規則分發給可以處理這些請求的controller。

而是用mvc:interceptors後,流程變成了:DispatcherServlet先獲取所有的URL請求,對於符合攔截器要求格式的URL,先分發給攔截器處理,最後再分發給可以處理這些請求的controller。

舉例說明:


    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/static/**" />
            <bean class="com.xxx.interceptor.LoginRequiredInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>
這個攔截器表示,它會攔截所有的URL請求,除了static路徑下的請求,並交給LoginRequiredInterceptor來處理