1. 程式人生 > >spring boot + dubbo小實戰(七):實現登陸攔截器

spring boot + dubbo小實戰(七):實現登陸攔截器

在上一章已經完成了登陸服務,那麼在本章中主要是實現登陸攔截。

如何實現登陸攔截器?

在登陸方法中,將使用者資訊儲存在session中,所以在攔截器中把session中的user資訊拿出來,判斷是否為空即可判斷是否登陸。

如何編寫攔截器

編寫攔截器,可實現HandlerInterceptor介面,重寫HandlerInterceptor介面中的preHandle(),postHandle()和afterCompletion()三個方法。

preHandle():在執行controller之前執行,返回true代表可以執行controller,返回false代表不執行controller。一般用在登陸驗證、記錄日誌等等操作。

postHandle():在執行controller之後執行,但在渲染試圖之前執行。在這個可以對ModelAndView進行處理,比如每次執行完都需要返回固定的引數到request中,就可在本方法中編寫。

afterCompletion():在返回ModelAndView後執行,也就是dispatcherServlet 渲染了對應的檢視之後執行。比如效能監控,即可以輸出本次請求的耗時和結束時間

程式碼實現

首先編寫一個LoginInterceptor類實現HandlerInterceptor方法,具體程式碼如下

@Component
public class LoginInterceptor implements HandlerInterceptor {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());


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

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

}

登陸攔截的具體實現邏輯,在preHandle中寫。具體邏輯程式碼如下,同時實現了日記記錄本次請求。

 @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //記錄請求資訊
    StringBuffer buf = new StringBuffer();
    String parameter = request.getParameterMap() == null ? "" : JSON.toJSONString(request.getParameterMap());
    buf.append("|").append("X-Real-IP=").append(request.getHeader("X-Real-IP"));
    buf.append("|").append("RequestURI=").append(request.getRequestURI());
    buf.append("|").append("RequestURL=").append(request.getRequestURL());
    buf.append("|").append("parameter=").append(parameter);
    buf.append("|").append("SessionId=").append(request.getSession().getId());
    logger.info(buf.toString());
    //是否登陸
    Employee user = (Employee) request.getSession().getAttribute("sessionUser");

    if (user == null) {
        //沒登陸,轉發到/unauthorized錯誤頁面
        response.sendRedirect("/unauthorized");
        return false;
    }
        
    return true;
}

這樣就完成了登陸攔截的邏輯,是不是很簡單?

之後我需要記錄請求到渲染完頁面的時間,這個時候需要在preHandle中新增一下程式碼,START_TIME是定義在該類的一個常量

//記錄請求開始時間
request.setAttribute(START_TIME, System.currentTimeMillis());

在afterCompletion()中的邏輯程式碼如下

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    //獲取開始時間
    long start = (long) request.getAttribute(START_TIME);
    //獲得結束時間
    long end = System.currentTimeMillis();
    StringBuffer buf = new StringBuffer();
    //構造日誌
    buf.append("|").append("SessionId=").append(request.getSession().getId());
    buf.append("|").append("RequestURI=").append(request.getRequestURI());
    buf.append("|").append("serviceTime=").append(end - start).append("ms");
    logger.info(buf.toString());
}

攔截器的程式碼寫完後,需要在config中註冊才能實現攔截。所以,需要寫一個簡單的config類,繼承WebMvcConfigurationSupport類,重寫addInterceptors()和addResourceHandlers()即可

具體程式碼如下

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        //配置攔截器,對所有url進行攔截,排除"/static/**", "/login", "/logout", "/"這幾個url的攔截
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**", "/login", "/logout", "/unauthorized", "/", "/thy/**");
        super.addInterceptors(registry);
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        //靜態資源路徑配置
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        super.addResourceHandlers(registry);
    }
}

addInterceptor是新增的攔截器類,addPathPatterns()是需要攔截的地址,/**是攔截所有地址,excludePathPatterns()是忽略攔截的地址。

addResourceHandlers()方法是配置一些靜態資源的方法,方法裡的邏輯是標識/static下的所有地址放行

啟動測試

啟動dubbo-user-web專案,進行測試。

未登入之前請求/index,會報401頁面

當你正確登陸後,進入首頁,控制檯中的資訊輸出如下

21:56:23 [http-nio-8180-exec-4] INFO  c.j.d.u.c.i.LoginInterceptor - |X-Real-IP=null|RequestURI=/index|RequestURL=http://127.0.0.1:8180/index|parameter={}|SessionId=239FBB265E0B721A92483E3AA2C112EE|RemoteAddr=127.0.0.1|RemoteHost=127.0.0.1|RemotePort=53728
21:56:23 [http-nio-8180-exec-4] INFO  c.j.d.u.c.i.LoginInterceptor - |SessionId=239FBB265E0B721A92483E3AA2C112EE|RequestURI=/index|serviceTime=147ms
21:56:23 [http-nio-8180-exec-8] INFO  c.j.d.u.c.i.LoginInterceptor - |X-Real-IP=null|RequestURI=/main|RequestURL=http://127.0.0.1:8180/main|parameter={}|SessionId=239FBB265E0B721A92483E3AA2C112EE|RemoteAddr=127.0.0.1|RemoteHost=127.0.0.1|RemotePort=53728
21:56:23 [http-nio-8180-exec-8] INFO  c.j.d.u.c.i.LoginInterceptor - |SessionId=239FBB265E0B721A92483E3AA2C112EE|RequestURI=/main|serviceTime=13ms

第二記錄準確的輸出了登陸成功後進入/index頁面並渲染頁面的請求相應的時間是147毫秒。(為什麼/login的登陸介面沒有輸出日誌呢?因為在WebMvcConfig中,忽略了/login路徑,所以請求的時候不經過攔截器)

到此,這樣就實現了一個簡單的登陸攔截器。。。