SpringMVC學習記錄
注意:以下內容是學習 北京動力節點 的SpringMVC視頻后所記錄的筆記、原始碼以及個人的理解等,記錄下來僅供學習
第4章 SpringMVC 核心技術
4.3 攔截器
??SpringMVC 中的 Interceptor 攔截器是非常重要和相當有用的,它的主要作用是攔截指定的用戶請求,并進行相應的預處理與后處理,其攔截的時間點在“處理器映射器根據用戶提交的請求映射出了所要執行的處理器類,并且也找到了要執行該處理器類的處理器配接器,在處理器配接器執行處理器之前”,當然,在處理器映射器映射出所要執行的處理器類時,已經將攔截器與處理器組合為了一個處理器執行鏈,并回傳給了中央調度器,
4.3.1 一個攔截器的執行
自定義攔截器
package com.bjpowernode.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
//攔截器類:攔截用戶的請求,
public class MyInterceptor implements HandlerInterceptor {
private long btime = 0;
/*
* preHandle叫做預處理方法,
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
btime = System.currentTimeMillis();
System.out.println("攔截器的MyInterceptor的preHandle()");
//計算的業務邏輯,根據計算結果,回傳true或者false
//給瀏覽器一個回傳結果 //request.getRequestDispatcher("/tips.jsp").forward(request,response);
return true;
}
/*
postHandle:后處理方法,
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler, ModelAndView mv) throws Exception {
System.out.println("攔截器的MyInterceptor的postHandle()");
//對原來的doSome執行結果,需要調整,
if( mv != null){
//修改資料
mv.addObject("mydate",new Date());
//修改視圖
mv.setViewName("other");
}
}
/*
afterCompletion:最后執行的方法
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("攔截器的MyInterceptor的afterCompletion()");
long etime = System.currentTimeMillis();
System.out.println("計算從preHandle到請求處理完成的時間:"+(etime - btime ));
}
}
自定義攔截器,需要實作Handlerinterceptor介面,而該介面中含有三個方法:
1、 preHandle(request,response, Object handler) 預處理方法:
??該方法在處理器方法執行之前執行,其回傳值為boolean,若為true,則緊接著會執行處理器方 法,且會將afterCompletion()方法放入到一個專門的方法堆疊中等待執行,
重要:
是整個專案的入口,門戶, 當preHandle回傳true 請求可以被處理, preHandle回傳false,請求到此方法就截止,
引數:
Object handler : 被攔截的控制器物件
回傳值boolean
true:請求是通過了攔截器的驗證,可以執行處理器方法,
攔截器的MyInterceptor的preHandle()
=====執行MyController中的doSome方法=====
攔截器的MyInterceptor的postHandle()
攔截器的MyInterceptor的afterCompletion()
false:請求沒有通過攔截器的驗證,請求到達攔截器就截止了, 請求沒有被處理
攔截器的MyInterceptor的preHandle()
特點:
a.方法在控制器方法(MyController的doSome)之前先執行的, 用戶的請求首先到達此方法
b.在這個方法中可以獲取請求的資訊, 驗證請求是否符合要求,可以驗證用戶是否登錄, 驗證用戶是否有權限訪問某個連接地址(url),
如果驗證失敗,可以截斷請求,請求不能被處理,
如果驗證成功,可以放行請求,此時控制器方法才能執行,
2、postHandle(request/response/ Object handlei,modelAndView) 后處理方法:
?該方法在處理器方法執行之后執行,處理器方法若最終未被執行,則該方法不會執行, 由于該方法是在處理器方法執行完后執行,且該方法引數中包含ModelAndView,所以該方法可以修 改處理器方法的處理結果資料,且可以修改跳轉方向,
引數:
Object handler:被攔截的處理器物件MyController
ModelAndView mv:處理器方法的回傳值
特點:
a.在處理器方法之后執行的(MyController.doSome())
b.能夠獲取到處理器方法的回傳值ModelAndView,可以修改ModelAndView中的
資料和視圖,可以影響到最后的執行結果,
c.主要是對原來的執行結果做二次修正,
ModelAndView mv = MyController.doSome();
postHandle(request,response,handler,mv);
3、afterCompletion(request,response, Object handler, Exception ex)最后執行的方法:
?當preHandle()方法回傳true時,會將該方法放到專門的方法堆疊中,等到對請求進行回應的所有 作業完成之后才執行該方法,即該方法是在中央調度器渲染(資料填充)了回應頁面之后執行的,此 時對ModelAndView再操作也對回應無濟于事,
afterCompletion**最后執行的方法,清除資源,例如在Controller方法中加入資料
引數
Object handler:被攔截器的處理器物件
Exception ex:程式中發生的例外
特點:
a.在請求處理完成后執行的,框架中規定是當你的視圖處理完成后,對視圖執行了forward,就認為請求處理完成,
b.一般做資源回收作業的, 程式請求程序中創建了一些物件,在這里可以洗掉,把占用的記憶體回收,
攔截器中方法與處理器方法的執行順序如下圖:

換一種表現方式,也可以這樣理解:

(1) 注冊攔截器
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--宣告組件掃描器-->
<context:component-scan base-package="com.bjpowernode.controller" />
<!--宣告 springmvc框架中的視圖決議器, 幫助開發人員設定視圖檔案的路徑-->
<bean >
<!--前綴:視圖檔案的路徑-->
<property name="prefix" value="https://www.cnblogs.com/WEB-INF/view/" />
<!--后綴:視圖檔案的擴展名-->
<property name="suffix" value="https://www.cnblogs.com/chuchq/p/.jsp" />
</bean>
<!--宣告攔截器: 攔截器可以有0或多個-->
<mvc:interceptors>
<!--宣告第一個攔截器-->
<mvc:interceptor>
<!--指定攔截的請求uri地址
path:就是uri地址,可以使用通配符 **
** : 表示任意的字符,檔案或者多級目錄和目錄中的檔案
http://localhost:8080/myweb/user/listUser.do
http://localhost:8080/myweb/student/addStudent.do
-->
<mvc:mapping path="/**"/>
<!--宣告攔截器物件-->
<bean />
</mvc:interceptor>
</mvc:interceptors>
</beans>
mvc:mapping/用于指定當前所注冊的攔截器可以攔截的請求路徑,而 /**表示攔截所 有請求,
(2) 修改 index 頁面
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String basePath = request.getScheme() + "://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/";
%>
<html>
<head>
<title>Title</title>
<base href="https://www.cnblogs.com/chuchq/p/" />
</head>
<body>
<p>一個攔截器</p>
<form action="some.do" method="post">
姓名:<input type="text" name="name"> <br/>
年齡:<input type="text" name="age"> <br/>
<input type="submit" value="https://www.cnblogs.com/chuchq/p/提交請求">
</form>
</body>
</html>
(3) 修改處理器
MyController.java
package com.bjpowernode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* @RequestMapping:
* value : 所有請求地址的公共部分,叫做模塊名稱
* 位置: 放在類的上面
*/
@Controller
public class MyController {
@RequestMapping(value = "https://www.cnblogs.com/some.do")
public ModelAndView doSome(String name,Integer age) {
System.out.println("=====執行MyController中的doSome方法=====");
//處理some.do請求了, 相當于service呼叫處理完成了,
ModelAndView mv = new ModelAndView();
mv.addObject("myname",name);
mv.addObject("myage",age);
mv.setViewName("show");
return mv;
}
}
(4) 修改 show 頁面
show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>/WEB-INF/view/show.jsp從request作用域獲取資料</h3><br/>
<h3>myname資料:${myname}</h3><br/>
<h3>myage資料:${myage}</h3>
</body>
</html>
4.3.2 多個攔截器的執行
專案在4.3.1的基礎上
專案結構

(1) 再定義一個攔截器
MyInterceptor2 .java
package com.bjpowernode.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//攔截器類:攔截用戶的請求,
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("22222-攔截器的MyInterceptor的preHandle()");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler, ModelAndView mv) throws Exception {
System.out.println("22222-攔截器的MyInterceptor的postHandle()");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("22222-攔截器的MyInterceptor的afterCompletion()");
}
}
(2) 多個攔截器的注冊與執行
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--宣告組件掃描器-->
<context:component-scan base-package="com.bjpowernode.controller" />
<!--宣告 springmvc框架中的視圖決議器, 幫助開發人員設定視圖檔案的路徑-->
<bean >
<!--前綴:視圖檔案的路徑-->
<property name="prefix" value="https://www.cnblogs.com/WEB-INF/view/" />
<!--后綴:視圖檔案的擴展名-->
<property name="suffix" value="https://www.cnblogs.com/chuchq/p/.jsp" />
</bean>
<!--宣告攔截器: 攔截器可以有0或多個
在框架中保存多個攔截器是ArrayList,
按照宣告的先后順序放入到ArrayList
-->
<mvc:interceptors>
<!--宣告第一個攔截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!--宣告攔截器物件-->
<bean />
</mvc:interceptor>
<!--宣告第二個攔截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean />
</mvc:interceptor>
</mvc:interceptors>
</beans>
當有多個攔截器時,形成攔截器鏈,攔截器鏈的執行順序,與其注冊順序一致,需要再次強調一點的是,當某一個攔截器的peHandle()方法回傳 true 并被執行到時,會向一個專門的方法堆疊中放入該攔截器的 afterCompletion()方法,
多個攔截器中方法與處理器方法的執行順序如下圖:

