亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Spring Boot實(shí)踐——三種攔截器的創(chuàng)建

fnngj / 561人閱讀

摘要:中的攔截器在開(kāi)發(fā)中,攔截器是經(jīng)常用到的功能。該攔截器只能過(guò)濾請(qǐng)求,允許多個(gè)攔截器同時(shí)存在,通過(guò)攔截器鏈管理。當(dāng)時(shí)不再執(zhí)行后續(xù)的攔截器鏈及被攔截的請(qǐng)求。實(shí)現(xiàn)攔截器大致也分為兩種,一種是實(shí)現(xiàn)接口,另一種利用的注解或配置。

Spring中的攔截器

  在web開(kāi)發(fā)中,攔截器是經(jīng)常用到的功能。它可以幫我們驗(yàn)證是否登陸、權(quán)限認(rèn)證、數(shù)據(jù)校驗(yàn)、預(yù)先設(shè)置數(shù)據(jù)以及統(tǒng)計(jì)方法的執(zhí)行效率等等。今天就來(lái)詳細(xì)的談一下spring中的攔截器。spring中攔截器主要分種,一個(gè)是HandlerInterceptor,一個(gè)是MethodInterceptor。

一、HandlerInterceptor攔截器

  HandlerInterceptor是springMVC項(xiàng)目中的攔截器,它攔截的目標(biāo)是請(qǐng)求的地址,比MethodInterceptor先執(zhí)行。實(shí)現(xiàn)一個(gè)HandlerInterceptor攔截器可以直接實(shí)現(xiàn)HandlerInterceptor接口,也可以繼承HandlerInterceptorAdapter類。這兩種方法殊途同歸,其實(shí)HandlerInterceptorAdapter也就是聲明了HandlerInterceptor接口中所有方法的默認(rèn)實(shí)現(xiàn),而我們?cè)诶^承他之后只需要重寫(xiě)必要的方法。下面就是HandlerInterceptorAdapter的代碼,可以看到一個(gè)方法只是默認(rèn)返回true,另外兩個(gè)是空方法:

/** * 自定義攔截器-基于springmvc
 * @ClassName: CustomInterceptor 
 * @Description: springMVC項(xiàng)目中的攔截器,它攔截的目標(biāo)是請(qǐng)求的地址,比MethodInterceptor先執(zhí)行。
 *                 該攔截器只能過(guò)濾action請(qǐng)求,SPring允許多個(gè)攔截器同時(shí)存在,通過(guò)攔截器鏈管理。
 *                 當(dāng)preHandle return true時(shí),執(zhí)行下一個(gè)攔截器,直到所有攔截器執(zhí)行完,再運(yùn)行被攔截的請(qǐng)求。
 *                 當(dāng)preHandle return false時(shí), 不再執(zhí)行后續(xù)的攔截器鏈及被攔截的請(qǐng)求。
 * @author OnlyMate
 * @Date 2018年8月28日 下午2:30:22  
 * */
public class CustomInterceptor implements HandlerInterceptor  {

    @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // TODO Auto-generated method stub
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }

}

