Filter

過(guò)濾器(Filter)

Servlet/Filter/Listener統(tǒng)稱為JavaWeb的三大組件.其中Filter也叫做過(guò)濾器,通過(guò)過(guò)濾器技術(shù)拌滋,開(kāi)發(fā)人員可以實(shí)現(xiàn)用戶在訪問(wèn)某個(gè)資源之前或之后赞辩,對(duì)訪問(wèn)的請(qǐng)求和響應(yīng)進(jìn)行攔截雌芽,從而做一些相關(guān)的處理。

image

總結(jié):

1.所謂的過(guò)濾器诗宣,就是攔截用戶對(duì)資源的訪問(wèn)

2.一個(gè)過(guò)濾器可以攔截多個(gè)資源膘怕,一個(gè)資源也可以配置多個(gè)過(guò)濾器進(jìn)行攔截

3.其實(shí)所謂的攔截,就是將代表請(qǐng)求的request對(duì)象和代表響應(yīng)的response對(duì)象攔截下來(lái),攔截下來(lái)后:

(1)控制是否允許訪問(wèn) – 比如:用戶登陸之后才能訪問(wèn)自己的訂單或購(gòu)物車

(2)在訪問(wèn)資源之前或之后做一些處理 比如: 全站亂碼解決


[toc]

開(kāi)發(fā)過(guò)濾器

1.步驟

Servlet API中提供了一個(gè)Filter接口召庞,開(kāi)發(fā)web應(yīng)用時(shí),如果編寫一個(gè)類實(shí)現(xiàn)了這個(gè)接口来破,則這個(gè)類就是一個(gè)過(guò)濾器類篮灼。

(1)寫一個(gè)類實(shí)現(xiàn)Filter接口,并實(shí)現(xiàn)其中的方法
(2)在web應(yīng)用的web.xml中配置過(guò)濾器所攔截的路徑

2.過(guò)濾器方法

(1)init方法

當(dāng)Filter實(shí)例創(chuàng)建之后徘禁,服務(wù)器立即調(diào)用init方法進(jìn)行初始化的操作.

public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("FilterDemo1實(shí)例已經(jīng)被創(chuàng)建...");
    }
(2)doFilter方法

當(dāng)過(guò)濾器攔截到對(duì)資源的訪問(wèn)時(shí)诅诱,服務(wù)器會(huì)調(diào)用doFilter方法進(jìn)行處理

//
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("FilterDemo1.doFilter()");
    }

FilterChain:代表多個(gè)過(guò)濾器組成的過(guò)濾器鏈對(duì)象

(1)一個(gè)資源可以配置多個(gè)過(guò)濾器進(jìn)行攔截,多個(gè)過(guò)濾器執(zhí)行的順序是按照Filter在web.xml中對(duì)應(yīng)的filter-mapping標(biāo)簽的先后配置順序執(zhí)行的.多個(gè)過(guò)濾器就組成了一條過(guò)濾器鏈.

(2)當(dāng)過(guò)濾器攔截到對(duì)資源的訪問(wèn)時(shí)送朱,如果處理之后放行過(guò)濾器娘荡,即調(diào)用FilterChain中的doFilter方法來(lái)放行過(guò)濾器. 接著才可以執(zhí)行后面的資源

(3)如果后面仍然是過(guò)濾器,則也需要在過(guò)濾器的doFilter方法中調(diào)用FilterChain.doFilter方法才可以放行過(guò)濾器驶沼,執(zhí)行后面的資源.

(4)如果后面沒(méi)有過(guò)濾器炮沐,則訪問(wèn)對(duì)應(yīng)的資源.
也就是說(shuō)當(dāng)所有的過(guò)濾器都調(diào)用了FilterChain的doFilter方法時(shí),才可以放行所有的過(guò)濾器回怜,才可以訪問(wèn)到對(duì)應(yīng)的資源

chain.doFilter(request, response);
(3)destroy方法

在Filter實(shí)例銷毀之前大年,執(zhí)行destroy方法進(jìn)行善后的處理

public void destroy() {
        System.out.println("FilterDemo1實(shí)例將要被銷毀啦...");
    }

3.全站亂碼處理過(guò)濾器

//pakeage:com.znonline.jt.filter
/**
 * 處理全站亂碼的過(guò)濾器
 *  1.處理請(qǐng)求參數(shù)亂碼(GET和POST)
 *  2.處理響應(yīng)正文亂碼
 */
public class EncodingFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {}
    
    /* 處理所攔截到的請(qǐng)求的核心方法
     * (相當(dāng)于Servlet中的service方法) */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("EncodingFilter.doFilter()....");
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        /* POST:
         * 在過(guò)濾器中處理請(qǐng)求參數(shù)亂碼(只需要寫一次, 所有被攔截到的資源的亂碼問(wèn)題都可以解決)
         */
        request.setCharacterEncoding("utf-8");//針對(duì)POST提交
        
        /*
         * 在過(guò)濾器中處理響應(yīng)正文亂碼(只需要寫一次, 
         *   所有被攔截到的資源的亂碼問(wèn)題都可以解決)
         */
        response.setContentType("text/html;charset=utf-8");

        HttpServletRequest myRequest = new MyHttpServletRequest(req);
        //處理完后一定要放行過(guò)濾器, 才可以接著訪問(wèn)下面的資源
        chain.doFilter(myRequest, response);
    }
    
    /* 在Filter實(shí)例銷毀之前立即執(zhí)行
     * 進(jìn)行善后的處理
     */
    public void destroy() {}
}

