SpringMVC,3種不同的URL路由配置方法


1. 先說說一種比較常見的:   
    <servlet>
        <servlet-name>theDispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/spring-mvc-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>theDispatcher</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

讓SpringMVC只攔截動態請求,js、css、img等靜態資源不經過Spring,直接讓Web容器處理。如果配置了攔截器,也只會攔截.html動態請求。

靜態資源不走Spring,也不走攔截器,性能當然是比較好的。如果使用了Nginx,配置靜態資源攔截,讓Nginx處理靜態資源的訪問。

因為Nginx在處理靜態資源方面,比Tomcat等Web容器要強。

缺點:這種攔截動態請求的方法,比較死板。

 

2.  我自己經常有一種需求,http://FansUnion.cn/news 這種不指定.html后綴的其實也是動態請求,所以我在配置url-pattern喜歡用“/”,即攔截所有的請求。

URL是可以靈活配置了,問題又來了,靜態資源不再由Tomcat處理,所以必須在SpringMVC中再次配置

<mvc:resources mapping="/static/**" location="/static/" />

讓SpringMVC把static靜態資源也處理了。顯然,讓SpringMVC處理靜態資源的性能沒有Tomcat直接處理比較高。

理論上,請求中轉的次數越多, 性能越差。

本以為萬事大吉,雖然靜態資源的性能較低,至少程序可以正常運行了,“反正是混過去了”。

進一步的需求,如果在Spring中配置了登錄等攔截器,這個時候也會把 靜態資源給攔截進來。

<mvc:resources mapping="/static/**" location="/static/" />
 這種URL映射,也無法逃脫攔截器的魔爪。
 
我是怎么發現這個問題的呢?
public class BaseLoginInterceptor extends HandlerInterceptorAdapter { 
    
    public boolean preHandle(HttpServletRequest request, 
            HttpServletResponse response, Object handler) throws Exception {
        
        LoginUtil.setCurrentUser(null);
        initCurrentUser(request, response);
        HandlerMethod handlerMethod = (HandlerMethod) handler;
    }
}
公司的項目,Boss的登錄攔截器配置如上,“ HandlerMethod handlerMethod = (HandlerMethod) handler;”。但是我在自己的項目中,發現這行代碼是有問題的。
如果靜態資源被攔截到,會報錯:
java.lang.ClassCastException: org.springframework.web.servlet.resource.ResourceHttpRequestHandler 
cannot be cast to org.springframework.web.method.HandlerMethod
通過異常可以發現,Object handler是 ResourceHttpRequestHandler,而不是HandlerMethod。

因為mvc:resources把靜態資源請求交給了 ResourceHttpRequestHandler 處理,因此強制轉換是有問題的。

公司項目中Boss的配置之所以沒有出現問題,是因為他配置的是只攔截“.html” 動態請求,所以強制轉換總是成立的。

 

---------------------------------------------

我們分析了上述兩種情況, 發現“根本矛盾”“根本需求”是啥?

1.動態請求的URL應該非常靈活,/news /news.html都應該算作動態請求。

2.SpringMVC的url-pattern可以配置 / , *.html,或者正則表達式,但是我不太喜歡用正則表達式。

3.如果可能,SpringMVC最好不要攔截靜態資源,讓Tomcat容器直接處理更好。

<mvc:resources mapping="/static/**" location="/static/" />

這是為了性能考慮。

4.如果線上服務器配置了Nginx,我可以選擇讓Nginx攔截靜態請求,因為比Tomcat處理性能更高。

本地是否配置Nginx,都不需要改動任何代碼。

-------------------------------------------------

上面說的 第一種方法的缺陷是,url配置不夠靈活。

第二種方法的缺陷是,SpringMVC要攔截靜態資源,而且登錄攔截器 也會攔截 靜態資源,不但性能差,程序還得再次修改,判斷HandlerMethod的實際類型。

 

3.終極解決方案:

以我習慣用的第2種方法為基礎,進一步改進:

去掉 <mvc:resources mapping="/static/**" location="/static/" />,不做靜態資源請求的映射。

在web.xml里增加如下配置:

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/static/*</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>

激活Tomcat的defaultServlet來處理靜態文件。

這樣 SpringMVC不再響應靜態資源,登錄攔截器也沒有問題了。


免責聲明!

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



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