這三個(gè)方法都是干什么的,有什么作用,什么時(shí)候調(diào)用,不同的攔截器之間是怎樣的調(diào)用順序呢?這還得參考一下DispatcherServlet的doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                applyDefaultViewName(processedRequest, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                // As of 4.3, we"re processing Errors thrown from handler methods as well,
                // making them available for @ExceptionHandler methods and other scenarios.
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

  代碼有點(diǎn)長(zhǎng),但是它封裝了springMVC處理請(qǐng)求的整個(gè)過(guò)程。首先根據(jù)請(qǐng)求找到對(duì)應(yīng)的HandlerExecutionChain,它包含了處理請(qǐng)求的handler和所有的HandlerInterceptor攔截器;然后在調(diào)用hander之前分別調(diào)用每個(gè)HandlerInterceptor攔截器的preHandle方法,若有一個(gè)攔截器返回false,則會(huì)調(diào)用triggerAfterCompletion方法,并且立即返回不再往下執(zhí)行;若所有的攔截器全部返回true并且沒(méi)有出現(xiàn)異常,則調(diào)用handler返回ModelAndView對(duì)象;再然后分別調(diào)用每個(gè)攔截器的postHandle方法;最后,即使是之前的步驟拋出了異常,也會(huì)執(zhí)行triggerAfterCompletion方法。關(guān)于攔截器的處理到此為止,接下來(lái)看看triggerAfterCompletion做了什么

private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
            @Nullable HandlerExecutionChain mappedHandler, Exception ex) throws Exception {

        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, ex);
        }
        throw ex;
    }

  根據(jù)以上的代碼,分析一下不同攔截器及其方法的執(zhí)行順序。假設(shè)有5個(gè)攔截器編號(hào)分別為12345,若一切正常則方法的執(zhí)行順序是12345的preHandle,54321的postHandle,54321的afterCompletion。若編號(hào)3的攔截器的preHandle方法返回false或者拋出了異常,接下來(lái)會(huì)執(zhí)行的是21的afterCompletion方法。這里要注意的地方是,我們?cè)趯?xiě)一個(gè)攔截器的時(shí)候要謹(jǐn)慎的處理preHandle中的異常,因?yàn)檫@里一旦有異常拋出就不會(huì)再受到這個(gè)攔截器的控制。12345的preHandle的方法執(zhí)行過(guò)之后,若handler出現(xiàn)了異?;蛘吣硞€(gè)攔截器的postHandle方法出現(xiàn)了異常,則接下來(lái)都會(huì)執(zhí)行54321的afterCompletion方法,因?yàn)橹灰?2345的preHandle方法執(zhí)行完,當(dāng)前攔截器的攔截器就會(huì)記錄成編號(hào)5的攔截器,而afterCompletion總是從當(dāng)前的攔截器逆向的向前執(zhí)行。
  另外,實(shí)現(xiàn)HandlerInterceptor攔截器還有一個(gè)方法,就是實(shí)現(xiàn)WebRequestInterceptor接口。其實(shí)它和剛才的兩種方法也是殊途同歸,最終還是被spring適配成HandlerInterceptor。有一點(diǎn)不同,它的preHandle方法最終只會(huì)返回true。

這里可以根據(jù)自己的需求在對(duì)應(yīng)方法中寫(xiě)自己業(yè)務(wù)處理邏輯

/**
 * 自定義攔截器-基于springmvc
 * @ClassName: CustomInterceptor 
 * @Description: springMVC項(xiàng)目中的攔截器,它攔截的目標(biāo)是請(qǐng)求的地址,比MethodInterceptor先執(zhí)行。
 *                 該攔截器只能過(guò)濾action請(qǐng)求,SPring允許多個(gè)攔截器同時(shí)存在,通過(guò)攔截器鏈管理。
 *                 當(dāng)preHandle return true時(shí),執(zhí)行下一個(gè)攔截器,直到所有攔截器執(zhí)行完,再運(yùn)行被攔截的請(qǐng)求。
 *                 當(dāng)preHandle return false時(shí), 不再執(zhí)行后續(xù)的攔截器鏈及被攔截的請(qǐng)求。
 * @author OnlyMate
 * @Date 2018年8月28日 下午2:30:22  
 *
 */
public class CustomInterceptor implements HandlerInterceptor  {
    private Logger logger = LoggerFactory.getLogger(CustomInterceptor.class);
    
    /**
     * 在請(qǐng)求處理之前執(zhí)行,主要用于權(quán)限驗(yàn)證、參數(shù)過(guò)濾等
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        logger.info("CustomInterceptor ==> preHandle method: do request before");
        return true;
    }

    /**
     * 當(dāng)前請(qǐng)求進(jìn)行處理之后執(zhí)行,主要用于日志記錄、權(quán)限檢查、性能監(jiān)控、通用行為等
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        logger.info("CustomInterceptor ==> postHandle method: do request after");
    }

    /**
     * 當(dāng)前對(duì)應(yīng)的interceptor的perHandle方法的返回值為true時(shí),postHandle執(zhí)行完成并渲染頁(yè)面后執(zhí)行,主要用于資源清理工作
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        logger.info("CustomInterceptor ==> afterCompletion method: do request finshed");
    }
}

配置如下:

/**
 * Web MVC 配置適配器
 * @ClassName: WebAppConfigurer 
 * @Description: 
 * @author OnlyMate
 * @Date 2018年8月28日 下午2:39:31  
 * 
 * WebAppConfigurer extends WebMvcConfigurerAdapter 在Spring Boot2.0版本已過(guò)時(shí)了,用官網(wǎng)說(shuō)的新的類替換
 *
 */
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
    /**
     * 注入自定義攔截器
     * @Title: addInterceptors 
     * @Description: 先add的攔截器會(huì)越靠外,即越靠近瀏覽器
     * @Date 2018年8月28日 下午2:47:28 
     * @author OnlyMate
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        WebMvcConfigurer.super.addInterceptors(registry);
        registry.addInterceptor(new CustomInterceptor()).addPathPatterns("/**");//攔截所有請(qǐng)求
    }

}
二、MethodInterceptor攔截器

  MethodInterceptor是AOP項(xiàng)目中的攔截器,它攔截的目標(biāo)是方法,即使不是controller中的方法。實(shí)現(xiàn)MethodInterceptor攔截器大致也分為兩種,一種是實(shí)現(xiàn)MethodInterceptor接口,另一種利用AspectJ的注解或配置。

1、實(shí)現(xiàn)MethodInterceptor接口
/**
 * 自定義攔截器-方法攔截器,基于spring aop
 * @ClassName: CustomMethodInterceptor 
 * @Description: AOP項(xiàng)目中的攔截器,它攔截的目標(biāo)是方法
 *                 配置在applicationContext.xml中
 * @author OnlyMate
 * @Date 2018年8月29日 下午3:35:24  
 *
 */
public class CustomMethodInterceptor implements MethodInterceptor {
    private Logger logger = LoggerFactory.getLogger(CustomMethodInterceptor.class);
    
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        logger.info("CustomMethodInterceptor ==> invoke method: process method name is {}", invocation.getMethod().getName());
        
        //TODO 處理操作
        
        return invocation.proceed();
    }

}

配置說(shuō)明


    
    
        
        
        
        
        
    

CustomAnnotation自定義注解

/**
 * 自定義注解對(duì)象
 * @ClassName: TableSplit 
 * @Description: TODO
 * @author OnlyMate
 * @Date 2018年5月22日 上午11:43:57  
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    /** 需攔截方法名描述 */
    String name() default "";
    
    /** 加密 */
    String[] encrypt() default {};

    /** 解密 */
    String[] decrypt() default {};

}
2、利用AspectJ的注解或配置  a、基于AspectJ注解
/**
 * 自定義攔截器-方法攔截器,基于注解的AspectJ方式
 * @ClassName: CustomAutoAspectJInterceptor 
 * @Description: 配置在applicationContext.xml中
 * @author OnlyMate
 * @Date 2018年8月29日 下午4:03:49  
 *
 */
@Component
@Aspect
public class CustomAutoAspectJInterceptor {
    private Logger logger = LoggerFactory.getLogger(CustomAutoAspectJInterceptor.class);
    
    @Around("execution (* com.onlymate.springboot.controller.*.*(..))")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        logger.info("CustomAutoAspectJInterceptor ==> invoke method: process method class is {}", point.getTarget().getClass());
        
        //TODO 處理操作
        
        return point.proceed();
    }
}
b、基于AspectJ配置
/**
 * 自定義攔截器-方法攔截器,基于AspectJ方式
 * @ClassName: CustomAspectJInterceptor 
 * @Description: 配置在applicationContext.xml中
 * @author OnlyMate
 * @Date 2018年8月29日 下午4:03:49  
 *
 */
public class CustomAspectJInterceptor {
    private Logger logger = LoggerFactory.getLogger(CustomAspectJInterceptor.class);
    
    public Object around(ProceedingJoinPoint point) throws Throwable{
        logger.info("CustomAspectJInterceptor ==> invoke method: process method class is {}", point.getTarget().getClass());
        
        //TODO 處理操作
        
        return point.proceed();
    }
}
c、配置說(shuō)明

    
        
        
            
        
        
    

    
    
    
三、效果圖

