文章目录
- Filter
- 快速入门
- url-pattern
- 生命周期
- FilterConfig
- FilterChain 过滤器链
- 执行顺序
Filter
Filter 过滤器它是 JavaWeb 的三大组件之一(Servlet 程序、Listener 监听器、Filter 过滤器)。
Filter 过滤器它的作用是:拦截请求,过滤响应。
快速入门
创建一个login界面和一个admin界面,只有通过了登录才能访问admin界面
login.html:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>管理后台登录</title>
</head>
<body>
<h1>管理后台登录</h1>
<form action="/login" method="post">
u:<input type="text" name="username"/> <br/><br/>
p:<input type="password" name="password"/> <br/><br/>
<input type="submit" value="用户登录"/></form>
</body>
</html>
admin.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>admin</h1>
</body>
</html>
servlet:
public class myServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
if ("lxg".equals(username) && "123".equals(password)) {
req.getSession().setAttribute("role", "admin");
req.getRequestDispatcher("/admin.html").forward(req, resp);
} else {
req.getRequestDispatcher("/login.html").forward(req, resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
filter:
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init()...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
Object role = request.getSession().getAttribute("role");
if (role != null && ((String) role).equals("admin")) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
((HttpServletResponse) servletResponse).sendRedirect("login.html");
}
}
@Override
public void destroy() {
System.out.println("destroy()...");
}
}
在web.xml中配置filter
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.lhs.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/admin.html</url-pattern>
</filter-mapping>
url-pattern
1)url-pattern : Filter 的拦截路径, 即浏览器在请求什么位置的资源时,过滤器会进行拦截过滤
2)精确匹配 <url-pattern>/a.jsp</url-pattern> 对应的 请求地址 http://ip[域名]:port/工程路径/a.jsp 会拦截
3)目录匹配 <url-pattern>/manage/*</url-pattern>对应的 请求地址 http://ip[域名]:port/工程路径/manage/xx , 即 web 工程 manage 目录下所有资源 会拦截
4)后缀名匹配 <url-pattern>*.jsp</url-pattern> 后缀名可变,比如 *.action *.do 等等对应的请求地址 http://ip[域名]:port/工程路径/xx.jsp , 后缀名为 .jsp 请求会拦截
5)Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在
生命周期
FilterConfig
FilterConfig 是 Filter 过滤器的配置类。
Tomcat 每次创建 Filter 的时候,也会创建一个 FilterConfig 对象,这里包含了 Filter 配置文件的配置信息。
FilterConfig 对象作用是获取 filter 过滤器的配置内容。
FilterConfig
接口定义了以下方法:
String getFilterName()
:获取Filter
的名称。String getInitParameter(String name)
:根据参数名称获取Filter
的初始化参数值。Enumeration\<String> getInitParameterNames()
:获取所有的初始化参数名称。ServletContext getServletContext()
:获取ServletContext
对象。
代码示例:拦截指定IP的请求
在web.xml文件中配置要拦截的ip段
<init-param>
<!-- 封杀 ip 段 -->
<param-name>ip</param-name>
<param-value>127.0.0</param-value>
</init-param>
public class MyFilter implements Filter {
List<String> blockIp;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String ip = filterConfig.getInitParameter("ip");
blockIp = new ArrayList<>();
blockIp.add(ip);
System.out.println("init()...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String host = request.getRemoteHost();
System.out.println(host);
for (String s : blockIp) {
if (host.contains(s)) {
System.out.println("封杀成功");
return;
}
}
}
@Override
public void destroy() {
System.out.println("destroy()...");
}
}
FilterChain 过滤器链
在处理某些复杂业务时,一个过滤器不够,可以设计多个过滤器共同完成过滤任务,形成过滤器链。
执行顺序
1)创建A、B两个过滤器
public class MyFilterA implements Filter {
List<String> blockIp;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("A init()...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("A过滤器前置代码");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("A过滤器后置代码");
}
@Override
public void destroy() {
System.out.println("A destroy()...");
}
}
public class MyfilterB implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("B init()...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("B过滤器前置代码");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("B过滤器后置代码");
}
@Override
public void destroy() {
System.out.println("B destroy()...");
}
}
2)配置web.xml
<filter>
<filter-name>myFilterA</filter-name>
<filter-class>com.lhs.filter.MyFilterA</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilterA</filter-name>
<url-pattern>/admin.html</url-pattern>
</filter-mapping>
<filter>
<filter-name>myFilterB</filter-name>
<filter-class>com.lhs.filter.MyfilterB</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilterB</filter-name>
<url-pattern>/admin.html</url-pattern>
</filter-mapping>
3)启动项目后访问admin.html查看过滤器调用顺序如下:
可见多个 filter 执行顺序,和 web.xml 配置顺序保持一致。
多个 filter 共同执行时,因为是一次 http 请求, 使用同一个 request 对象,在同一个线程中。
具体过程如下:
Http请求 -> A 过滤器 dofilter() -> A 过滤器前置代码 -> A 过滤器 chain.doFilter() -> B 过滤器 dofilter() -> B 过滤器前置代码 -> B过滤器 chain.doFilter() -> 目标文件 -> B过滤器后置代码 -> A过滤器后置代码 -> 返回给浏览器页面/数据