SpringMVC,3种不同的URL路由配置方法(这根本不是一个小问题)

SpringMVC中配置URL拦截。很easy。网上找个演示样例,就能通过。可是。在我做了好几个Web项目,又參与了别人主导的Web项目时,发现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.假设线上server配置了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的拦截器DispatchServlet之前。 
  
參考了:http://blog.chinaunix.net/uid-20586655-id-3000946.html 第七部分
网友提问:http://www.iteye.com/problems/66915http://www.iteye.com/problems/69983

这样 SpringMVC不再响应静态资源,登录拦截器也没有问题了。



------------------------------------------------------------------------
具体讨论了上诉3种情况,我的结论是:URL配置根本不是一个简单的问题。



搞IT这门高科技技术的Coder,真心须要研究啊。

今天搞点小功能,遇到各种问题,探究了好久,才理清了脉络,单单是解决这个问题。而不能找到根本原因。在遇到下一个问题的时候,会再次束手无策。 

原文首发:
http://fansunion.cn/article/detail/61.html 

posted @ 2016-01-29 08:20  blfshiye  阅读(778)  评论(0编辑  收藏  举报