java web 之 listen 與 filter

来源:https://www.cnblogs.com/lzhh/archive/2018/01/14/javaweb_0.html
-Advertisement-
Play Games

一、Listener監聽器 Javaweb開發中的監聽器,是用於監聽web常見對象 HttpServletRequest HttpSession ServletContext 監聽它們的創建與銷毀、屬性變化 以及session綁定javaBean 1、監聽機制 事件 就是一個事情 事件源 產生這個事 ...


一、Listener監聽器

Javaweb開發中的監聽器,是用於監聽web常見對象 HttpServletRequest HttpSession ServletContext

監聽它們的創建與銷毀屬性變化 以及session綁定javaBean

1監聽機制

  • 事件  就是一個事情
  • 事件源  產生這個事情的源頭
  • 監聽器  用於監聽指定的事件的對象
  • 註冊監聽 要想讓監聽器可以監聽到事件產生,必須對其進行註冊。

2Javaweb開發中常見監聽器

2.1監聽域對象的創建與銷毀

  • 監聽ServletContext創建與銷毀  ServletContextListener
  • 監聽HttpSession創建與銷毀  HttpSessionListener
  • 監聽HttpServletRequest創建與銷毀  ServletRequestListener

2.2監聽域對象的屬性變化

  • 監聽ServletContext屬性變化  ServletContextAttributeListener
  • 監聽HttpSession屬性變化  HttpSessionAttributeListener
  • 監聽HttpServletRequest屬性變化  ServletRequestAttributeListener

2.3監聽session綁定javaBean

它是用於監聽javaBean對象是否綁定到了session域   HttpSessionBindingListener

它是用於監聽javaBean對象的活化與鈍化  HttpSessionActivationListener

3監聽器的快速入門

關於創建一個監聽器的步驟

  1. 創建一個類,實現指定的監聽器介面
  2. 重寫介面中的方法
  3. web.xml文件中對監聽器進行註冊。
  4. ServletContext對象的創建與銷毀

3.1關於域對象創建與銷毀的演示

這個對象是在伺服器啟動時創建的,在伺服器關閉時銷毀的。

HttpSession對象的創建與銷毀

HttpSession session=request.getSession();

Session銷毀 的方法

  1. 預設超時  30分鐘
  2. 關閉伺服器
  3. invalidate()方法
  4. setMaxInactiveInterval(int interval) 可以設置超時時間

問題:直接訪問一個jsp頁面時,是否會創建session?

會創建,因為我們預設情況下是可以在jsp頁面中直接使用session內置對象的。

HttpServletRequest創建與銷毀

Request對象是發送請求伺服器就會創建它,當響應產生時,request對象就會銷毀。

3.2演示了Request域對象中屬性變化

java的監聽機制中,它的監聽器中的方法都是有參數的,參數就是事件對象,而我們可以通過事件對象直接獲取事件源。

3.3演示session綁定javaBean

1、javaBean對象自動感知被綁定到session.

HttpSessionBindingListener 這個介面是由javaBean實現的,並且不需要在web.xml文件中註冊.

2、javabean對象可以活化或鈍化到session中。

HttpSessionActivationListener如果javaBean實現了這個介面,那麼當我們正常關閉伺服器時,session中的javaBean對象就會被鈍化到我們指定的文件中。

當下一次在啟動伺服器,因為我們已經將對象寫入到文件中,這時就會自動將javaBean對象活化到session中。

我們還需要個context.xml文件來配置鈍化時存儲的文件

meta-inf目錄下創建一個context.xml文件

<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="it315"/>
</Manager>
</Context>

案例-定時銷毀session

1、怎樣可以將每一個創建的session全都保存起來?

我們可以做一個HttpSessionListener,當session對象創建時,就將這個session對象裝入到一個集合中.

將集合List<HttpSession>保存到ServletContext域中。

2、怎樣可以判斷session過期了?

HttpSession中有一個方法public long getLastAccessedTime()

它可以得到session對象最後使用的時間,可以使用invalidate方法銷毀。

ps(我們上面的操作需要使用任務調度功能.)java中有一個Timer定時器類

 

package com.timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TestTimer {
    public static void main(String[] args) {
        Timer t = new Timer();
        
        t.schedule(new TimerTask() {
            
            @Override
            public void run() {
                System.out.println(new Date().toLocaleString());
            }
        }, 2000, 1000);
    }
}

關於三個域對象獲取

如果在Servlet中要獲取request在方法上就有,request.getSession()  getServletContext();

