Filter,过滤器,顾名思义,即是对数据等的过滤,预处理过程。为什么要引入过滤器呢?在平常访问网站的时候,有时候发一些敏感的信息,发出后显示时 就会将敏感信息用*等字符替代,这就是用过滤器对信息进行了处理。这只是一个简单的例子,当然,过滤器那么强大,它的功能也不可能局限于此,它不仅能预处 理数据,只要是发送过来的请求它都是可以预处理的,同时,它还可以对服务器返回的响应进行预处理,这样,大大减轻了服务器的压力。例如,实现URL级别的 权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。下面来详细介绍一下过滤器。
一、定义
学习一个东西,我们首先要理解它的定义。
1.概念
过滤作用,对从客户端向服务器端发送的请求进行过滤,也可以对服务器端返回的响应进行处理。它使用户可以改变一个request和修改一个 response.。Filter 不是一个servlet,它不能产生一个response,但是它能够在一个request到达servlet之前预处理request,也可以在 response离开servlet时处理response。换句话说,filter其实是客户端与servlet中间的一个传递者,并且它可以对要传递 的东西进行修改。
注意:过滤器是用来拦截请求和响应的,不能产生响应,而servlet是用来处理请求并产生响应的。
2.适用场合
实现URL级别的权限访问控制,过滤敏感词汇,压缩响应信息等。
3.过滤器如何实现拦截
当客户端发生请求后,在HttpServletRequest 到达Servlet 之前,过滤器拦截客户的HttpServletRequest 。
根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。
在过滤器中调用doFilter方法,对请求放行。请求到达Servlet后,对请求进行处理并产生HttpServletResponse发送给客户端。
在HttpServletResponse 到达客户端之前,过滤器拦截HttpServletResponse 。
根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。
最后,HttpServletResponse到达客户端。
4.Filter接口
Servlet API提供了一个Filter接口,编写的过滤器必须实现该接口。
5.Filter的生命周期
(1)Filter接口中有三个重要的方法。
init()方法:初始化参数,在创建Filter时自动调用。当我们需要设置初始化参数的时候,可以写到该方法中。
doFilter()方法:拦截到要执行的请求时,doFilter就会执行。这里面写我们对请求和响应的预处理。
destroy()方法:在销毁Filter时自动调用。
(2)Filter的生命周期
Filter的创建和销毁由web服务器控制。
服务器启动的时候,web服务器创建Filter的实例对象,并调用其init方法,完成对象的初始化功能。filter对象只会创建一次,init方法也只会执行一次。
拦截到请求时,执行doFilter方法。可以执行多次。
服务器关闭时,web服务器销毁Filter的实例对象。
6.Filter对象——FilterConfig
用 户在配置filter时,可以使用为filter配置一些初始化参数,当web容器实例化Filter对象,调用其 init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过 filterConfig对象的方法,就可获得:
String getFilterName():得到filter的名称。
String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
public ServletContext getServletContext():返回Servlet上下文对象的引用。
7.过滤器链——FilterChain
一组过滤器对某些web资源进行拦截,那么这组过滤器就称为过滤器链。过滤器的执行顺序和有关(谁在前先执行谁)。
二、开发步骤
了解了过滤器的相关概念,接下来进行实例开发。
1.编写步骤
编写java类实现Filter接口,并实现其doFilter方法。
在 web.xml 文件中使用和元素对编写的filter类进行注册,并设置它所能拦截的资源。
2.示例
(1)简单的Filter示例
编写FilterDemo1类
1 packagecom.oracle.filter;
2
3 importjava.io.IOException;
4
5 importjavax.servlet.Filter;
6 importjavax.servlet.FilterChain;
7 importjavax.servlet.FilterConfig;
8 importjavax.servlet.ServletException;
9 importjavax.servlet.ServletRequest;
10 importjavax.servlet.ServletResponse;
11
12 public class FilterDemo1 implementsFilter{
13
14 /*
15 * 对Filter的整个生命周期了解的一个案例
16 * 注意事项:
17 * 1.实现Filter接口时导入的是javax.servlet.Filter包
18 * 2.方法均有web服务器自动调用,不需我们手动调用
19 * 3.init方法中一般写初始化参数,这里先不用,后面的例子再使用。
20 * 4.destroy方法一般不需要写任何代码
21 * 5.重写doFilter方法,可以写我们对拦截的请求和响应的处理动作。
22 * 6.写完该类后配置filter,在web.xml中配置。
23 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
24 */
25 @Override
26 public void init(FilterConfig filterConfig) throwsServletException {
27 //TODO Auto-generated method stub
28 System.out.println("FilterDemo1的init方法被调用");
29 }
30
31 @Override
32 public voiddoFilter(ServletRequest request, ServletResponse response,
33 FilterChain chain) throwsIOException, ServletException {
34 //TODO Auto-generated method stub
35 System.out.println("我是FilterDemo1,客户端向Servlet发送的请求被我拦截到了");
36 chain.doFilter(request, response);
37 System.out.println("我是FilterDemo1,Servlet向客户端发送的响应被我拦截到了");
38 }
39
40 @Override
41 public voiddestroy() {
42 //TODO Auto-generated method stub
43 System.out.println("FilterDemo1的destroy方法被调用");
44 }
45
46 }
配置filter,在web.xml文件中加入下面这段代码
1
2 filterDemo1
3 com.oracle.filter.FilterDemo1
4
5
6 filterDemo1
7 /*
8
9
控制台结果
分 析:从上面结果可以看出,在服务器启动时,就调用了init方法,当访问页面时,该过滤器拦截到请求执行doFilter方法,在该方法中,使用 doFilter方法,当返回响应后,继续执行剩下的代码,执行完成后将响应传给客户端。当关闭服务器时,服务器就调用了destroy方法。
(2)Filter链示例
编写FilterDemo1类
1 packagecom.oracle.filter;
2
3 importjava.io.IOException;
4
5 importjavax.servlet.Filter;
6 importjavax.servlet.FilterChain;
7 importjavax.servlet.FilterConfig;
8 importjavax.servlet.ServletException;
9 importjavax.servlet.ServletRequest;
10 importjavax.servlet.ServletResponse;
11
12 public class FilterDemo1 implementsFilter{
13
14 /*
15 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
16 */
17 @Override
18 public void init(FilterConfig filterConfig) throwsServletException {
19 //TODO Auto-generated method stub
20 }
21
22 @Override
23 public voiddoFilter(ServletRequest request, ServletResponse response,
24 FilterChain chain) throwsIOException, ServletException {
25 //TODO Auto-generated method stub
26 System.out.println("我是FilterDemo1,客户端向Servlet发送的请求被我拦截到了");
27 //对请求放行,进入下一个过滤器FilterDemo2
28 chain.doFilter(request, response);
29 System.out.println("我是FilterDemo1,Servlet向客户端发送的响应被我拦截到了");
30 }
31
32 @Override
33 public voiddestroy() {
34 //TODO Auto-generated method stub
35 }
36
37 }
编写FilterDemo2类
1 packagecom.oracle.filter;
2
3 importjava.io.IOException;
4
5 importjavax.servlet.Filter;
6 importjavax.servlet.FilterChain;
7 importjavax.servlet.FilterConfig;
8 importjavax.servlet.ServletException;
9 importjavax.servlet.ServletRequest;
10 importjavax.servlet.ServletResponse;
11
12 public class FilterDemo2 implementsFilter{
13
14 @Override
15 public void init(FilterConfig filterConfig) throwsServletException {
16 //TODO Auto-generated method stub
17
18 }
19
20 @Override
21 public voiddoFilter(ServletRequest request, ServletResponse response,
22 FilterChain chain) throwsIOException, ServletException {
23 //TODO Auto-generated method stub
24 System.out.println("我是FilterDemo2,客户端向Servlet发送的请求被我拦截到了");
25 //对请求放行,进入Servlet
26 chain.doFilter(request, response);
27 System.out.println("我是FilterDemo2,Servlet向客户端发送的响应被我拦截到了");
28 }
29
30 @Override
31 public voiddestroy() {
32 //TODO Auto-generated method stub
33
34 }
35
36 }
配置filter,在web.xml文件中加入下面这段代码
1
2 filterDemo1
3 com.oracle.filter.FilterDemo1
4
5
6 filterDemo2
7 com.oracle.filter.FilterDemo2
8
9
10
11 filterDemo1
12 /*
13
14
15
16 filterDemo2
17 /*
18
19
控制台结果
分 析:当有多个过滤器对同一个请求进行拦截时,根据web.xml文件中的配置顺序,谁在前,先执行谁。当第 一过滤器拦截成功后,会执行doFilter方法,该方法中,调用chain.doFilter方法,会将该请求放行给下一个过滤器,依次执行,直到执行 到最后一个过滤器,当最后一个过滤器调用chain.doFilter方法时,请求会被放行给Servlet,当Servlet处理返回响应信息时,先返 回到最后执行的过滤器,继续执行该过滤器剩下的代码。依次返回,直到返回到第一个过滤器,最后返回给客户端。
(3)禁用所有动态页面的缓存过滤器
编写FilterDemo3类
1 packagecom.oracle.filter;
2
3 importjava.io.IOException;
4
5 importjavax.servlet.Filter;
6 importjavax.servlet.FilterChain;
7 importjavax.servlet.FilterConfig;
8 importjavax.servlet.ServletException;
9 importjavax.servlet.ServletRequest;
10 importjavax.servlet.ServletResponse;
11 importjavax.servlet.http.HttpServletResponse;
12
13 public class FilterDemo3 implementsFilter{
14
15 @Override
16 public void init(FilterConfig filterConfig) throwsServletException {
17 //TODO Auto-generated method stub
18
19 }
20
21 @Override
22 public voiddoFilter(ServletRequest request, ServletResponse response,
23 FilterChain chain) throwsIOException, ServletException {
24 //在response的头部设置Cache-Control、Pragma和Expires即可取消缓存
25 HttpServletResponse resp =(HttpServletResponse)response;
26 resp.setHeader("Cache-Control", "no-cache");
27 resp.setHeader("Pragma", "no-cache");
28 resp.setDateHeader("Expires", -1);
29 chain.doFilter(request, resp);
30 }
31
32 @Override
33 public voiddestroy() {
34 //TODO Auto-generated method stub
35
36 }
37
38 }
配置filter,在web.xml文件中加入下面这段代码
1
2 filterDemo3
3 com.oracle.filter.FilterDemo3
4
5
6
7 filterDemo3
8 /*
9
(4) 分IP统计网站的访问次数过滤器
编写FilterDemo4类
1 packagecom.oracle.filter;
2
3 importjava.io.IOException;
4 importjava.util.HashMap;
5 importjava.util.Map;
6
7 importjavax.servlet.Filter;
8 importjavax.servlet.FilterChain;
9 importjavax.servlet.FilterConfig;
10 importjavax.servlet.ServletContext;
11 importjavax.servlet.ServletException;
12 importjavax.servlet.ServletRequest;
13 importjavax.servlet.ServletResponse;
14
15 public class FilterDemo4 implementsFilter{
16
17 privateFilterConfig filterConfig;
18 @Override
19 public void init(FilterConfig filterConfig) throwsServletException {
20 //TODO Auto-generated method stub
21
22 //初始化参数,ipCount用来存放ip及访问次数
23 ServletContext application =filterConfig.getServletContext();
24 Map ipCount = new HashMap();
25 application.setAttribute("ipCount",ipCount);
26 this.filterConfig =filterConfig;
27 }
28
29
30 @Override
31 public voiddoFilter(ServletRequest request, ServletResponse response,
32 FilterChain chain) throwsIOException, ServletException {
33 //TODO Auto-generated method stub
34 ServletContext application =filterConfig.getServletContext();
35 Map ipCount = (HashMap)application.getAttribute("ipCount");
36 String ip =request.getRemoteAddr();
37 Integer count =ipCount.get(ip);
38 if(count != null){
39 //Map中存在该ip
40 count = count + 1;
41 }else{
42 count = 1;
43 }
44 ipCount.put(ip, count);
45 application.setAttribute("ipCount",ipCount);
46 chain.doFilter(request, response);
47 }
48
49 @Override
50 public voiddestroy() {
51 //TODO Auto-generated method stub
52
53 }
54
55 }
编写index.jsp页面
1
2
3
4 String path =request.getContextPath();
5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
6 %>
7
8
9
10
11
12
13
My JSP 'index.jsp' starting page14
15
16
17
18
19
22
23
24
25
分IP统计网站浏览次数
26
27
28
IP地址29
浏览次数30
31
32
33
${m.key}34
${m.value}35
36
37
38
39
配置filter,在web.xml文件中加入下面这段代码
1
2 filterDemo4
3 com.oracle.filter.FilterDemo4
4
5
6
7 filterDemo4
8 /*
9
网页结果
(5)自动登录
编写AutoLoginFilter类
1 packagecom.oracle.filter;
2
3 importjava.io.IOException;
4
5 importjavax.servlet.Filter;
6 importjavax.servlet.FilterChain;
7 importjavax.servlet.FilterConfig;
8 importjavax.servlet.ServletException;
9 importjavax.servlet.ServletRequest;
10 importjavax.servlet.ServletResponse;
11 importjavax.servlet.http.Cookie;
12 importjavax.servlet.http.HttpServletRequest;
13 importjavax.servlet.http.HttpSession;
14
15 importcom.oracle.biz.UserInfoBiz;
16 importcom.oracle.biz.impl.UserInfoBizImpl;
17 importcom.oracle.entity.UserInfo;
18 importcom.oracle.util.CookieUtil;
19
20 public class AutoLoginFilter implementsFilter{
21
22 @Override
23 public void init(FilterConfig filterConfig) throwsServletException {
24 //TODO Auto-generated method stub
25
26 }
27
28 @Override
29 public voiddoFilter(ServletRequest request, ServletResponse response,
30 FilterChain chain) throwsIOException, ServletException {
31 //TODO Auto-generated method stub
32 //先判断session中是否存在,存在则放行,不存在则判断cookie中是否存在用户名密码,存在则到数据库中查询是否正确,正确则存入session并放行,不正确则放行
33 HttpServletRequest req =(HttpServletRequest)request;
34 HttpSession session =req.getSession();
35 UserInfo user = (UserInfo)session.getAttribute("user");
36 if(user != null){
37 chain.doFilter(req, response);
38 }else{
39 //session中不存在用户
40 Cookie[] cookies =req.getCookies();
41 Cookie cookie = CookieUtil.findCookie(cookies, "autoLogin");
42 if(cookie!=null){
43 //在cookie中找到该用户
44 UserInfoBiz ubiz = newUserInfoBizImpl();
45 String name = cookie.getValue().split("#oracle#")[0];
46 String pwd = cookie.getValue().split("#oracle#")[1];
47 String msg =ubiz.login(name, pwd);
48 if("登陆成功!".equals(msg)){
49 user =ubiz.getByName(name);
50 session.setAttribute("user", user);
51 chain.doFilter(req, response);
52 }else{
53 chain.doFilter(req, response);
54 }
55 }else{
56 //没有找到该客户
57 chain.doFilter(req, response);
58 }
59 }
60 }
61
62 @Override
63 public voiddestroy() {
64 //TODO Auto-generated method stub
65
66 }
67
68
69 }
编写DoLoginServlet
1 packagecom.oracle.servlet;
2
3 importjava.io.IOException;
4
5 importjavax.servlet.ServletException;
6 importjavax.servlet.http.Cookie;
7 importjavax.servlet.http.HttpServlet;
8 importjavax.servlet.http.HttpServletRequest;
9 importjavax.servlet.http.HttpServletResponse;
10 importjavax.servlet.http.HttpSession;
11
12 importcom.oracle.biz.UserInfoBiz;
13 importcom.oracle.biz.impl.UserInfoBizImpl;
14 importcom.oracle.entity.UserInfo;
15
16 public class DoLoginServlet extendsHttpServlet {
17
18 /**
19 * Constructor of the object.
20 */
21 publicDoLoginServlet() {
22 super();
23 }
24
25 /**
26 * Destruction of the servlet.
27 */
28 public voiddestroy() {
29 super.destroy(); //Just puts "destroy" string in log
30 //Put your code here
31 }
32
33 /**
34 * The doGet method of the servlet.
35 *
36 * This method is called when a form has its tag value method equals to get.
37 *
38 * @paramrequest the request send by the client to the server
39 * @paramresponse the response send by the server to the client
40 * @throwsServletException if an error occurred
41 * @throwsIOException if an error occurred
42 */
43 public voiddoGet(HttpServletRequest request, HttpServletResponse response)
44 throwsServletException, IOException {
45
46 doPost(request,response);
47 }
48
49 /**
50 * The doPost method of the servlet.
51 *
52 * This method is called when a form has its tag value method equals to post.
53 *
54 * @paramrequest the request send by the client to the server
55 * @paramresponse the response send by the server to the client
56 * @throwsServletException if an error occurred
57 * @throwsIOException if an error occurred
58 */
59 public voiddoPost(HttpServletRequest request, HttpServletResponse response)
60 throwsServletException, IOException {
61
62 HttpSession session =request.getSession();
63 request.setCharacterEncoding("UTF-8");
64 response.setCharacterEncoding("UTF-8");
65 String name = request.getParameter("myname");
66 String pwd = request.getParameter("pwd");
67 String autoLogin = request.getParameter("autoLogin");
68 UserInfoBiz ubiz = newUserInfoBizImpl();
69 //ubiz.login(name, pwd):判断用户是否登陆成功,返回一个字符串。成功则返回"登陆成功!",不成功则返回对应的错误提示。
70 String msg =ubiz.login(name, pwd);
71 if("登陆成功!".equals(msg)){
72 UserInfo user =ubiz.getByName(name);
73 session.setAttribute("user", user);
74 if("true".equals(autoLogin)){
75 //利用cookie记住用户名和密码
76 Cookie cookie = new Cookie("autoLogin",user.getUserName()+"#oracle#"+user.getPassword());
77 //设置有效时间
78 cookie.setMaxAge(60*60*24);
79 //将cookie回写到浏览器
80 response.addCookie(cookie);
81 }
82 response.sendRedirect("success.jsp");
83 }else{
84 request.setAttribute("msg", msg);
85 request.getRequestDispatcher("login.jsp").forward(request, response);
86 }
87 }
88
89 /**
90 * Initialization of the servlet.
91 *
92 * @throws ServletException if an error occurs
93 */
94 public void init() throws ServletException {
95 // Put your code here
96 }
97
98 }
编写CookieUtil
1 packagecom.oracle.util;
2
3 importjavax.servlet.http.Cookie;
4
5
6
7 public classCookieUtil {
8
9 public staticCookie findCookie(Cookie[] cookies,String name){
10 if(cookies==null){
11 return null;
12 }else{
13 for(Cookie cookie:cookies){
14 if(cookie.getName().equals(name)){
15 returncookie;
16 }
17 }
18 return null;
19 }
20 }
21 }
编写login.jsp
1
2
3 Stringpath =request.getContextPath();
4 StringbasePath =request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
5 %>
6
7
8
9
10
11
12
My JSP 'login.jsp' starting page13
14
15
16
17
18
19
22
23
24
25
26
27 用户名
28 密 码
29 自动登录
30
31
32
33
编写success.jsp
1
2
3
4 Stringpath =request.getContextPath();
5 StringbasePath =request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
6 %>
7
8
9
10
11
12
13
My JSP 'success.jsp' starting page14
15
16
17
18
19
20
23
24
25
26
27
28
您还未登陆,请去登陆
29
30
31
欢迎你${user.userName}
32
33
34
配置filter和servlet,在web.xml文件中加入下面的代码
1
2 This is the description of my J2EE component
3 This is the display name of my J2EE component
4 DoLoginServlet
5 com.oracle.servlet.DoLoginServlet
6
7
8
9 DoLoginServlet
10 /doLogin
11
12
13
14 AutoLoginFilter
15 com.oracle.filter.AutoLoginFilter
16
17
18 AutoLoginFilter
19 /*
20
(6)处理网站的Get和Post请求乱码
思 路:增强request对象的getParameter方法等方法。编写一个类MyHttpServletRequest实现 HttpServletRequestWrapper,重写它的getParameter方法等方法,在这些方法中对不同方式提交的数据进行转码。在过滤 器中,将request强制转换成MyHttpServletRequest类型的对象,这样,当再次使用getParameter等方法时其实调用的是 你重写后的getParametr方法,也就是已经处理过的数据,这样就不用再担心乱码的问题了。
MyHttpServletRequest类
1 packagecom.oracle.bookshop.filter;
2
3 importjava.io.UnsupportedEncodingException;
4 importjava.util.Map;
5
6 importjavax.servlet.http.HttpServletRequest;
7 importjavax.servlet.http.HttpServletRequestWrapper;
8
9
10 public class MyHttpServletRequest extendsHttpServletRequestWrapper {
11 /*
12 * 该类重写
13 */
14 privateHttpServletRequest request;
15
16 private booleanhasEncode;
17
18 publicMyHttpServletRequest(HttpServletRequest request) {
19 super(request);//super必须写
20 this.request =request;
21 }
22
23 //对需要增强方法进行覆盖
24 @Override
25 publicMap getParameterMap() {
26 //先获得请求方式
27 String method =request.getMethod();
28 if (method.equalsIgnoreCase("post")) {
29 //post请求
30 try{
31 //处理post乱码
32 request.setCharacterEncoding("utf-8");
33 returnrequest.getParameterMap();
34 } catch(UnsupportedEncodingException e) {
35 e.printStackTrace();
36 }
37 } else if (method.equalsIgnoreCase("get")) {
38 //get请求
39 Map parameterMap =request.getParameterMap();
40 if (!hasEncode) { //确保get手动编码逻辑只运行一次
41 for(String parameterName : parameterMap.keySet()) {
42 String[] values =parameterMap.get(parameterName);
43 if (values != null) {
44 for (int i = 0; i < values.length; i++) {
45 try{
46 //处理get乱码
47 values[i] = newString(values[i]
48 .getBytes("ISO-8859-1"), "utf-8");
49 } catch(UnsupportedEncodingException e) {
50 e.printStackTrace();
51 }
52 }
53 }
54 }
55 hasEncode = true;
56 }
57 returnparameterMap;
58 }
59
60 return super.getParameterMap();
61 }
62
63 @Override
64 publicString getParameter(String name) {
65 Map parameterMap =getParameterMap();
66 String[] values =parameterMap.get(name);
67 if (values == null) {
68 return null;
69 }
70 return values[0]; //取回参数的第一个值
71 }
72
73 @Override
74 publicString[] getParameterValues(String name) {
75 Map parameterMap =getParameterMap();
76 String[] values =parameterMap.get(name);
77 returnvalues;
78 }
79
80 }
编写CharacterEnodingFilter
1 packagecom.oracle.bookshop.filter;
2
3 importjava.io.IOException;
4
5 importjavax.servlet.Filter;
6 importjavax.servlet.FilterChain;
7 importjavax.servlet.FilterConfig;
8 importjavax.servlet.ServletException;
9 importjavax.servlet.ServletRequest;
10 importjavax.servlet.ServletResponse;
11 importjavax.servlet.http.HttpServletRequest;
12
13 public class CharacterEnodingFilter implementsFilter{
14
15 @Override
16 public voiddestroy() {
17 //TODO Auto-generated method stub
18
19 }
20
21 @Override
22 public voiddoFilter(ServletRequest request, ServletResponse response,
23 FilterChain chain) throwsIOException, ServletException {
24 //TODO Auto-generated method stub
25 HttpServletRequest req =(HttpServletRequest)request;
26 MyHttpServletRequest myreq = newMyHttpServletRequest(req);
27 chain.doFilter(myreq, response);
28
29 }
30
31 @Override
32 public void init(FilterConfig arg0) throwsServletException {
33 //TODO Auto-generated method stub
34
35 }
36
37
38 }