-
理解过滤器的作用
-
掌握过滤器的开发技巧
-
掌握项目中过滤器的应用场景
过滤器 - Filter
- 过滤器(Filter)是J2EE Servlet模块下的组件
- Filter的作用是对URL进行统一的拦截处理
- Filter通常应用于应用程序层面进行全局处理
过滤链
开发过滤器三要素
- 任何过滤器都要实现javax.servlet.Filter接口
- 在Filter接口的doFilter()方法中编写过滤器的功能代码
- 在web.xml中对过滤器进行配置,说明拦截URL的范围
案例:
MyFirstFilter.java
package filter;
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;
public class MyFirstFilter implements Filter{
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("过滤器已被销毁");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
System.out.println("过滤器已生效");
// 将请求与响应对象随着过滤链向后传递
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
System.out.println("过滤器初始化成功");
}
}
配置web.xml 后面会讲到使用注解的方式配置过滤器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>first-filter</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- filter标签用于说明哪个类是过滤器,并在应用启动时自动加载 -->
<filter>
<filter-name>MyFirstFilter</filter-name>
<filter-class>filter.MyFirstFilter</filter-class>
</filter>
<!--
filter-mapping标签用于说明过滤器对URL的应用范围,要点有二:
1. filter-name过滤器名称与filter.filter-name保持一致
2. url-pattern说明过滤器作用范围,/* 代表对所有URL进行过滤
-->
<filter-mapping>
<filter-name>MyFirstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
随便编写两个页面测试一下过滤器是否生效
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
我是默认首页
</body>
</html>
HelloServlet.java
package filter;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class HelloServlet
*/
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HelloServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("Hello World!!!");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
过滤器的生命周期
Tomcat启动应用加载时:初始化 - Filter.init()
程序运行过程中:提供服务 - Filter.doFilter()
web应用重启或关闭时:销毁 - Filter.destroy()
过滤器的特性–单例多线程
过滤器对象在Web应用启动时被创建且全局唯一
唯一的过滤器对象在并发环境中采用“多线程”提供服务
过滤器的配置形式–注解形式
在Tomcat3.0版本之后默认对注解进行支持,在应用程序启动时Tomcat对每一个字节码文件类进行扫描,检查注解实现配置
配置web.xml形式过滤器要比注解形式的过滤器先执行
import javax.servlet.annotation.WebFilter;
@WebFilter(filterName="MyFirstFilter",urlPatterns="/*")
public class MyFirstFilter implements Filter{
...
配置与注解如何选择
-
配置形式维护更好,适合应用全局过滤
-
注解形式开发体验更好,适用于小型项目敏捷开发
-
建议项目中统一使用配置或注解形式,否则两者混用会使项目难以维护
开发字符集过滤器
Web中文乱码的解决
- GET请求-server.xml增加URIEncoding=“UTF-8”
- POST请求-使用request.setCharacterEncoding(“UTF-8”);
- 响应-response.setContentType(“text/html;charset=UTF-8”)
除了第一点需要在server.xml中配置之外,其他两个都需要在代码中手动编写,在程序开发过程中少写任何一个都可能出现乱码问题,字符集过滤器的作用就是对所有请求进行前置处理,将请求与响应的字符集进行同一的设置,在使用servlet开发时就不需要写这两行代码来设置了,可以极大的降低程序员开发出错的风险。
CharacterEncodingFilter.java
package filter;
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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebFilter(filterName="CharacterEncodingFilter",urlPatterns="/*")
public class CharacterEncodingFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest req = (HttpServletRequest)request;
req.setCharacterEncoding("UTF-8");
HttpServletResponse res = (HttpServletResponse)response;
res.setContentType("text/html;charset=UTF-8");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
过滤器参数化
- 过滤器为了增强灵活性,允许配置信息放在web.xml
- 在web.xml中配置<init-param>设置过滤器参数
优化字符集过滤器
将可能会产生变化的字符集编码放到web.xml,可以方便的对程序进行调整,而且不需要重启系统编译就可以生效,在大多数开发中,过滤器中的一些可变的选项都进行参数化设置
配置web.xml进行参数化设置
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>first-filter</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
<!-- 设置多个同级加多个init-param -->
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
CharacterEncodingFilter.java 在init中使用filterConfig.getInitParameter()接收参数
package filter;
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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//@WebFilter(filterName="CharacterEncodingFilter",urlPatterns="/*")
public class CharacterEncodingFilter implements Filter {
private String encoding;
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest req = (HttpServletRequest)request;
req.setCharacterEncoding(encoding);
HttpServletResponse res = (HttpServletResponse)response;
res.setContentType("text/html;charset="+encoding);
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
encoding = filterConfig.getInitParameter("encoding");
System.out.println("encoding:"+encoding);
}
}
使用注解的形式进行参数化设置
CharacterEncodingFilter.java
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
@WebFilter(filterName="CharacterEncodingFilter",urlPatterns="/*",
initParams= {
@WebInitParam(name="encoding",value="UTF-8")
// @WebInitParam(name="p1",value="v1")
})
public class CharacterEncodingFilter implements Filter {
...
url-pattern设置过滤范围
- /index.jsp - 执行资源精准匹配
- /servlet/* - 以前缀进行模糊匹配 所有url以servlet开头的资源
- *.jsp - 以后缀进行模糊匹配
映射的问题
- /指映射web应用根路径,且只对Servlet生效
- 默认首页index.jsp会让/失效 比如定义一个servlet映射到/,但是如果有默认首页该servlet映射不会生效
- /与/*含义不同,前者指向根路径,后者代表所有
如果想同时映射多个规则,写多个filter-mapping即可,只要保持filter-mapping中的filter-name与filter中的对应,写不同的url-pattern
注解形式设置过滤范围
也是直接设置即可,如果要设置多个规则,映射到大括号数组
@WebFilter(filterName="CharacterEncodingFilter",urlPatterns={"/*","/servlet/*","*.jsp"})
在实际开发过程中这种复杂的配置,建议优先考虑配置形式
过滤器链开发注意事项
- 每一个过滤链应具有单独职能
- 过滤器的执行顺序以<filter-mapping>的顺序为准;注解描述的过滤器,按照类名(升序)进行排序
- 调用chain.doFilter()将请求向后传递,如果不向后传递则中断过滤链,可以根据此开发防火墙
多端设备自动适配案例
根据访问的设备不同显示不同的网页
DeviceAdapterFilter.java 判断设备过滤器
package filter;
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;
public class DeviceAdapterFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
String uri = req.getRequestURI();
System.out.println(uri);
// 判断字符串是否以某个字符串开始/结尾
// uri.startsWith("")
// uri.endsWith("")
if(uri.startsWith("/desktop") || uri.startsWith("/mobile")) {
chain.doFilter(req, res);
}else {
String userAgent = req.getHeader("User-Agent").toLowerCase();
String targetURI = "";
if(userAgent.indexOf("android")!=-1 || userAgent.indexOf("iphone")!=-1) {
targetURI = "/mobile"+uri;
System.out.println("移动端设备正在访问,重新跳转uri:");
//重新访问新的uri,中断当前过滤器重新进入
res.sendRedirect(targetURI);
}else {
targetURI = "/desktop"+uri;
System.out.println("PC端设备正在访问,重新跳转uri:");
res.sendRedirect(targetURI);
}
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
web.xml 配置过滤器
<filter>
<filter-name>DeviceAdapterFilter</filter-name>
<filter-class>filter.DeviceAdapterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>DeviceAdapterFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
/desktop/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
桌面端
</body>
</html>
/mobile/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
移动端
</body>
</html>