Day62 Filter过滤器
简介
Filter:过滤器,通过Filter可以拦截访问web资源的请求与响应操作。
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器。他可以拦截Jsp、Servlet、 静态图片文件、静态 html文件等,从而实现一些特殊的功能。
例如:实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
服务器发送请求,通过层层过滤器,才能访问资源
创建步骤
- 创建过滤器类并实现Filter接口
- 在web.xml文件中配置Filter
javax.servlet.Filter接口中的方法介绍:
方法 描述 init(FilterConfig fConfig) 初始化方法 doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 过滤方法 destroy() 销毁方法
1.初始Filter过滤器
创建过滤器的步骤:
1.创建Java类,实现Filter接口(javax.servlet.Filter)
2.在web.xml中配置
操作
Welcome.html
导包servlet-api.jar,在web.xml中配置首页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>欢迎页面</h1>
<a href="ser01">向Servlet01发送一个请求</a>
</body>
</html>
Filter01
package com.qf.filter;
public class Filter01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter01 -- doFilter() -- 前");
//chain过滤器链
//注意:如果拦截后不调用doFilter(),请求将无法传到下一个过滤器或服务器里
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("Filter01 -- doFilter() -- 后");
}
@Override
public void destroy() {
}
}
Servlet01
package com.qf.servlet;
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet01收到了一个请求");
}
}
在web.xml配置文件中配置过滤器信息
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>Welcome.html</welcome-file>
</welcome-file-list>
<filter>
<filter-name>Filter01</filter-name>
<filter-class>com.qf.filter.Filter01</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter01</filter-name>
<url-pattern>/*</url-pattern><!-- 拦截所有请求 -->
</filter-mapping>
</web-app>
2.过滤器链
客户端对服务器请求之后,服务器在调用Servlet之前,会执行一组过滤器(多个过滤器),那么这组过滤器就称为一条过滤器链。
过滤器链是指在一个Web应用,可以配置多个过滤器,这多个过滤器称为过滤器链。
3.Filter的生命周期
3.1生命周期 - 单个过滤器
单个过滤器的生命周期:
创建:项目启动时 – 无参构造、init()
销毁:服务器正常关闭时 – destroy()
package com.qf.filter;
public class Filter01 implements Filter {
public Filter01(){
System.out.println("Filter01 -- Filter01()");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String code = filterConfig.getInitParameter("code");
System.out.println("Filter01 -- init() -- " + code);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter01 -- doFilter() -- 前");
//放行
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("Filter01 -- doFilter() -- 后");
}
@Override
public void destroy() {
System.out.println("Filter01 -- destroy()");
}
}
在web.xml配置文件中配置初始化参数信息 code-UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>Welcome.html</welcome-file>
</welcome-file-list>
<filter>
<filter-name>Filter01</filter-name>
<filter-class>com.qf.filter.Filter01</filter-class>
<init-param>
<param-name>code</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Filter01</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
运行结果:
3.2 生命周期 - 多个过滤器
Filter的生命周期:
创建:项目启动时 – 无参构造、init()
销毁:服务器正常关闭时 – destroy()
Filter的创建顺序 – 不用关注:
多线程抢资源(创建顺序无序)
Filter的调用顺序 – 关注:
web.xml配置 ------> 按照配置顺序
@WebFilter配置 --> 按照类名的字典排序
经验:一般使用web.xml配置
是单例模式
//----------- Filter01 -----------------------
public class Filter01 implements Filter {
public Filter01() {
System.out.println("Filter01 - Filter01()");
}
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("Filter01 - init()");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("Filter01执行前");
chain.doFilter(request, response);//放行
System.out.println("Filter01执行后");
}
public void destroy() {
System.out.println("Filter01 - destroy()");
}
}
//----------- Filter02 -----------------------
public class Filter02 implements Filter {
public Filter02() {
System.out.println("Filter02 - Filter02()");
}
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("Filter02 - init()");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("Filter02执行前");
chain.doFilter(request, response);//放行
System.out.println("Filter02执行后");
}
public void destroy() {
System.out.println("Filter02 - destroy()");
}
}
//----------- Filter03 -----------------------
public class Filter03 implements Filter {
public Filter03() {
System.out.println("Filter03 - Filter03()");
}
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("Filter03 - init()");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("Filter03执行前");
chain.doFilter(request, response);//放行
System.out.println("Filter03执行后");
}
public void destroy() {
System.out.println("Filter03 - destroy()");
}
}
2.在web.xml配置文件中配置过滤器信息
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<welcome-file-list>
<welcome-file>welcome.html</welcome-file>
</welcome-file-list>
<filter>
<filter-name>Filter01</filter-name>
<filter-class>com.qf.filter.Filter01</filter-class>
<init-param>
<param-name>code</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Filter01</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>Filter02</filter-name>
<filter-class>com.qf.filter.Filter02</filter-class>
<init-param>
<param-name>code</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Filter02</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>Filter03</filter-name>
<filter-class>com.qf.filter.Filter03</filter-class>
<init-param>
<param-name>code</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Filter03</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3.3 注解配置过滤器(简化配置)
创建顺序:创建顺序无序
执行顺序:按照类名的顺序执行
注意:一般不使用这个
@WebFilter(value="/*",initParams={@WebInitParam(name="encode",value="UTF-8")})
public class EncodeFilter implements Filter {
...
}
4.案例
4.1 案例一:编码过滤器
解决请求和响应乱码问题
package com.qf.filter;
public class CodeFilter implements Filter {
private String code;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//获取web.xml中该过滤器的初始化属性
code = filterConfig.getInitParameter("code");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding(code);
servletResponse.setContentType("text/html;charset="+code);
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
<filter>
<filter-name>CodeFilter</filter-name>
<filter-class>com.qf.filter.CodeFilter</filter-class>
<init-param>
<param-name>code</param-name><!-- 初始化参数名 -->
<param-value>UTF-8</param-value><!-- 初始化参数值 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>CodeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4.2 案例二:登录权限过滤器
解决权限的统一控制问题,没有登录,就不能直接跳转到其他详情页面
package com.qf.filter;
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//强转
HttpServletRequest request= (HttpServletRequest) servletRequest;
HttpServletResponse response= (HttpServletResponse) servletResponse;
//获取请求地址
String uri = request.getRequestURI();
if (uri.equals("/Day19_war_exploded/") ||
uri.contains("register.jsp") ||
uri.contains("RegisterServlet") ||
uri.contains("welcome.html") ||
uri.contains("login.jsp") ||
uri.contains("CodeServlet") ||
uri.contains("LoginServlet") ){
filterChain.doFilter(request,response);
}else {
//如果登录成功,会存储session凭证
HttpSession session = request.getSession();
String username = (String) session.getAttribute("username");
String name = (String) session.getAttribute("name");
String role = (String) session.getAttribute("role");
if (username==null||name==null||role==null){//session凭证为空,不允许登录
response.sendRedirect("login.jsp");
}else {
if(!role.equals("teacher") && uri.contains("GetStuListServlet")){
response.sendRedirect("login.jsp");
}else{
filterChain.doFilter(request,response);
}
}
}
}
@Override
public void destroy() {
}
}
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.qf.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4.3 案例三:关键字过滤器
解决文档内的一个敏感词汇
Welcome.html,提交建议
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<a href="proposal.jsp">提交建议</a>
</body>
</html>
proposal.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>建议页面</h1>
<form action="ProposalServlet" method="post">
建议:<input type="text" name="info"><br>
<input type="submit" value="提交"/>
<input type="button" value="返回" οnclick="goIndex()"/>
</form>
<script type="text/javascript">
function goIndex(){
window.location = "Welcome.html";
}
</script>
</body>
</html>
MyHttpServletRequestWrapper
请求包装类,处理敏感词
package com.qf.wrapper;
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
//有参构造
public MyHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
//子类重写
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
//把尖括号替换成字符尖括号,替换后不会认为是html里的尖括号符号
value = value.replaceAll("<", "<");
value = value.replaceAll(">", ">");
value = value.replaceAll("傻逼", "**");
return value;
}
}
SensitiveWordsFilter
package com.qf.filter;
public class SensitiveWordsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//创建请求包装类对象(注意:对象中包含了请求对象)
MyHttpServletRequestWrapper myHttpServletRequestWrapper = new MyHttpServletRequestWrapper(request);
//放行的是请求包装类对象
filterChain.doFilter(myHttpServletRequestWrapper,response);
}
@Override
public void destroy() {
}
}
<filter>
<filter-name>SensitiveWordsFilter</filter-name>
<filter-class>com.qf.filter.SensitiveWordsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SensitiveWordsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
运行结果:
总结
Filter
概念
理解:过滤器链
过滤器的生命周期
案例