SSM-Springboot筆記(7)- Servlet3.0和SpringBoot過濾器和攔截器

1 SpringBoot過濾器

  • 什么是過濾器
    filter簡(jiǎn)單理解:?--->檢票員(filter)---> 景點(diǎn)
  • SpringBoot2.X??的過濾器
ApplicationContextHeaderFilter
OrderedCharacterEncodingFilter
OrderedFormContentFilter
OrderedRequestContextFilter
  • 過濾器優(yōu)先級(jí)
    Ordered.HIGHEST_PRECEDENCE Ordered.LOWEST_PRECEDENCE
    低位值意味著更?的優(yōu)先級(jí) Higher values are interpreted as lower priority
    ?定義Filter赔嚎,避免和默認(rèn)的Filter優(yōu)先級(jí)?樣,不然會(huì)沖突
  • 注冊(cè)Filter配置兩種?式
bean FilterRegistrationBean
Servlet3.0 webFileter

2 使用Servlet3.0注解開發(fā)?定義的過濾器

  • 使?Servlet3.0的注解進(jìn)?配置步驟
    啟動(dòng)類??增加 @ServletComponentScan裙犹,進(jìn)?掃描
    新建?個(gè)Filter類尽狠,implements Filter衔憨,并實(shí)現(xiàn)對(duì)應(yīng)的接?
    @WebFilter 標(biāo)記?個(gè)類為filter,被spring進(jìn)?掃描
    urlPatterns:攔截規(guī)則袄膏,?持正則
    控制chain.doFilter的?法的調(diào)?践图,來(lái)實(shí)現(xiàn)是否通過放?
    不放?,web應(yīng)?resp.sendRedirect("/index.html") 或者 返回json字符串
  • 使用場(chǎng)景
    權(quán)限控制沉馆、?戶登錄狀態(tài)控制码党,也可以交給攔截器處理等
  • 示例:用戶登錄過濾器

2.1 新建controller同級(jí)包filter

2.2 創(chuàng)建登錄過濾器類LoginFilter

@WebFilter(urlPatterns = "/app/v1/pri/*", filterName = "loginFilter")
public class LoginFilter implements Filter {

    private static final ObjectMapper objectMapper = new ObjectMapper();  // 處理對(duì)象與json的轉(zhuǎn)換

    /**
     * 容器加載的時(shí)候
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        System.out.println("init LoginFilter======");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("doFilter LoginFilter======");

        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        String token = req.getHeader("token");
        if(StringUtils.isEmpty(token)){
            token = req.getParameter("token");
        }

        if(!StringUtils.isEmpty(token)){
            //判斷token是否合法
            User user = UserServiceImpl.sessionMap.get(token);
            if(user!=null){
                filterChain.doFilter(servletRequest,servletResponse);
            } else {
                // 有token,但token無(wú)效
                RetData retData =  RetData.RetError(-2,"登錄失敗斥黑,token無(wú)效");
                String jsonStr = objectMapper.writeValueAsString(retData);
                renderJson(resp,jsonStr);
            }
        }else {
            // 沒有登錄
            RetData retData =  RetData.RetError(-3,"未登錄");
            String jsonStr = objectMapper.writeValueAsString(retData);
            renderJson(resp,jsonStr);
        }
    }

    /**
     * 容器銷毀的時(shí)候
     */
    @Override
    public void destroy() {

        System.out.println("destroy LoginFilter======");

    }

    /**
     * @param response
     * @param json
     */
    private void renderJson(HttpServletResponse response,String json){

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");

        try(PrintWriter writer = response.getWriter()){
            writer.print(json);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

2.3 測(cè)試

沒有登錄訪問

{
    "code": -3,
    "data": null,
    "message": "未登錄"
}

錯(cuò)誤的token訪問

{
    "code": -2,
    "data": null,
    "message": "登錄失敗揖盘,token無(wú)效"
}

登錄之后使用正確的token訪問

{
    "code": 0,
    "data": "下單成功!",
    "message": "success"
}

3 使? Servlet3.0的注解?定義原?Servlet

編寫Servlet類繼承HttpServlet

/**
 * 使用servlet3.0開發(fā)原生接口
 */
@WebServlet(name = "userServlet", urlPatterns = "/api/v1/test/customs" )
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.write("this is my custom servlet api");
        writer.flush();
        writer.close();
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}

測(cè)試接口訪問:結(jié)果正確輸出

this is my custom servlet api

4 Servlet3.0的注解?定義原?Listener監(jiān)聽器

  • 應(yīng)用上下文監(jiān)聽器ServletContextListener
@WebListener
public class CustomContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("===========contextInitialized==============");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("===========contextDestroyed==============");
    }
}
  • 會(huì)話監(jiān)聽器HttpSessionLisener
@WebListener
public class CustomSessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("===========sessionCreated==============");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("===========sessionDestroyed==============");
    }
}
  • 請(qǐng)求監(jiān)聽器ServletRequestListener
@WebListener
public class CustomRequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("===========requestDestroyed==============");
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("===========requestInitialized==============");
    }
}

5 SpringBoot2.X攔截器配置

