在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>
(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; } }
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; } }
三、小结
(1)通过解决这个问题,学会了filter的init-param该怎么玩(2)后续可以直接复用这个代码了,静态资源的放行直接在web.xml中配置。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/15529.html