如果我們有request對象了,  request.getSession()    request.getSession().getServletCotnext();

 

public class MySessionListener implements HttpSessionListener {

    public void sessionCreated(HttpSessionEvent arg0) {
        HttpSession session = arg0.getSession();
        //得到application中的list集合
        ServletContext application = session.getServletContext();
        //得到session對象,並放入list集合
        List<HttpSession> list =(List<HttpSession>) application.getAttribute("sessions");
        list.add(session);
        System.out.println("添加了"+session.getId());
    }
    public void sessionDestroyed(HttpSessionEvent arg0) {
        // TODO Auto-generated method stub
    }

}

程式在使用時,需要考慮併發問題,因為我們在web中,它一定是一個多線程的,那麼我們的程式對集合進行了添加,還有移除操作。具體在MyServletContextListener的方法中如下

public class MyServletContextListener implements ServletContextListener {
    public void contextDestroyed(ServletContextEvent arg0) {   
    }
    public void contextInitialized(ServletContextEvent arg0) {
        //通過事件原對象得到事件源
            ServletContext application = arg0.getServletContext();
            //創建一個集合 存儲所有session對象
            final List<HttpSession> list = Collections.synchronizedList(new ArrayList<HttpSession>());
            application.setAttribute("sessions", list);
            //創建一個計時器對象
            Timer t = new Timer();
            t.schedule(new TimerTask() {
                
                @Override
                public void run() {
                    System.out.println("開始掃描");
                    for (Iterator iterator = list.iterator(); iterator.hasNext();) {
                        HttpSession session = (HttpSession) iterator.next();
                        long l = System.currentTimeMillis() - session.getLastAccessedTime();
                        if(l > 5000){
                            System.out.println("session移除了"+session.getId());
                            session.invalidate();
                            iterator.remove();
                        }
                    }
                }
            }, 2000, 5000);    
    }
}

二、Filter

 

二、Filter過濾器(重要)

Javaweb中的過濾器可以攔截所有訪問web資源的請求或響應操作。

1.1、步驟:

  1. 創建一個類實現Filter介面
  2. 重寫介面中方法  doFilter方法是真正過濾的。
  3. 在web.xml文件中配置

註意:在Filter的doFilter方法內如果沒有執行chain.doFilter(request,response),那麼資源是不會被訪問到的。

 

1.2、FilterChain

FilterChain 是 servlet 容器為開發人員提供的對象,它提供了對某一資源的已過濾請求調用鏈的視圖。過濾器使用 FilterChain 調用鏈中的下一個過濾器,如果調用的過濾器是鏈中的最後一個過濾器,則調用鏈末尾的資源。

問題:怎樣可以形成一個Filter鏈?

  只要多個Filter對同一個資源進行攔截就可以形成Filter鏈

問題:怎樣確定Filter的執行順序?

  由<filter-mapping>來確定

1.3、Filter生命周期

Servlet生命周期:

實例化 --》 初始化 --》 服務 --》 銷毀

  • 1 當伺服器啟動,會創建Filter對象,並調用init方法,只調用一次.
  • 2 當訪問資源時,路徑與Filter的攔截路徑匹配,會執行Filter中的doFilter方法,這個方法是真正攔截操作的方法.
  • 3 當伺服器關閉時,會調用Filter的destroy方法來進行銷毀操作.

1.4、FilterConfig

在Filter的init方法上有一個參數,類型就是FilterConfig.

FilterConfig它是Filter的配置對象,它可以完成下列功能

  1. 獲取Filtr名稱
  2. 獲取Filter初始化參數
  3. 獲取ServletContext對象。

問題:怎樣在Filter中獲取一個FIlterConfig對象?

 1 package com.itheima.filter;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.Filter;
 6 import javax.servlet.FilterChain;
 7 import javax.servlet.FilterConfig;
 8 import javax.servlet.ServletException;
 9 import javax.servlet.ServletRequest;
10 import javax.servlet.ServletResponse;
11 
12 public class MyFilterConfigTest implements Filter{
13 
14     private FilterConfig filterConfig;
15 
16     public void init(FilterConfig filterConfig) throws ServletException {
17         this.filterConfig = filterConfig;
18     }
19 
20     public void doFilter(ServletRequest request, ServletResponse response,
21             FilterChain chain) throws IOException, ServletException {
22         //通過FilterConfig對象獲取到配置文件中的初始化信息
23         String encoding = filterConfig.getInitParameter("encoding");
24         System.out.println(encoding);
25         request.setCharacterEncoding(encoding);
26         //放行
27         chain.doFilter(request, response);
28     }
29 
30     public void destroy() {
31         // TODO Auto-generated method stub
32     }
33 }

如下 web.xml配置
<filter>
    <filter-name>MyFilterConfigTest</filter-name>
    <filter-class>com.itheima.filter.MyFilterConfigTest</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>MyFilterConfigTest</filter-name>
    <servlet-name>ServletDemo2</servlet-name>
</filter-mapping>

1.5、Filter配置

基本配置

<filter>
<filter-name>filter名稱</filter-name>
<filter-class>Filter類的包名.類名</filter-class>
</filter>
<filter-mapping>
<filter-name>filter名稱</filter-name>
<url-pattern>路徑</url-pattern>
</filter-mapping>

 

關於其它配置

1.<url-pattern>

完全匹配   以”/demo1”開始,不包含通配符*

目錄匹配   以”/”開始  以*結束

擴展名匹配  *.xxx  不能寫成/*.xxx

2.<servlet-name>

它是對指定的servlet名稱的servlet進行攔截的。

3.<dispatcher>

可以取的值有  REQUEST  FORWARD  ERROR  INCLUDE    根據跳轉方式攔截

它的作用是:當以什麼方式去訪問web資源時,進行攔截操作.

1.REQUEST 當是從瀏覽器直接訪問資源,或是重定向到某個資源時進行攔截方式配置的 它也是預設值

2.FORWARD 它描述的是請求轉發的攔截方式配置

3.ERROR 如果目標資源是通過聲明式異常處理機制調用時,那麼該過濾器將被調用。除此之外,過濾器不會被調用。

4.INCLUDE 如果目標資源是通過RequestDispatcher的include()方法訪問時,那麼該過濾器將被調用。除此之外,該過濾器不會被調用

 三、自動登錄  (PS bean的屬性名和資料庫里的欄位名千萬要一樣哦 不然會emmm 很慘)

  1. 當用戶登陸成功後,判斷是否勾選了自動登陸,如果勾選了,就將用戶名與密碼持久化存儲到cookie
  2. 做一個Filter,對需要自動登陸的資源進行攔截

首寫要在登錄Servlet中登錄成功時把登錄的信息保存在cookie里,並設置存活時間

if(null != user){
            String autologin = request.getParameter("autologin");
            
            Cookie cookie = new Cookie("user", user.getUsername()+"&"+user.getPassword());
            cookie.setPath("/");
            if(autologin != null){// on / null
                cookie.setMaxAge(60*60*24*7);
            }else{
                cookie.setMaxAge(0);
            }
            response.addCookie(cookie);
            request.getSession().setAttribute("user", user);
            request.getRequestDispatcher("/home.jsp").forward(request, response);
        }

 然後設置好filter類 記住要在web.xml裡面配置  如下 為 doFilter代碼

public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {
        //1、轉換對象
        HttpServletRequest req = (HttpServletRequest) arg0;
        String uri = req.getRequestURI();
        String path = req.getContextPath();
        path = uri.substring(path.length());
        
        if(!("/login.jsp".equals(path)||"/servlet/loginServlet".equals(path))){
            
            User user = (User) req.getSession().getAttribute("user");
            if(user == null){
                //2、處理業務
                Cookie[] cookies = req.getCookies();
                String username = "";
                String password = "";
                for (int i = 0;cookies!=null && i < cookies.length; i++) {
                    if("user".equals(cookies[i].getName())){
                        String value = cookies[i].getValue();
                        String[] values = value.split("&");
                        username = values[0];
                        password = values[1];
                    }
                }
                UserService us = new UserService();
                User u = us.findUser(username, password);
                if(u != null){
                    req.getSession().setAttribute("user", u);
                }
            }
        }
        //3、放行
        arg2.doFilter(arg0, arg1);
    }

 

ps 當訪問別的頁面時通過判斷session時減少訪問資料庫的操作

四、MD5加密

mysql中可以對數據進行md5加密   Md5(欄位)

UPDATE USER SET PASSWORD=MD5(PASSWORD);

需要一個MD5Utils工具類

package com.util;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Utils {
    /**
     * 使用md5的演算法進行加密
     */
    public static String md5(String plainText) {
        byte[] secretBytes = null;
        try {
            secretBytes = MessageDigest.getInstance("md5").digest(
                    plainText.getBytes());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("沒有md5這個演算法!");
        }
        String md5code = new BigInteger(1, secretBytes).toString(16);
        for (int i = 0; i < 32 - md5code.length(); i++) {
            md5code = "0" + md5code;
        }
        return md5code;
    }
}

 
這樣在loginservlet調用一下方法轉化一下就ok了。

