在javaweb開發中,過濾器Filter比較常用於類似登錄的攔截等場景。但是,當過濾器的配置不當時就會把所有的請求都攔截,靜態資源也會被攔截掉,導致靜態頁面加載不出來。
一般的解決方案是在過濾器代碼中對所有的靜態資源放行,但這樣硬編碼的方式特別不靈活,代碼復用性也不高。下面說個更優雅點的方案。
一、解決方案
如果將靜態資源放行的功能做成在web.xml中可以直接配置的話,就比較方便了。因此我們可以采用配置Filter的init-param的方式來配置那些資源不需要過濾器攔截,然后在過濾器Filter中的init方法去取這個配置的init-param。 具體的還是直接上代碼吧。
二、代碼
(1)web.xml中Filter的配置代碼片段如下
這里的重點是配置了一個init-param
<!--身份驗證、登錄、權限-->
<filter>
<filter-name>authorityFilter</filter-name>
<filter-class>com.hk.uc.client.filter.RestAuthorizeFilter</filter-class>
<init-param>
<!-- 配置不需要被登錄過濾器攔截的鏈接,只支持配后綴、前綴 及全路徑,多個配置用逗號分隔 -->
<param-name>excludedPaths</param-name>
<param-value>/pages/*,*.html,*.js,*.ico</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>authorityFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
x
14
1
<!--身份驗證、登錄、權限-->
2
<filter>
3
<filter-name>authorityFilter</filter-name>
4
<filter-class>com.hk.uc.client.filter.RestAuthorizeFilter</filter-class>
5
<init-param>
6
<!-- 配置不需要被登錄過濾器攔截的鏈接,只支持配后綴、前綴 及全路徑,多個配置用逗號分隔 -->
7
<param-name>excludedPaths</param-name>
8
<param-value>/pages/*,*.html,*.js,*.ico</param-value>
9
</init-param>
10
</filter>
11
<filter-mapping>
12
<filter-name>authorityFilter</filter-name>
13
<url-pattern>/*</url-pattern>
14
</filter-mapping>
(2)自定義Filter的代碼如下
代碼解釋如下:
- 首先我聲明了excludedPaths用來接收web.xml中配置的init-param
- 在init()方法中把init-param的值賦值給excludedPaths
- 寫一個方法用來判斷是否是直接放行的請求,這里寫了isFilterExcludeRequest()這個方法
- 在doFilter()這個方法中,先調用isFilterExcludeRequest()這個方法,判斷是否應該直接放行。如果不是直接放行才走我們的邏輯代碼
import java.io.IOException;
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.kangxiinfo.framework.common.util.StringUtils;
/**
* 身份認證過濾器
* @author ZENG.XIAO.YAN
* @time 2018-10-19 14:07:44
* @version v1.0
*/
public class RestAuthorizeFilter implements Filter {
/**
* 不需要被過濾器攔截的頁面 ,主要用於靜態資源的放行
* 在web.xml中配置filter的init-param
*/
private String excludedPaths;
private String [] excludedPathArray;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化時讀取web.xml中配置的init-param
excludedPaths = filterConfig.getInitParameter("excludedPaths");
if(!StringUtils.isNullOrBlank(excludedPaths)){
excludedPathArray = excludedPaths.split(",");
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 判斷是否是直接放行的請求
if (!isFilterExcludeRequest(request)) {
// TODO 這里寫你的過濾器處理邏輯
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
/**
* 判斷是否是 過濾器直接放行的請求
* <br/>主要用於靜態資源的放行
* @param url
* @return
*/
private boolean isFilterExcludeRequest(HttpServletRequest request) {
if(null != excludedPathArray && excludedPathArray.length > 0) {
String url = request.getRequestURI();
for (String ecludedUrl : excludedPathArray) {
if (ecludedUrl.startsWith("*.")) {
// 如果配置的是后綴匹配, 則把前面的*號干掉,然后用endWith來判斷
if(url.endsWith(ecludedUrl.substring(1))){
return true;
}
} else if (ecludedUrl.endsWith("/*")) {
if(!ecludedUrl.startsWith("/")) {
// 前綴匹配,必須要是/開頭
ecludedUrl = "/" + ecludedUrl;
}
// 如果配置是前綴匹配, 則把最后的*號干掉,然后startWith來判斷
String prffixStr = request.getContextPath() + ecludedUrl.substring(0, ecludedUrl.length() - 1);
if(url.startsWith(prffixStr)) {
return true;
}
} else {
// 如果不是前綴匹配也不是后綴匹配,那就是全路徑匹配
if(!ecludedUrl.startsWith("/")) {
// 全路徑匹配,也必須要是/開頭
ecludedUrl = "/" + ecludedUrl;
}
String targetUrl = request.getContextPath() + ecludedUrl;
if(url.equals(targetUrl)) {
return true;
}
}
}
}
return false;
}
}
94
1
import java.io.IOException;
2
import javax.servlet.Filter;
3
import javax.servlet.FilterChain;
4
import javax.servlet.FilterConfig;
5
import javax.servlet.ServletException;
6
import javax.servlet.ServletRequest;
7
import javax.servlet.ServletResponse;
8
import javax.servlet.http.HttpServletRequest;
9
import javax.servlet.http.HttpServletResponse;
10
import com.kangxiinfo.framework.common.util.StringUtils;
11
12
/**
13
* 身份認證過濾器
14
* @author ZENG.XIAO.YAN
15
* @time 2018-10-19 14:07:44
16
* @version v1.0
17
*/
18
public class RestAuthorizeFilter implements Filter {
19
/**
20
* 不需要被過濾器攔截的頁面 ,主要用於靜態資源的放行
21
* 在web.xml中配置filter的init-param
22
*/
23
private String excludedPaths;
24
private String [] excludedPathArray;
25
26
27
public void init(FilterConfig filterConfig) throws ServletException {
28
// 初始化時讀取web.xml中配置的init-param
29
excludedPaths = filterConfig.getInitParameter("excludedPaths");
30
if(!StringUtils.isNullOrBlank(excludedPaths)){
31
excludedPathArray = excludedPaths.split(",");
32
}
33
}
34
35
36
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
37
FilterChain filterChain) throws IOException, ServletException {
38
HttpServletRequest request = (HttpServletRequest) servletRequest;
39
HttpServletResponse response = (HttpServletResponse) servletResponse;
40
// 判斷是否是直接放行的請求
41
if (!isFilterExcludeRequest(request)) {
42
// TODO 這里寫你的過濾器處理邏輯
43
}
44
filterChain.doFilter(servletRequest, servletResponse);
45
}
46
47
48
49
public void destroy() {
50
// TODO Auto-generated method stub
51
}
52
53
/**
54
* 判斷是否是 過濾器直接放行的請求
55
* <br/>主要用於靜態資源的放行
56
* @param url
57
* @return
58
*/
59
private boolean isFilterExcludeRequest(HttpServletRequest request) {
60
if(null != excludedPathArray && excludedPathArray.length > 0) {
61
String url = request.getRequestURI();
62
for (String ecludedUrl : excludedPathArray) {
63
if (ecludedUrl.startsWith("*.")) {
64
// 如果配置的是后綴匹配, 則把前面的*號干掉,然后用endWith來判斷
65
if(url.endsWith(ecludedUrl.substring(1))){
66
return true;
67
}
68
} else if (ecludedUrl.endsWith("/*")) {
69
if(!ecludedUrl.startsWith("/")) {
70
// 前綴匹配,必須要是/開頭
71
ecludedUrl = "/" + ecludedUrl;
72
}
73
// 如果配置是前綴匹配, 則把最后的*號干掉,然后startWith來判斷
74
String prffixStr = request.getContextPath() + ecludedUrl.substring(0, ecludedUrl.length() - 1);
75
if(url.startsWith(prffixStr)) {
76
return true;
77
}
78
} else {
79
// 如果不是前綴匹配也不是后綴匹配,那就是全路徑匹配
80
if(!ecludedUrl.startsWith("/")) {
81
// 全路徑匹配,也必須要是/開頭
82
ecludedUrl = "/" + ecludedUrl;
83
}
84
String targetUrl = request.getContextPath() + ecludedUrl;
85
if(url.equals(targetUrl)) {
86
return true;
87
}
88
}
89
}
90
}
91
return false;
92
}
93
}
94
三、小結
(1)通過解決這個問題,學會了filter的init-param該怎么玩(2)后續可以直接復用這個代碼了,靜態資源的放行直接在web.xml中配置。