四、談一談區(qū)別

  上面的兩種攔截器都能起到攔截的效果,但是他們攔截的目標(biāo)不一樣,實(shí)現(xiàn)的機(jī)制不同,所以有的時(shí)候適用不同的場(chǎng)景。HandlerInterceptoer攔截的是請(qǐng)求地址,所以針對(duì)請(qǐng)求地址做一些驗(yàn)證、預(yù)處理等操作比較合適。當(dāng)你需要統(tǒng)計(jì)請(qǐng)求的響應(yīng)時(shí)間時(shí)MethodInterceptor將不太容易做到,因?yàn)樗赡芸缭胶芏喾椒ɑ蛘咧簧婕暗揭呀?jīng)定義好的方法中一部分代碼。MethodInterceptor利用的是AOP的實(shí)現(xiàn)機(jī)制,在本文中只說(shuō)明了使用方式,關(guān)于原理和機(jī)制方面介紹的比較少,因?yàn)橐f(shuō)清楚這些需要講出AOP的相當(dāng)一部分內(nèi)容。在對(duì)一些普通的方法上的攔截HandlerInterceptoer就無(wú)能為力了,這時(shí)候只能利用AOP的MethodInterceptor。利用MethodInterceptor就可以很容易的實(shí)現(xiàn)一個(gè)日志攔截處理。

   另外,還有一個(gè)跟攔截器類似的東西----Filter。Filter是Servlet規(guī)范規(guī)定的,不屬于spring框架,也是用于請(qǐng)求的攔截。但是它適合更粗粒度的攔截,在請(qǐng)求前后做一些編解碼處理、日志記錄等。而攔截器則可以提供更細(xì)粒度的,更加靈活的,針對(duì)某些請(qǐng)求、某些方法的組合的解決方案。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/76210.html

相關(guān)文章

  • springboot整合shiro使用shiro-spring-boot-web-starter

    摘要:此文章僅僅說(shuō)明在整合時(shí)的一些坑并不是教程增加依賴集成依賴配置三個(gè)必須的用于授權(quán)和登錄創(chuàng)建自己的實(shí)例用于實(shí)現(xiàn)權(quán)限三種方式實(shí)現(xiàn)定義權(quán)限路徑第一種使用角色名定義第二種使用權(quán)限定義第三種使用接口的自定義配置此處配置之后需要在對(duì)應(yīng)的 此文章僅僅說(shuō)明在springboot整合shiro時(shí)的一些坑,并不是教程 增加依賴 org.apache.shiro shiro-spring-...

    sevi_stuo 評(píng)論0 收藏0
  • Spring Boot - 整合JdbcTemplate、MyBatis

    摘要:更簡(jiǎn)答的說(shuō)就是要么全部執(zhí)行成功,要么撤銷(xiāo)不執(zhí)行。因此,數(shù)據(jù)庫(kù)操作的事務(wù)習(xí)慣上就稱為事務(wù)。實(shí)現(xiàn)原理單機(jī)事務(wù)事務(wù)是用對(duì)象控制的。接口提供了兩種事務(wù)模式自動(dòng)提交和手工提交。事務(wù)多機(jī)事務(wù),通過(guò)實(shí)現(xiàn),需要驅(qū)動(dòng)支持。局限于應(yīng)用使用。 Spring Boot - 數(shù)據(jù)庫(kù)配置 回顧 Spring Boot - 初識(shí) Hello World Spring Boot - Servlet、過(guò)濾器、監(jiān)聽(tīng)器、...

    Keagan 評(píng)論0 收藏0
  • 貓頭鷹深夜翻譯:使用SpringBoot和AspectJ實(shí)現(xiàn)AOP

    摘要:我們會(huì)寫(xiě)切面來(lái)攔截對(duì)這些業(yè)務(wù)類和類的調(diào)用。切面定義何時(shí)攔截一個(gè)方法以及做什么和在一起成為切面連接點(diǎn)當(dāng)代碼開(kāi)始執(zhí)行,并且切點(diǎn)的條件滿足時(shí),通知被調(diào)用。 前言 這篇文章會(huì)幫助你使用Spring Boot Starter AOP實(shí)現(xiàn)AOP。我們會(huì)使用AspectJ實(shí)現(xiàn)四個(gè)不同的通知(advice),并且新建一個(gè)自定義的注解來(lái)追蹤方法的執(zhí)行時(shí)間。 你將會(huì)了解 什么是交叉分割關(guān)注點(diǎn)(cross...

    meislzhua 評(píng)論0 收藏0
  • Spring Boot 進(jìn)階

    摘要:我們可不可以提供一個(gè)公共的入口進(jìn)行統(tǒng)一的異常處理呢當(dāng)然可以。一般我們可以在地址上帶上版本號(hào),也可以在參數(shù)上帶上版本號(hào),還可以再里帶上版本號(hào),這里我們?cè)诘刂飞蠋习姹咎?hào),大致的地址如,其中,即代表的是版本號(hào)。 上一篇帶領(lǐng)大家初步了解了如何使用 Spring Boot 搭建框架,通過(guò) Spring Boot 和傳統(tǒng)的 SpringMVC 架構(gòu)的對(duì)比,我們清晰地發(fā)現(xiàn) Spring Boot ...

    galaxy_robot 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

fnngj

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<