再玩springmvc的攔截器

spingmvc的執行步驟

用戶發送請求到dispatcherservlet,

前端控制器到handermaping去找對應的handler,

然後返回一個執行鏈,是handler和響應的攔截器,

執行鏈經過適配器,做一些處理,

到達對應的handler,

經過handler來處理後,返回modelandview,

前端控制器會先對視圖對象進行解析,解析完成後,

前端控制器會對視圖進行渲染,

渲染完成之後,將視圖返回給用戶。


首先,我們發現以上步驟中包含了handlermaping,handlerAdpdater(適配器),和handler,那麼springmvc執行的時候,這些都應該作爲對象存在的,這就是我們springmvc配置的由來

1.我們配置掃描包,將controller全都交給spring管理

2.然後我們開啓註解的自動,來註冊handlermaping和handlerAdpdater

3.因爲我們要解析視圖,所以要有視圖解析器的配置。

4.我們看到經過handlerMaping後,返回的是一個handler和攔截器的執行鏈,那麼重點來了,我們的攔截器開始配置了。

步驟是:我們首先用一個類實現HandlerAdpter,實現裏面的方法,有前置攔截(在handler之前),後置攔截,最終攔截(視圖渲染完成之後)

public class LoginInterceptor implements HandlerInterceptor {
    
    @Autowired
    private UserServiceImpl userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //在Handler執行之前處理
        //判斷用戶是否登錄
        //從cookie中取token
        String token = CookieUtils.getCookieValue(request, "TT_TOKEN");
        
        /*if(StringUtils.isBlank(token)){
            //跳轉到登錄頁面,把用戶請求的url作爲參數傳遞給登錄頁面。
            response.sendRedirect(userService.SSO_BASE_URL + userService.SSO_PAGE_LOGIN
                    + "?redirect=" + request.getRequestURL());
            //返回false
            return false;
        }*/
        
        //根據token換取用戶信息,調用sso系統的接口。
        TbUser user = userService.getUserByToken(token);
        //取不到用戶信息
        if (null == user) {
            //跳轉到登錄頁面,把用戶請求的url作爲參數傳遞給登錄頁面。
            response.sendRedirect(userService.SSO_BASE_URL + userService.SSO_PAGE_LOGIN
                    + "?redirect=" + request.getRequestURL());
            //返回false
            return false;
        }
        //取到用戶信息,放行
        //把用戶信息放入request
        request.setAttribute("user", user); 
        //返回值決定handler是否執行。true:執行,false:不執行。
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // handler執行之後,返回ModelAndView之前

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        // 返回ModelAndView之後。
        //響應用戶之後。

    }

}



以上是springmvc的攔截器,那麼springboot中的攔截器又是怎麼實現的呢?

springboot中使用攔截器,

  • 自定義一個攔截器,
  • 一個類通過實現WebMvcConfigurer並添加@Configuration,
  • 在這個類中重寫   addInterceptors方法,這裏還有一點巧妙的是通過@Bean的方式,將日誌引入
    @Bean
    public LoginInterceptor loginInterceptor(){
        return new LoginInterceptor();
    }
    
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**");
    }

這個方式來添加攔截器,那麼我們真實開發是怎麼用的呢?

首先跟mvc一樣,用一個類繼承handlerintercapter

public class LoginInterceptor extends HandlerInterceptorAdapter {

    private JwtProperties jwtProperties;

    // 定義一個線程域,存放登錄用戶
    private static final ThreadLocal<UserInfo> tl = new ThreadLocal<>();

    public LoginInterceptor(JwtProperties jwtProperties) {
        this.jwtProperties = jwtProperties;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 查詢token
        String token = CookieUtils.getCookieValue(request, "LY_TOKEN");
        if (StringUtils.isBlank(token)) {
            // 未登錄,返回401
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        // token,查詢用戶信息
        try {
            // 解析成功,證明已經登錄
            UserInfo user = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey());
            // 放入線程域
            tl.set(user);
            return true;
        } catch (Exception e) {
            // 拋出異常,證明未登錄或超時,返回401
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }

    }

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

    public static UserInfo getLoginUser() {
        return tl.get();
    }
}
然後用mvcconfig實現webmvcconfigurer

@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class MvcConfig implements WebMvcConfigurer {

    @Autowired
    private JwtProperties jwtProperties;

    @Bean
    public LoginInterceptor loginInterceptor() {
        return new LoginInterceptor(jwtProperties);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor())
                .addPathPatterns("/**");
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章