攔截器的作用和用法和過濾器?途基本類似
SpringBoot2.x使?步驟:

  • ?定義攔截器 HandlerInterceptor
    preHandle:調(diào)?Controller某個(gè)?法之前
    postHandle:Controller之后調(diào)?锌奴,視圖渲染之前兽狭,如果控制器Controller出現(xiàn)了異常,則不會(huì)執(zhí)?此?法
    afterCompletion:不管有沒有異常鹿蜀,這個(gè)afterCompletion都會(huì)被調(diào)?箕慧,?于資源清理
  • 配置攔截器 implements WebMvcConfigurer
    有多個(gè)攔截器的情況下,按照注冊(cè)順序進(jìn)?攔截茴恰,先注冊(cè)颠焦,先被攔截

5.1 示例演示:配置登錄攔截器

  • 創(chuàng)建controller同級(jí)包intercepter
  • 創(chuàng)建自定義攔截器類LoginIntercepter
public class LoginIntercepter implements HandlerInterceptor {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("========LoginIntercepter preHandle======");

        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token)){
            token = request.getParameter("token");
        }

        if(!StringUtils.isEmpty(token)){

            //判斷token是否合法
            User user = UserServiceImpl.sessionMap.get(token);
            if(user!=null){
                return true;
            } else {
                RetData retData =  RetData.RetError(-2,"登錄失敗,token無(wú)效");
                String jsonStr = objectMapper.writeValueAsString(retData);
                renderJson(response,jsonStr);
            }

        }else {
            RetData retData =  RetData.RetError(-3,"未登錄");
            String jsonStr = objectMapper.writeValueAsString(retData);
            renderJson(response,jsonStr);
        }

        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("=============postHandle=============");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("=============postHandle=============");
    }

    /**
     * 返回json數(shù)據(jù)
     * @param response
     * @param json
     */
    private void renderJson(HttpServletResponse response,String json){

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");

        try(PrintWriter writer = response.getWriter()){
            writer.print(json);
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}
  • 配置攔截器
/**
 * 攔截器配置類
 */
@Configuration
public class CustomMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        System.out.println("==========addInterceptors=============");
        registry.addInterceptor(getLoginInterceptor()).addPathPatterns("/app/v1/pri/**");
        WebMvcConfigurer.super.addInterceptors(registry);
    }

    /**
     * 通過bean的方式引入攔截器
     * @return
     */
    @Bean
    public LoginIntercepter getLoginInterceptor(){
        return new LoginIntercepter();
    }
}

5.2 攔截器不?效常?問題:

  • 是否有加@Configuration
  • 攔截路徑是否有問題 ** 和 *
  • 攔截器最后路徑?定要 /** 如果是?錄的話則是 /*/

5.3 攔截器和Filter過濾器的區(qū)別

  • Filter和Interceptor?者都是AOP編程思想的體現(xiàn)往枣,功能基本都可以實(shí)現(xiàn)
  • 攔截器功能更強(qiáng)?些伐庭,F(xiàn)ilter能做的事情它都能做
  • Filter在只在Servlet前后起作?,?Interceptor夠深?到?法前后分冈、異常拋出前后等
  • filter依賴于Servlet容器即web應(yīng)?中圾另,?Interceptor不依賴于Servlet容器所以可以運(yùn)?在
    多種環(huán)境。
  • 在接?調(diào)?的?命周期?丈秩,Interceptor可以被多次調(diào)?盯捌,?Filter只能在容器初始化時(shí)調(diào)??
    次淳衙。

5.4 Filter和Interceptor的執(zhí)?順序

  • 過濾前->攔截前->action執(zhí)?->攔截后->過濾后

5.5 如何配置不攔截某些路徑蘑秽?

registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/v1/pri/**")
//配置不攔截某些路徑,?如靜態(tài)資源
.excludePathPatterns("/**/*.html","/**/*.js");
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末箫攀,一起剝皮案震驚了整個(gè)濱河市肠牲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌靴跛,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梢睛,死亡現(xiàn)場(chǎng)離奇詭異肥印,居然都是意外死亡识椰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門深碱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)腹鹉,“玉大人,你說(shuō)我怎么就攤上這事敷硅」χ洌” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵绞蹦,是天一觀的道長(zhǎng)力奋。 經(jīng)常有香客問我,道長(zhǎng)幽七,這世上最難降的妖魔是什么景殷? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮澡屡,結(jié)果婚禮上滨彻,老公的妹妹穿的比我還像新娘。我一直安慰自己挪蹭,他們只是感情好亭饵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著梁厉,像睡著了一般辜羊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上词顾,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天八秃,我揣著相機(jī)與錄音,去河邊找鬼肉盹。 笑死昔驱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的上忍。 我是一名探鬼主播骤肛,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窍蓝!你這毒婦竟也來(lái)了腋颠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤吓笙,失蹤者是張志新(化名)和其女友劉穎淑玫,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡絮蒿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年尊搬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片土涝。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡戈毒,死狀恐怖郭膛,靈堂內(nèi)的尸體忽然破棺而出盹廷,到底是詐尸還是另有隱情跋炕,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布茵肃,位于F島的核電站腔长,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏验残。R本人自食惡果不足惜捞附,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望您没。 院中可真熱鬧鸟召,春花似錦、人聲如沸氨鹏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)仆抵。三九已至跟继,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間镣丑,已是汗流浹背舔糖。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留莺匠,地道東北人金吗。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像趣竣,于是被迫代替她去往敵國(guó)和親摇庙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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