1-Listener介紹與接口調用原理
Listener-監聽器:利用接口調用,監聽某一個事件的發生,狀態的改變
監聽器總共有8個,分成三種類型↓
一類:監聽作用域的創建和銷燬
二類:監聽作用域中屬性的創建銷燬和替換
三類:Session值的鈍化和活化(Activation)
接口調用:假設A類方法中的參數爲一個接口,而你在Test類中要調用A的方法,那麼只能通過編寫接口和實例化來調用A的方法
2-Listener監聽三個作用域創建和銷燬
監聽器的新建要在web.xml中先配置
先回憶一下有哪幾個作用域以及作用域的對象是什麼:
1、pageContext - PageContext
2、request - HttpServletRequest
3、session - HttpSession
4、application - ServletContext
我們主要對下面2、3、4三個作用域進行監聽,每個作用域的監聽器對象其實就是在作用域對象名後+Listener
-
ServletContextListener
servletcontext創建:
啓動服務器的時候
servletContext銷燬:
關閉服務器、從服務器移除項目
-
ServletRequestListener(比較少用)
request創建:
訪問服務器上的任意資源都會有請求出現。 訪問 html、訪問 jsp、訪問 servlet
request銷燬:
服務器已經對這次請求作出了響應之後
public class MyRequestListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent sre) { System.out.println("servletrequest 銷燬了"); } @Override public void requestInitialized(ServletRequestEvent sre) { System.out.println("servletrequest 初始化了"); } }
-
HttpSessionListener
session的創建
只要有調用getSession就創建。 html:(沒有Session的調用) jsp:(默認調用getSession) servlet:(默認調用getSession)
session的銷燬
1、超時,30分鐘 2、非正常關閉,銷燬 3、正常關閉服務器(序列化)
public class MySessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("創建session了"); } @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("銷燬session了"); } }
監聽器作用:
利用它來,在作用域對象創建的時候
1. 完成自己想要的初始化工作
2. 執行自定義任務調度 執行某一個任務 Timer(定時器)
3-Listener監聽三個作用域屬性狀態變更
使用AttributeListener重寫並查看狀態變更
其中有屬性:添加(set)、替換(set:key一樣)、移出(remove)三種狀態
- servletContext — ServletContextAttributeListene
- request — ServletRequestAttributeListener
- session — HttpSessionAttributeListener
HttpSessionBindingListener(比較少用,作用類似,就是看是否添加或移出屬性)
> 監聽對象與session綁定和解除綁定的動作
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("對象被綁定進來了");
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("對象被解除綁定");
}
這裏有必要解釋一下HttpSessionBindingListener與HttpSessionAttributeListener的區別。
首先,兩者的作用類似,都是監聽對象的添加與解除,最大的區別就是,BindingListener要一個待監聽對象去實現這個接口,然後在Session中添加該對象的時候纔會觸發監聽器,但是如果你添加了其他對象,這個監聽器是不會被觸發的。
相反,AttributeListener也是要一個類去實現,在web.xml中配置要監聽的Session對象,注意是Session對象,也就是說,只要Session中無論添加了什麼對象,都會觸發這個監聽器,可以理解爲這是一個安檢門。
4-Listener監聽HttpSession鈍化活化
上面所說的兩種監聽器都必須在xml文件中進行註冊,而最後一種監聽器不需要註冊,只需要實現接口
HttpSessionActivationListener
用於監聽現在session的值是鈍化(序列化)還是活化(反序列化)的動作
1、鈍化 (序列化)
把內存中的數據 存儲到硬盤上
2、活化 (反序列化)
一定要實現Serializable接口 若已經鈍化,則重啓服務器就自動活化了 即把硬盤中的數據讀取到內存中
爲什麼要有鈍化活化?
Session中存放過多的值會增加內存負擔,所以我們可以把暫時不用的東西先鈍化,要用的時候活化
自動執行鈍化的事件默認是30分鐘,我們可以手動配置事件和路徑
如何配置Session自動鈍化?
1、在tomcat/conf/context.xml 裏面配置
對所有的運行在這個服務器的項目生效
2、在conf/Catalina/localhost/context.xml 配置
對 localhost生效 localhost:8080
3、在web工程項目中的META-INF/context.xml配置
只對當前的工程生效
#maxIdleSwap : 1分鐘不用就鈍化
#directory : 鈍化後的那個文件存放的目錄位置。
#D:\tomcat\apache-tomcat-7.0.52\work\Catalina\localhost\ListenerDemo\helloworld
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="helloworld"/>
</Manager>
</Context>
5-Filter介紹與簡單使用
Filter 其實就是對客戶端發出來的請求進行過濾,瀏覽器發出,然後服務器派servlet處理,在中間就可以過濾,其實過濾器起到的是攔截的作用
比如它可以做什麼?
1. 對一些敏感詞彙進行過濾
2. 統一設置編碼
3. 自動登錄
…
Filter的生命週期:在服務器加載該項目時創建,在服務器關閉或從服務器移除該項目時銷燬
Filter的執行順序:
1、客戶端發出請求,先經過過濾器 如果過濾器放行,那麼才能到servlet
2、如果有多個過濾器,則會按照註冊的映射順序來排隊,如果只有一個過濾器不放行,那麼後面排隊的過濾器以及servlet都不會受到請求
Filter的簡單使用:
1、定義一個類 實現Filter
public class FilterDemo implements Filter {
public void destroy() {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter……");
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {}
}
2、註冊過濾器
#在web.xml裏面註冊 註冊的手法與servlet基本一樣
<filter>
<display-name>FilterDemo</display-name>
<filter-name>FilterDemo</filter-name>
<filter-class>com.itheima.filter.FilterDemo</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Filter的一些細節:
1、如果想放行,那麼在doFilter方法裏面操作,使用參數chain的
chain.doFilter(request, response);放行,讓請求到達下一個目標
2、<url-pattern>/*</url-pattern>
寫法格式與servlet一樣
1. 全路徑匹配 以 / 開始
2. 以目錄匹配 以 / 開始 以 * 結束
3. 以後綴名匹配 以 * 開始 以後綴名結束
3、針對 dispatcher 設置
REQUEST : 只要是請求過來,都攔截,默認就是REQUEST
FORWARD : 只要是轉發都攔截
ERROR : 頁面出錯發生跳轉
INCLUDE : 包含頁面的時候就攔截
6-Filter實現自動登錄
1、案例分析
2、搭建好數據庫(用戶信息),頁面(jsp)
3、AutoLoginFilter(主要代碼):
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
//1.首先,無論用戶進入什麼頁面,先判斷用戶是否登陸並且沒關閉瀏覽器
HttpServletRequest req = (HttpServletRequest) request;
//如果已登錄且沒關閉瀏覽器,則自動放行
if(req.getSession().getAttribute("user")!=null){
chain.doFilter(request, response);
}else{//session值不存在
Cookie[] cookies = req.getCookies();
Cookie cookie = CookieUtil.findCookie(cookies, "autologin");
if(cookie!=null){//如果cookie存在,則說明用戶已經登錄過
String value = cookie.getValue();
String username = value.split("#")[0];
String password = value.split("#")[1];
UserDao dao = new UserDaoImpl();
UserBean user = dao.login(username, password);
req.getSession().setAttribute("user", user);
chain.doFilter(request, response);
}else{
//cookie和session都不存在,直接放行要求登錄
chain.doFilter(request, response);
}
}
} catch (Exception e) {
e.printStackTrace();
chain.doFilter(request, response);
}
}
4、LoginServlet(主要代碼):
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String username = request.getParameter("username");
String password = request.getParameter("password");
String auto_login = "";
auto_login+=request.getParameter("autologin");
System.out.println(auto_login);
// System.out.println(username+"=="+password+"=="+aotologin);
UserDao dao = new UserDaoImpl();
UserBean user = dao.login(username,password);
if(user != null){
//將user存儲到session中
request.getSession().setAttribute("user", user);
if(auto_login.equals("on")){
//設置autologin的Cookie,包含賬號密碼,準備自動登錄
Cookie autologin = new Cookie("autologin", (username+"#"+password));
//設置最長存活時間
autologin.setMaxAge(60*2);
//設置保存路徑
autologin.setPath(request.getContextPath());
response.addCookie(autologin);
}
response.sendRedirect("index.jsp");
}else{
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("賬號或密碼錯誤!請重新登錄!");
response.setHeader("refresh", "3;login.jsp");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
HPF-自我總結
第一次接觸監聽器尤其是過濾器的時候,對於這個自動登錄案例還不是理解的特別到位,但這次寫博客的時候,我對案例的代碼做了修改,而且針對修改過的代碼與原來的代碼做了比較,最後發現了問題所在。總而言之,希望對這兩個組件的理解能夠深刻記下!
——— 不積跬步,無以至千里;不積小流,無以成江海。