springmvc DispatcherServlet和攔截器詳解
阿新 • • 發佈:2019-02-19
1,程式例項
把程式貼下來:web.xml
<servlet> <!--既然DispatcherServlet 寫在這說明 DispatcherServlet也是servlet--> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:config/spring-mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>/</url-pattern> <!-- 不可以用 /* 來代替所有的路徑,這裡攔截的是所有的路徑, 故意的,一般不要這樣寫,而是要加上一些限制 --> </servlet-mapping> <servlet> <servlet-name>ToLogin</servlet-name> <servlet-class>servlet.ToLogin</servlet-class> </servlet> <servlet-mapping> <servlet-name>ToLogin</servlet-name> <url-pattern>/toLogin.do</url-pattern><!-- servlet的請求路徑--> </servlet-mapping>
config包中的 spring-mvc.xml檔案的主要資訊:
<!-- 避免 Dispatcher 攔截掉靜態資源,當靜態資源路徑出現時,交由DispatcherServlet 處理,不會找其他Controller ,而是交給 ResourceHttpRequestHandler 處理,從而找到靜態資源--> <mvc:resources location="/page/" mapping="/page/**"/> <!--配置攔截器, 多個攔截器,順序執行 ,路徑攔截的相同也是互不影響的。--> <mvc:interceptors> <mvc:interceptor> <!-- 匹配的是url路徑, 如果不配置 或 /**,將攔截所有的Controller,這裡為做實驗,採取全攔截 --> <mvc:mapping path="/**" /> <bean class="interceptor.MyInterceptor"></bean> </mvc:interceptor> <!-- 當設定多個攔截器時,先按順序呼叫preHandle方法,然後逆序呼叫每個攔截器的postHandle和afterCompletion方法--> </mvc:interceptors>
配置檔案就這些。
接下來的就是Java程式碼:
ToLogin:路徑是 /toLogin.do public class ToLogin extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("spring MVC 進入 ToLogin "); request.getSession().setAttribute("name","ToLogin.do"); if(request.getCookies()!=null) for(Cookie c:request.getCookies()){ System.out.println(c.getName()+" : "+c.getValue()); } request.getRequestDispatcher("/login.jsp").forward(request, response); } } MyInterceptor: 作用是攔截所有的請求Controller的路徑。 public class MyInterceptor extends HandlerInterceptorAdapter { /* preHandle是一開始就 執行的 方法,並由返回的結果決定--> 後面的 攔截器是否執行 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle 執行!!!"); return false; // 為了說明效果,全部攔截下來 } /* postHandle 是controller正常執行完成後,執行的方法。如果沒有正常執行完成,所有的postHandle 方法都不會執行 */ /* 該方法在controller正常執行完成之後 才會執行,並且在 中央處理器 渲染頁面之前 執行。 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle 執行!!!"); } /* afterCompletion 是隻要該攔截器的preHandle 方法執行的結果為true ,該方法就執行 */ /* * afterCompletion 在所有的工作完成之後,且該該攔截器的 preHandle 返回的結果是 true ,該方法相當於 * try-catch-finally 中的finally ,用來釋放一些資源。 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion 執行!!!"); } } ControllerOne:程式碼 跳轉到 index.jsp頁面 @Controller public class ControllerOne { // @RequestMapping("/hello") 這兩種url的請求方式都是一樣的。一種是絕對路徑,一種是相對路徑 // @RequestMapping("hello") public ModelAndView getHello(int num) { System.out.println("進入hello請求中"); ModelAndView mv = new ModelAndView(); mv.setViewName("/index.jsp"); return mv; } }
請求結果及說明
本專案名為 springMVC 。
1,請求為 :http://localhost:8080/springMVC/login.jsp
結果如上,所載入的圖片沒有顯示出來。檢視控制檯:
Mapped URL path [/page/**] onto handler 'org.springframework.web.servlet.resource.ResourceHttpRequestHandler'
說明配置檔案中的資訊,靜態資源資訊已經交給了ResourceHttpRequestHandler這個Controller處理,DispatcherServlet會將靜態資源交由它處理。
preHandle 執行!!!
說明攔截器起了作用,而雖然請求login.jsp頁面,但是有兩次請求,一次是請求login.jsp第二次是請求 <img alt="你好" src="page/pieBiz.jpg"/> 靜態資源,但是攔截器只攔截一次,且根據結果看,只是攔截了後面的靜態資源的請求,導致沒有加載出圖畫。原因也在上面的日誌輸出上顯示出來了,就是為靜態資源服務的ResourceHttpRequestHandler被攔截,從而不會被處理的原因。
下一個請求:
http://localhost:8080/springMVC/toLogin.do
其實控制檯上沒有出現報錯或警告資訊,這是為什麼呢?畢竟是沒有toLogin.do對應的Controller,那麼DispatcherServlet如何將請求資訊正確轉發呢?其實這麼想就錯了。上面已經提到了DispatcherServlet本身就是一個轉發的servlet,並根據路徑的匹配原則,最長路徑匹配優先匹配的原則,所以當碰到一個合適的servlet就會先執行該servlet,這裡就是ToLogin.java, 同樣原理,jsp就是特殊的servlet,所以會直接訪問到,根本不經過
DispatcherServlet。
下面解決靜態資源無法訪問到的問題:
判斷當前的處理器是否是:org.springframework.web.servlet.resource.ResourceHttpRequestHandler,如果是就說明這個請求其實是靜態資源的請求。就要放行,改後的程式碼如下(攔截其中):
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle 執行!!!");
String str=handler.getClass().getName();
//判斷是否是靜態資源的處理器,是就放行
if("org.springframework.web.servlet.resource.ResourceHttpRequestHandler".equals(str)){
return true;
}
return false;
}
上圖是資源的程式碼層級。
其中index.jsp 和 helloone.html檔案都是普通的檔案,只是展示一些東西。要詳細說明的是 login.jsp :
<body>
<form action="login" method="post">
姓名: <input type="text" name="name" /><br/>
密碼: <input type="password" name="passwd" /><br/>
<input type="submit" value="提交"/>
<input type="reset" value="清空"/>
</form>
<img alt="你好" src="page/pieBiz.jpg"/> //引用的靜態資源
</body>
執行結果如下(圖片被顯示出來):
通過這個例子相信大家已經對springMVC 的攔截器和DispatcherServlet以及servlet,jsp有了進一步的瞭解。