SpringMVC會在dispatchServlet攔截請求,所有在我們配置的時候,如果將所有請求都攔截了,連同靜態資源也會攔截。
有兩種方式對靜態資源進行訪問:
1、配置default-servlet-handler,SpringMVC上下文中定義一個DefaultServletHttpRequestHandler,它會檢查DispatchServlet的URL。然後如果發現是靜態資源,就由web應用服務器的默認Servlet處理,如果是其他請求就直接交由相應的handler處理。
2、使用mvc:resources配置,定義相應的靜態資源映射。
配置default-servlet-handler非常簡單,就一行配置就完成了:
<mvc:default-servlet-handler />
使用mvc:resources配置也不復雜:
<mvc:resources mapping="/resource" location="/" /> mapping是訪問的路徑,location是實際的訪問資源的位置。
例如我想訪問/image/abc.jpg 在客戶端輸入的路徑就爲/resource/image/abc.jpg
靜態資源緩存
我們可以使用靜態緩存cache-period,但是緩存之後,如果我們的靜態資源文件更新了,用戶也是用舊緩存的,只要未達到過期時間。
<mvc:resources cache-period="2592000" mapping="/#{re.resourcePath}/**" location="/"/>
所以我們希望在我們更新靜態資源後,用戶會使用新的靜態資源,所以我們需要採用動態的mapping資源映射目錄。
public class ResourcePathExposer implements ServletContextAware { private ServletContext servletContext; private String resourcePath; public void init(){ String version = "1.0"; String path = "/resource"; this.resourcePath = path + "-" + version; this.servletContext.setAttribute("resourcePath",this.resourcePath); } public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } public ServletContext getServletContext() { return servletContext; } public String getResourcePath() { return resourcePath; } public void setResourcePath(String resourcePath) { this.resourcePath = resourcePath; } }實現ServletContextAware接口獲得ServletContext,然後通過ServletContext將映射目錄進行動態定義。這裏現在的目錄爲/resource-1.0,如果我們需要更改靜態文件,就直接修改爲1.1或者其他即可。然後將這個類配置爲MVC的bean,然後配置mvc:resources的時候使用SpringEL表達式獲得這個bean的resourcePath屬性:
<bean id="re" class="com.maxfunner.web.ResourcePathExposer" init-method="init"/> <mvc:resources cache-period="2592000" mapping="/#{re.resourcePath}/**" location="/"/>因爲我們在ResourcePathExposer 將resourcePath 這個屬性寫到了context的attribute當中。所以在JSP頁面可以直接獲得這個屬性的值:
<img src="<c:url value="/" />${applicationScope.resourcePath}/image/${imagePath}"/>
這樣我們就能又做到緩存也能夠做到更新最後不讀取緩存的靜態資源。
SpringMVC Intercepter 攔截器
SpringMVC 的Intercepter 是一個相對比較簡單的功能,主要就完成攔截的工作任務,實現攔截器需要實現HandlerInterceptor接口,裏面有三大方法。
public class TestIntercepter implements HandlerInterceptor { //在調用handler處理方法之前調用,參數有request response 和 handler 如果返回false則不調用到handler當中 public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception { System.out.println("(uri:"+httpServletRequest.getRequestURI()+")>>>>>>>preHandle:"+handler.getClass().getName()); if(httpServletRequest.getRequestURI().equals("/springreview/user/main.html")){ httpServletResponse.sendRedirect("/springreview/user/login.html"); return false; } Map<String, String[]> params = httpServletRequest.getParameterMap(); Set<String> keySets = params.keySet(); for (String key : keySets) { System.out.print(key + "->"); String[] values = params.get(key); for (String valueItem : values) { System.out.print(" " + valueItem); } System.out.println(""); } return true; } //在調用handler之後執行,參數除了有request response 和 handler之外還提供了handler所返回的modelAndView public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, ModelAndView modelAndView) throws Exception { modelAndView.addObject("IntercepterMessage", "TEST"); System.out.println(">>>>>>>postHandle:"+handler.getClass().getName()); } //在渲染完View之後執行 public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
相關的三個方法已經提供了相應的註釋,但是方法的內容我一會再說,先看看配置文件對interceptor的配置:
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/user/*"/> <bean class="com.maxfunner.web.TestIntercepter"/> </mvc:interceptor> </mvc:interceptors>這裏可以看就到mapping是代表所需要攔截的目標uri,而bean就是interceptor的實現類,當然我們可以添加多個interceptor 執行的順序跟<mvc:interceptor>定義的順序一致。preHandle是由上至下執行 postHandle是由下至上執行。這個跟filter的執行一致。
在preHandle這個方法當中我們通過request對象getParameterMap獲得所有請求參數。如果我們對參數提交檢查失敗或者某些頁面需要特定的權限或這個請求沒有允許登入,我們可以使用response對象sendRedirect到指定的頁面當中,並返回false 代表攔截,並不繼續執行其餘的interceptor和目標的handler。如果我們sendRedirect之後返回true,會報需要注意。
postHandle方法可以在modelAndView添加一些模型屬性 進行相應的渲染,甚至改變其viewName。