五、全局的編碼過濾器

之前做的操作,只能對post請求是ok

 

 

怎樣可以做成一個通用的,可以處理post,get所有的請求的?

在java中怎樣可以對一個方法進行功能增強?

  1. 繼承
  2. 裝飾設
    1. 創建一個類讓它與被裝飾類實現同一個介面或繼承同一個父類
    2. 在裝飾類中持有一個被裝飾類的引用
    3. 重寫要增強的方法

我們可以用getparameterMap這個方法來實現getparameter和getparametervalues兩個方法 即MyFilter 最終版本

package com.filter;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class MyFilter implements Filter{

    public void destroy() {
        // TODO Auto-generated method stub
        
    }

    public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) arg0;
        req = new MyRequest(req);
        arg2.doFilter(req, arg1);
        
    }

    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
        
    }

}
class MyRequest extends HttpServletRequestWrapper{

    private HttpServletRequest request;

    public MyRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    /*@Override
    public String getParameter(String name) {
        name = request.getParameter(name);
        try {
            return new String(name.getBytes("iso-8859-1"),"UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }*/
    @Override
    public String getParameter(String name) {
        Map<String, String[]> map = getParameterMap();
        return map.get(name)[0];
    }
    @Override
    public String[] getParameterValues(String name) {
        Map<String, String[]> map = getParameterMap();
        return map.get(name);
    }
    private boolean flag = true; //防止重覆
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> map = request.getParameterMap();
        if(flag){
            for (Map.Entry<String, String[]> m : map.entrySet()) {
                String[] values = m.getValue();
                for (int i = 0; i < values.length; i++) {
                    try {
                        values[i] = new String(values[i].getBytes("iso-8859-1"),"UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            }
            flag =false;
        }
        return map;
    }
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 很多人喜歡逛油管看視頻,自然就會有一些喜歡的收藏集或者視頻作者,有時候想要下載下來保存在本地播放,這樣的話就不用每次FQ,畢竟有些代理的速度並不是很理想(如果你的代理速度炒雞快的話,請忽略這篇文章)。 當你想下載油管視頻,又覺得一些下載網站或者工具無法滿足你的要求的時候,比如我想定製下載的清晰度,我 ...
  • "如何處理 Python 入門難以進步的現象?" "Python 練習冊,每天一個小程式" " Python之美[從菜鳥到高手" " Python實戰" "Python 的練手項目有哪些值得推薦?" "廖雪峰實戰" "菜鳥教程實例(3.3)" "菜鳥教程100例(2.7)" PS :找的一些學習的東 ...
  • 一、重構簡單的CRUD 1.JDBC工具類 1.因為在crud中都包含一些相同的代碼所以可以提取出來,抽取代碼重構為工具類。 2.將工具類設置為static靜態類,方便調用,不需要new對象。 二、使用預編譯sql語句 1.預編譯sql語句的好處 1.效率高,預編譯對象把一些格式固定的SQL編譯後, ...
  • (一)指針數組 指針數組就是每一個元素存放一個地址,相當於一個指針變數。如:int *p[4]指針數組比較適合用來指向若幹字元串,使得處理字元串更加靈活。例如,現在要將若幹字元串按字母順序由小到大輸出 通過上例子,試比較if(strcmp(name[k],name[j])>0)和if(strcmp( ...
  • 上次通過eclipse在控制台輸出了hello world,是不是有點小激動啊,今天接著介紹Java基礎知識。 一、Java註釋 1、Java註釋語句不會被編譯器運行,不用擔心代碼因為許多註釋語句顯得臃腫而影響程式運行速度。 2、Java註釋有三種寫法。 一是雙斜杠 // 。需要註掉哪一行就添加到哪 ...
  • 1.python模塊:標準庫和第三方庫,第三方庫需要下載安裝2.模塊sys:命令 功能 sys.stdin 標準輸入流sys.stdout 標準輸出流sys.stderr 標準錯誤流 sys.argv[value] 接收命令行的參數。例如,windows下的命令行cmd裡面的參數。其中,argv[0 ...
  • 1. Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,Boot致力於在蓬勃發展的快速應用開發領域(rapid application de ...
  • Using mac os python3.6 to connect ssl will occur urllib.error.URLError. It requires a post-install step, which installs the certifi package of certifi ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...