在servlet开发中,对于请求的拦截,常使用filter过滤器,这里结合源码对Filter过滤器进行介绍。
Filter过滤器是实现特殊接口的java类,由servlet容器调用执行,可用于权限过滤、日志记录、图片转换、加密、数据压缩等操作。
Filter过滤器核心类是Filter,关联的还有有FilterConfig、FilterChain,其实是三个接口,。下面结合源码分别介绍。
Filter是在请求到响应(servlet或静态资源),或者一个响应到另一个响应中间,执行过滤任务的对象。Filter执行过滤任务是在方法doFilter中。源码如下:
package javax.servlet;
import java.io.IOException;
public interface Filter {
//初始化方法,容器创建Filter对象后,立即调用init方法,整个生命周期中只执行一次。
//在init方法成功(失败如抛异常等)执行完前,不能提供过滤服务。
//参数FilterConfig用于获取初始化参数
public void init(FilterConfig filterConfig) throws ServletException;
//执行过滤任务的方法,参数FilterChain表示Filter链,doFilter方法中只有执行FilterChain只有执行了doFilter方法,
//才能将请求交经下一个Filter或Servlet执行
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException;
//销毁方法,当移出服务时由web容器调用。整个生命周期中destroy方法只会执行一次
//destroy方法可用于释放持有的资源,如内存、文件句柄等
public void destroy();
}
FilterConfig用于获取过滤器的初始化参数。源码如下:
package javax.servlet;
import java.util.Enumeration;
public interface FilterConfig {
//获取过滤器名称
public String getFilterName();
//获取关联的ServletContext
public ServletContext getServletContext();
//获取指定名称的初始化参数
public String getInitParameter(String name);
//获取初始化参数名称集合
public Enumeration<String> getInitParameterNames();
}
FilterChain是容器提供给开发者的,用于调用Filter链上的下一个Filter或最终servlet服务。
package javax.servlet;
import java.io.IOException;
public interface FilterChain {
//调用引用链的下一个filter或最终servlet服务
public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;
}
过滤器注册有两种方式,使用常规的xml注册和使用注解注册(会在示例代码中以注释的方式体现)。这里以常规xml注册为例。xml注册是在项目的web.xml上注册的,可以对指定访问路径或指定servlet进行拦截,示例如下:
<filter-name>demoFitlerfilter-name>
<filter-class>filter.DemoFilterfilter-class>
<init-param>
<param-name>forbidIdsparam-name>
<param-value>002,003,004param-value>
init-param>
filter>
<filter-mapping>
<filter-name>demoFitlerfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
资源servlet类DemoServlet.java如下:
package filter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name="DemoServlet", urlPatterns = "/demoServlet")
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write("this is a demo test");
}
}
过滤器DemoFilter.java
package filter;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
import java.util.Objects;
//可以使用下面注解方式注册Filter,其中urlPatterns拦截指定路径,demoServlet拦截指定servlet
//@WebFilter(filterName = "demoFilter", urlPatterns = "/*", servletNames = "demoServlet",
// initParams = {@WebInitParam(name = "forbidIds", value = "002,003,004")})
public class DemoFilter implements Filter {
private FilterConfig filterConfig;
private String forbidIds;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
//获取初始化参数
forbidIds = filterConfig.getInitParameter("forbidIds");
System.out.println("forbidIds:" + forbidIds);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String id = request.getParameter("id");
if (StringUtils.isBlank(forbidIds) || !forbidIds.contains(Objects.toString(id, "001"))) {
//不拦截,调用后续访问
chain.doFilter(request, response);
} else {
//拦截,输出错误信息
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("forbid");
}
}
@Override
public void destroy() {
System.out.println("DemoFilter destroy");
}
}
响应:
请求:http://localhost:8080/demoServlet?id=001
响应:this is a demo test
请求:http://localhost:8080/demoServlet?id=002
响应:forbid