在Servlet中,可以通过实现Filter接口的方式对请求添加过滤器。Filter接口有如下几个方法:
package javax.servlet;
import java.io.IOException;
public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException;
public void destroy();
}
对于init方法和destroy方法,分别会在Filter创建和销毁的时候会被调用,也就是对于整个Filter生命周期,两个方法只会被调用一次。当我们通过实现Filter接口来自定义过滤器时,如果直接实现Filetr接口,要实现大量的init和destroy方法,这也许不是我们需要的。所以,为了简化实现,可抽象出如下的工具类:
(1)定义一个抽象类AbstractFilter,直接实现Filter接口,并提供一个filtering抽象方法由子类实现具体的过滤逻辑:
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
*
* 自定义Filter模板类
*
* 包访问权限为default,同一个包下面的类可以访问
*
* @author javaerui
* @Description:
* @date 2020/12/28
*/
abstract class AbstractFilter implements Filter {
/**
* 此方法时继承自Filter接口的,所以,每个Filter实现类都会调用此方法
* 但是可以在重写的doFilter方法中,添加逻辑,控制不一定都要调用filtering方法
*
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
doFilter((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse, filterChain);
}
/**
* 子类可以通过重写此方法来调整逻辑
* @param request
* @param response
* @param filterChain
* @throws IOException
* @throws ServletException
*/
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException{
filtering(request, response, filterChain);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// do something
}
@Override
public void destroy() {
// do something
}
/**
* 具体的过滤器去实现此方法,用来实现具体的过滤逻辑
* @param request
* @param response
* @param filterChain
* @throws IOException
* @throws ServletException
*/
protected abstract void filtering(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException;
}
(2)定义AbstractRequestFilter,继承AbstractFilter,重写了doFilter方法,添加白名单功能。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author javaerui
* @Description:
* @date 2020/12/28
*/
public abstract class AbstractRequestFilter extends AbstractFilter{
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRequestFilter.class);
/**
* 定义白名单,直接放行的请求url
*/
private static final String[] whiteList = {"/ehr/corp/init", "/client", "/account/signin"};
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
if (skipFiltering(request)) {
filterChain.doFilter(request, response);
return;
}
filtering(request, response, filterChain);
}
/**
* 是否跳过执行filtering方法
* 处理给第三方提供的接口,无需执行其他的过滤器了
* 子类可重写此方法来控制是否过滤
* @param request
* @return true,跳过执行filtering方法,否则,执行filtering
*/
protected boolean skipFiltering(HttpServletRequest request) {
String requestURI = request.getRequestURI();
for (String whiteURI : whiteList) {
if (requestURI.startsWith(whiteURI)) {
return true;
}
}
return false;
}
}
(3)自定义过滤器,通过继承AbstractRequestFilter,实现filtering方法来完成过滤逻辑:
import com.google.common.util.concurrent.RateLimiter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 限流过滤器
*/
public class AccessFilter extends AbstractRequestFilter {
private static final RateLimiter rateLimiter = RateLimiter.create(1000);
@Override
protected void filtering(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
if (rateLimiter.tryAcquire(1)) {
filterChain.doFilter(request, response);
} else {
// 拦截住当前请求
...
}
}
/**
* 重写AbstractRequestFilter中的方法,永远返回false,表示不放过任何的请求URL
* @param request
* @return
*/
@Override
protected boolean skipFiltering(HttpServletRequest request) {
return false;
}
}