class MyHttpServletRequest extends HttpServletRequestWrapper{
    private boolean isEncode = true;
    /* isEncode 是否進(jìn)行手動(dòng)編解碼的標(biāo)識(shí), 
      默認(rèn)值是true, 表示還沒(méi)有手動(dòng)編解碼 */
    private HttpServletRequest request;
    public MyHttpServletRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }
    @Override
    public String getParameter(String name) {
        return this.getParameterValues(name) == null? null : this.getParameterValues(name)[0];
    }
    
    @Override
    public String[] getParameterValues(String name) {
        return this.getParameterMap().get(name);
    }
    @Override
    public Map<String, String[]> getParameterMap() {
        /*
        該方法可以返回所有請(qǐng)求參數(shù)組成的map集合, 此時(shí)map中
        保存的數(shù)據(jù)是亂碼(get提交), 我們可以遍歷map中的每一個(gè)
        參數(shù)值, 手動(dòng)編解碼處理完后將正確的數(shù)據(jù)再次存回map中,
        最后返回一個(gè)沒(méi)有亂碼的map集合
         */
        if("POST".equalsIgnoreCase(request.getMethod())){//是POST提交
            return request.getParameterMap();
        }else if("GET".equalsIgnoreCase(request.getMethod())){
            //遍歷map, 挨個(gè)取出亂碼, 手動(dòng)編解碼再次存回map并返回map
            Map<String, String[]> map = request.getParameterMap();
            if(isEncode){
                for (Map.Entry<String, String[]> entry : map.entrySet()) {
                    //取出每一個(gè)鍵值對(duì), 由于值是數(shù)組, 還需要遍歷
                    String[] vs = entry.getValue();
                    for (int i = 0; i < vs.length; i++) {
                        try {
                            vs[i] = new String(vs[i].getBytes("iso8859-1"), "utf-8");
                        } catch (Exception e) {
                            e.printStackTrace();
                            throw new RuntimeException(e);
                        }
                    }
                }
                isEncode = false;
            }
            return map;
        }else{//其他5種提交方式
            return request.getParameterMap();
        }
    }
}
/*
 * 被裝飾者: request對(duì)象 --> 所屬的類: A
 * 被裝飾者所屬的類實(shí)現(xiàn)的接口: HttpServletRequest
 * 
 * 裝飾類: MyHttpServletRequest  要實(shí)現(xiàn)HttpServletRequest接口
 * 在這里讓MyHttpServletRequest繼承一個(gè)裝飾類, 我們這個(gè)類也是一個(gè)
 * 裝飾類, 只需要覆蓋需要改造的父類中方法即可!!
 */
/*
 * 1.寫一個(gè)裝飾類, 裝飾類要和被裝飾者所屬的類實(shí)現(xiàn)相同的接口
 *  或者繼承相同的父類
 * 2.裝飾類要提供構(gòu)造方法接受被裝飾者并保存在類的內(nèi)部
 * 3.對(duì)于想要改造的方法直接進(jìn)行改造, 對(duì)于不想改造的方法, 調(diào)用
 *  原有對(duì)象上的方法
 */

web.xml配置

<filter>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>com.znonline.jt.filter.EncodingFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Java設(shè)計(jì)模式:裝飾器模式

裝飾者模式(Decorator Pattern,有的也用 Wrapper Pattern)就是動(dòng)態(tài)地把職責(zé)附加到已有對(duì)象上去玉雾,實(shí)現(xiàn)功能擴(kuò)展翔试。這種特性,使得裝飾者模式提供了比繼承更具有彈性的解決方案复旬。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末垦缅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子驹碍,更是在濱河造成了極大的恐慌壁涎,老刑警劉巖凡恍,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異粹庞,居然都是意外死亡咳焚,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門庞溜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)革半,“玉大人,你說(shuō)我怎么就攤上這事流码∮止伲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵漫试,是天一觀的道長(zhǎng)六敬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)驾荣,這世上最難降的妖魔是什么外构? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮播掷,結(jié)果婚禮上审编,老公的妹妹穿的比我還像新娘。我一直安慰自己歧匈,他們只是感情好垒酬,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著件炉,像睡著了一般勘究。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斟冕,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天口糕,我揣著相機(jī)與錄音,去河邊找鬼宫静。 笑死走净,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的孤里。 我是一名探鬼主播伏伯,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼捌袜!你這毒婦竟也來(lái)了说搅?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤虏等,失蹤者是張志新(化名)和其女友劉穎弄唧,沒(méi)想到半個(gè)月后适肠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡候引,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年侯养,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澄干。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逛揩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出麸俘,到底是詐尸還是另有隱情辩稽,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布从媚,位于F島的核電站逞泄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拜效。R本人自食惡果不足惜喷众,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望紧憾。 院中可真熱鬧侮腹,春花似錦、人聲如沸稻励。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)望抽。三九已至,卻和暖如春履婉,著一層夾襖步出監(jiān)牢的瞬間煤篙,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工毁腿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辑奈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓已烤,卻偏偏與公主長(zhǎng)得像鸠窗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胯究,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容