從圖中可以看出,只要有一個preHandle()方法回傳false,則上部的執行鏈將被斷開, 其后續的處理器方法與postHandle()方法將無法執行,但,無論執行鏈執行情況怎樣,只要 方法堆疊中有方法,即執行鏈中只要有preHandle()方法回傳true,就會執行方法堆疊中的 afterCompletion()方法,最終都會給出回應,
換一種表現方式,也可以這樣理解:

4.3.3 公共資源
(1) pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bjpowernode</groupId>
<artifactId>ch11-interceptor2</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--servlet依賴-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jsp依賴-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
<!--springmvc依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 編碼和編譯和JDK版本 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
(2) web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--宣告,注冊springmvc的核心物件DispatcherServlet
需要在tomcat服務器啟動后,創建DispatcherServlet物件的實體,
為什么要創建DispatcherServlet物件的實體呢?
因為DispatcherServlet在他的創建程序中, 會同時創建springmvc容器物件,
讀取springmvc的組態檔,把這個組態檔中的物件都創建好, 當用戶發起
請求時就可以直接使用物件了,
servlet的初始化會執行init()方法, DispatcherServlet在init()中{
//創建容器,讀取組態檔
WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml");
//把容器物件放入到ServletContext中
getServletContext().setAttribute(key, ctx);
}
啟動tomcat報錯,讀取這個檔案 /WEB-INF/springmvc-servlet.xml(/WEB-INF/myweb-servlet.xml)
springmvc創建容器物件時,讀取的組態檔默認是/WEB-INF/<servlet-name>-servlet.xml .
-->
<servlet>
<servlet-name>myweb</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--自定義springmvc讀取的組態檔的位置-->
<init-param>
<!--springmvc的組態檔的位置的屬性-->
<param-name>contextConfigLocation</param-name>
<!--指定自定義檔案的位置-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--在tomcat啟動后,創建Servlet物件
load-on-startup:表示tomcat啟動后創建物件的順序,它的值是整數,數值越小,
tomcat創建物件的時間越早, 大于等于0的整數,
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myweb</servlet-name>
<!--
使用框架的時候, url-pattern可以使用兩種值
1. 使用擴展名方式, 語法 *.xxxx , xxxx是自定義的擴展名, 常用的方式 *.do, *.action, *.mvc等等
不能使用 *.jsp
http://localhost:8080/myweb/some.do
http://localhost:8080/myweb/other.do
2.使用斜杠 "/"
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/263305.html
標籤:Java
上一篇:c++函式指標說明
下一篇:4種GC日志解讀和分析
