淺談Springboot實現攔截器的兩種方式

實現過濾請求有兩種方式:

一種就是用攔截器,一種就是過濾器

攔截器相對來說比較專業,而過濾器雖然不專業但是也能完成基本的攔截請求要求。

一、攔截器方式

1、配置HandlerInterceptor

下面這個也是我們公司項目攔截器的寫法,總體來說感覺還不錯,我就記錄瞭下來。
利用瞭一個靜態Pattern變量存儲不走攔截器的路徑,然後在preHandle方法當中進行過濾,讓他返回true。

@Component
public class LoginInterceptor implements HandlerInterceptor{
	
	private static final Pattern SHOULD_NOT_FILTER_URL_PATTERN;
	
	static {
		List<String> urlList = new ArrayList<>();
		// 將不走攔截器的請求存放到Pattern
		urlList.add("(socket/.*)");
		urlList.add("(user/findUserList)");
		StringBuilder sb = new StringBuilder();
		for (String url : urlList) {
			sb.append(url);
			sb.append("|");
		}
		sb.setLength(sb.length() - 1);
		SHOULD_NOT_FILTER_URL_PATTERN = Pattern.compile(sb.toString());
	}
	
	/**
	 * 在請求處理之前進行調用(Controller方法調用之前)
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		HttpSession session = request.getSession();
		// 獲取訪問的url
 		String servletPath = request.getServletPath();
		// 排除特定請求
		if (SHOULD_NOT_FILTER_URL_PATTERN.matcher(servletPath).find()) {
			return true;
		}
		if (session.getAttribute("user") != null) {
			// 可能有的項目在校驗完session,還會校驗token
			String token = request.getHeader("access_token");
			// 此處業務省略。。。
			return true;
		}
		return false;
	}

	/**
	 * 請求處理之後進行調用,但是在視圖被渲染之前(Controller方法調用之後)
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		
	}

	/**
	 * 在整個請求結束之後被調用,也就是在DispatcherServlet 渲染瞭對應的視圖之後執行(主要是用於進行資源清理工作)
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		
	}
}

2、註冊攔截器

配置完上面的攔截器還需要註冊攔截器。

WebMvcConfigurerAdapter類是 Spring內部的一種配置方式
采用JavaBean的形式來代替傳統的xml配置文件形式進行針對框架個性化定制

@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
	
	@Autowired
    private LoginInterceptor loginInterceptor;
	

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 多個攔截器組成一個攔截器鏈
		// addPathPatterns 用於添加攔截規則
		// excludePathPatterns 用戶排除攔截
		registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
		super.addInterceptors(registry);
	}
}

3、使用攔截器的坑

繼承WebMvcConfigurerAdapter 重寫addInterceptors方法的時候,一定要使用註入方式,將loginInterceptor註入到變量當中,要麼就使用@Bean註解的方式,將loginInterceptor(攔截器)註入到容器。

之所以這麼搞是因為攔截器在 Bean 初始化之前進行,所以在攔截器中無法像這樣註入 Bean。
就算加瞭@Component,他是存放於容器當中瞭,但是他存放容器當中的對象屬性,是空屬性。

在WebMvcConfigurerAdapter 使用@Autowired註入瞭一遍攔截器,屬性就有值瞭。

說白瞭不管采用哪種方案,目的隻有一個,讓對象的屬性有值,因為攔截器比其他對象初始化早,導致屬性為空,想讓他有值,就想辦法讓他重新走一遍spring註入容器,也可以采用這種方式:

@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
	
	// 這麼寫的目的是為瞭在SessionInterceptor中能註入spring中的service
	@Bean
	LoginInterceptor loginInterceptor() {
		return new LoginInterceptor();
	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 多個攔截器組成一個攔截器鏈
		// addPathPatterns 用於添加攔截規則
		// excludePathPatterns 用戶排除攔截
		registry.addInterceptor(loginInterceptor()).addPathPatterns("/**");
		super.addInterceptors(registry);
	}
}

二、過濾器方式

本人這一篇博客寫瞭關於filter的一些知識:https://www.jb51.net/article/204084.htm

1、實現Filter接口

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Component;

@Component
@WebFilter(filterName = "requestParamFilter",urlPatterns = "/*")
public class RequestParamFilter implements Filter {

	private static final Pattern SHOULD_NOT_FILTER_URL_PATTERN;
	
	static {
		List<String> urlList = new ArrayList<>();
		// 將不走攔截器的請求存放到Pattern
		urlList.add("(socket/.*)");
		urlList.add("(user/findUserList)");
		StringBuilder sb = new StringBuilder();
		for (String url : urlList) {
			sb.append(url);
			sb.append("|");
		}
		sb.setLength(sb.length() - 1);
		SHOULD_NOT_FILTER_URL_PATTERN = Pattern.compile(sb.toString());
	}

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
	
	// 發送請求會執行這個方法
    // 一個doFilter相當於攔截器的執行前和執行後
    // filterChain.doFilter後面的內容就是執行後的內容,假如不執行filterChain.doFilter方法相當於方法被攔截
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        System.out.println("sunhan---請求參數過濾器!---test1");
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpSession session = request.getSession();
		// 獲取訪問的url
 		String servletPath = request.getServletPath();
		// 排除特定請求
		if (SHOULD_NOT_FILTER_URL_PATTERN.matcher(servletPath).find()) {
			filterChain.doFilter(servletRequest,servletResponse);
		}
        System.out.println("開始攔截瞭................");
        //業務代碼
    }

    @Override
    public void destroy() {

    }
}

2、使用過濾器需要註意的

攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器裡註入一個service,可以調用業務邏輯

執行順序如下:

在這裡插入圖片描述

到此這篇關於淺談Springboot實現攔截器的兩種方式的文章就介紹到這瞭,更多相關Springboot 攔截器內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: