1. 程式人生 > >Spring MVC攔截器配置以及統一登陸校驗實現

Spring MVC攔截器配置以及統一登陸校驗實現

攔截器概念

這裡引用百度百科裡面的說法,java裡的攔截器是動態攔截Action呼叫的物件。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的程式碼,也可以在一個action執行前阻止其執行,同時也提供了一種可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中攔截器用於在某個方法或欄位被訪問之前,進行攔截然後在之前或之後加入某些操作

用途

  1. 日誌記錄:記錄請求的一些資訊和請求引數
  2. 許可權校驗:如登陸校驗,管理員許可權校驗
  3. 效能監控:監控請求處理的時間
  4. 通用行為:如讀取cookie資訊等

配置Spring MVC攔截器

配置 dispatch-servlet.xml


<mvc:interceptors>
        <!-- 如果在interceptors中配置bean,那麼所有定義在這裡的bean都會被攔截-->
        <!--<bean></bean>-->
        <mvc:interceptor>
            <mvc:mapping path="/manage/**"/>
            <!--過濾登陸死迴圈情況-->
            <!--<mvc:exclude-mapping path="/manage/login.do"/>-->
<bean class="com.test.controller.common.interceptor.AuthorityInterceptor"/> </mvc:interceptor> </mvc:interceptors>
分析配置中的節點
  • interceptors節點:這個節點是SpringMVC的攔截器集配置節點,在這個節點裡面我們可以宣告多個interceptor
  • interceptor節點:這個節點是配置攔截路徑以及你攔截器實現類的節點
    • mapping節點:符合mapping路徑匹配的請求都會經過攔截器
    • exclude-mapping節點:符合exclude-mapping路徑匹配的請求都不會經過攔截器
    • bean節點:配置我們自己的實現類,實現類要實現HandlerInterceptor介面
path情況分析
  1. 如果要攔截同一個controller下的所有的請求,如/manage/***.do,path應該為 /manage/*
  2. 如果要攔截請求路徑為manage包下不同controller的所有請求,如 /manage/product/b.do/manage/order/list.do,path應該為/manage/**
  3. 如果想要某個請求不走攔截器,那麼可以配置exclude-mappingpath應該為具體的url,準確到方法,如/manage/login.do
spring MVC攔截器請求流程
spring請求流程具體如下:
  1. 瀏覽器/客戶端傳送請求給我們的伺服器
  2. 請求來到Spring的dispatchServlet進行請求分發
  3. dispatchServlet檢查我們在dispatch-servlet.xml定義好的規則,按照規則判斷請求是否走攔截器
  4. 如果判斷請求不走攔截器,請求直接分發到對應的controller(這裡預設有對應的controller)
  5. 如果判斷請求是走攔截器的,就走我們自己實現的攔截器,驗證請求,通過就放行,走到controller,反之則提前返回給客戶端
spring請求流程圖

這裡寫圖片描述

實現攔截器示例(java)

這是自己實現的一個統一登陸校驗攔截器,具體程式碼如下,寫程式碼之前一定要根據自己的實際情況,把dispatch-servlet.xml中的攔截器路徑配置好,不然攔截器無法正常工作

@Slf4j
public class AuthorityInterceptor implements HandlerInterceptor{
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info(("preCompletion"));
        //請求中controller的方法名
        HandlerMethod handlerMethod = (HandlerMethod)handler;
        //解析handlermethod

        //獲取方法名
        String methodName = handlerMethod.getMethod().getName();
        //獲取類名,simplename是獲取名字不帶包名,name是帶包名的
        String className = handlerMethod.getBean().getClass().getSimpleName();
        //解析引數
        StringBuffer stringBuffer = new StringBuffer();
        Map paramMap = request.getParameterMap();
        Iterator it = paramMap.entrySet().iterator();
        while ((it.hasNext())){

            Map.Entry entry = (Map.Entry) it.next();
            String mapKey = (String) entry.getKey();
            String mapValue = "";

            //request的這個引數map的value返回的是一個String[]
            Object obj = entry.getValue();
            if (obj instanceof String[]){
                String[] strs = (String[])obj;
                mapValue = Arrays.toString(strs);
            }
            stringBuffer.append(mapKey).append("=").append(mapValue);
        }

        //判斷登陸,如果是登陸就放行
        if(StringUtils.equals(className, UserManageController.class.getSimpleName())&&StringUtils.equals(methodName,"login")){
            //登陸的時候不能把引數的日誌也打上,如果日誌洩露,賬號密碼就會洩露
            log.info("許可權攔截器攔截到的請求 className{} methodName{}",className,methodName);
            return true;
        }
        //判斷登陸
        User user = session.getAttribute(Const.CURRENT_USER);
        if(user == null )){
            //未登入,返回false,不會呼叫controller裡面的方法
            //response必須重置重置,否則會寶getWritter() has already been called for this response
            //這裡我們手動接管了SpringMVC原生的返回,而是託管到攔截器中返回
            response.reset();
            //這是返回編碼,否者會亂碼
            response.setCharacterEncoding("UTF-8");
            //設定返回值型別
            response.setContentType("application/json;chartset=UTF-8");
            PrintWriter out = response.getWriter();
            out.print("你想返回的錯誤資訊")
            }
            out.flush();
            out.close();
            return false;
        }
        return  true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info(("postCompletion"));
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info(("afterCompletion"));
    }
}