专栏首页好好学java的技术栈重温java web过滤器filter

重温java web过滤器filter

1、Filter是什么?

Filter 技术是servlet 2.3 新增加的功能。Filter翻译过来的意思就是过滤器,能对客户端的消息进行预处理,然后将请求转发给其它的web组件,可以对ServletHttpRequest和ServletHttpResponse进行修改和检查。例如:在Filter中可以检查用户是否登录,对未登录的用户跳转到登陆界面。

2、过滤器快速入门

要定义一个过滤器,则需要实现javax.servlet.Filter接口,一个过滤器中包含了三个与生命周期相关的方法:

  • void init(FilterConfig config) 过滤器初始化时执行,FilterConfig 可以用来获取过滤器的初始化参数。
  • void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

过滤器过滤请求时执行,包含了request和response,chain用来是否执行下一步请求。

  • destroy() web容器(tomcat)停止时执行

第一步:创建DemoFilter.java

package cn.zq.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 DemoServlet implements Filter{	
	
        public void init(FilterConfig config) throws ServletException {
		System.out.println("DemoServlet.init...");
	}	public void doFilter(ServletRequest req, ServletResponse resp,			FilterChain chain) throws IOException, ServletException {		
        System.out.println("DemoServlet.doFilter...");
                System.out.println("this = " + this);
        }	
	public void destroy() {
		System.out.println("DemoServlet.destroy...");
	}
	

}

第二步:在web.xml文件中添加如下配置:

  <filter>
  	<filter-name>demo</filter-name>
  	<filter-class>cn.zq.filter.DemoServlet</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>demo</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

url-pattern配置为/*,表示过滤所有请求。

启动tomcat,可以看到如下输出:

说明Filter的init方法在web容器启动的时候执行,读者可以自行验证destroy()方法会在web容器停止时执行,访问主页:

在访问主页的时候浏览器是一片空白的,控制台输出上面的消息,Filter只会实例化一次,为什么我们访问不到我们要访问的内容呢?只需要在doFilter方法中加入如下的语句就可以了:

chain.doFilter(req, resp);

FilterChain(过滤器链)是用来干什么的呢?这个对象只包含一个void doFilter(ServletRequest request, ServletResponse response)方法,Filter调用此方法去调用下一个web组件(Filter,Servlet等),如果不调用此方法,那么下一个web组件不会被执行。

再放行之前,我们可以在Filter中设置响应头信息,如下:

        resp.setContentType("text/html;charset=UTF-8");
        chain.doFilter(req, resp);

过滤器的过滤过程如下:

过滤器中的各项配置:

  • 配置初始化参数:
 <filter>
  	<filter-name>demo</filter-name>
  	<filter-class>cn.zq.filter.DemoServlet</filter-class>
  	<init-param>
  		<param-name>encoding</param-name>
  		<param-value>UTF-8</param-value>
  	</init-param>
  	<init-param>
  		<param-name>name</param-name>
  		<param-value>RiccioZhang</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>demo</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

然后在init方法中获取:

public void init(FilterConfig config) throws ServletException {
		System.out.println("DemoServlet.init...");
		String encoding = config.getInitParameter("encoding");
		String name = config.getInitParameter("name");
		System.out.println("encoding="+encoding);
		System.out.println("name="+name);
	}
<filter>
  	<!-- filter的名字 -->
  	<filter-name>demo</filter-name>
  	<!-- 类名 -->
  	<filter-class>cn.zq.filter.DemoServlet</filter-class>
  </filter>
  <!-- 可以有多个 -->
  <filter-mapping>
  	<!-- 对哪个filter进行配置 -->
  	<filter-name>demo</filter-name>
  	<!--   		配置过滤的url,不能是/  		其他与servlet配置类似  	 -->
  	<url-pattern>/*</url-pattern>
  	<!-- 
  		根据名字配置对哪个servlet进行过滤
  	 -->
  	<servlet-name>DemoServlet</servlet-name>
  	<!-- 
  		ERROR: <error-page>过来的请求
  		FORWARD: 对转发过来的请求进行过滤,也就是对request.getRequestDispatcher(path).forward(request, response)
  		INCLUDE:对request.getRequestDispatcher(path).include(request, response)过来的请求进行过滤
  		REQUEST(默认): 对客户端的请求进行拦截
  		可以配置多个
  	 -->
  	<dispatcher>ERROR</dispatcher>
  </filter-mapping>

3、Filter的应用

为了便于编写Filter,本节的所有应用中提供了一个通过的Filter的实现:

package cn.zq.filter;
import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/** * 通用的Filter的实现 *
 @author zq 
 * 
 */
 
public abstract class GenericFilter implements Filter,FilterConfig, Serializable{	
	private static final long serialVersionUID = 5497978960987185665L;	
        private FilterConfig filterConfig;	
	/**
	 * 需要初始化,应该覆盖整个方法
	 */
	public void init(){}	
	public void init(FilterConfig filterConfig) throws ServletException {		this.filterConfig = filterConfig;
		init();
	}	

	abstract public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException;	
	
	public void destroy() {}

		
	public String getFilterName() {		
	    return getFilterConfig().getFilterName();
	}	

	public String getInitParameter(String name) {		

	    return getFilterConfig().getInitParameter(name);
	}	

	public Enumeration<String> getInitParameterNames() {		

	    return getFilterConfig().getInitParameterNames();
	}	

	public ServletContext getServletContext() {		
	    return getFilterConfig().getServletContext();
	}	
	public FilterConfig getFilterConfig() {		
	    return filterConfig;
	}
}
package cn.zq.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class HttpFilter extends GenericFilter{	

        private static final long serialVersionUID = 1029993995265394412L;	
        public void doFilter(ServletRequest request, ServletResponse response,			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;
		doFilter(req, resp, chain);
	}	
	protected abstract void doFilter(HttpServletRequest request, HttpServletResponse response,
			FilterChain chain) throws IOException, ServletException;
}

3.1、解决GET和POST获取参数的乱码问题

第一步:创建Filter

package cn.zq.filter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
/** 
* 处理字符编码的Filter 
* @author zq 
* 
*/

public class CharacterEncodingFilter extends HttpFilter{	
        private static final long serialVersionUID = -4329981031091311164L;	
	private String characterEncoding = "UTF-8";	
	public void init() {
		String ce = getInitParameter("characterEncoding");		if(ce != null && !ce.equals("")){
			characterEncoding = ce.toUpperCase();
		}
	}	
	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		request.setCharacterEncoding(characterEncoding);
		response.setContentType("text/html;charset="+characterEncoding);		
		//优化:只对GET请求的request进行包装
		if(request.getMethod().equals("GET")){
			request = new ParameterHandlerRequest(request);
		}
		chain.doFilter(request, response);
	}	
	private class ParameterHandlerRequest extends HttpServletRequestWrapper{		public ParameterHandlerRequest(HttpServletRequest request) {			super(request);
		}		
		public String getParameter(String name) {
			String value = super.getParameter(name);			return getString(value);
		}		
		private String getString(String value){			if(value != null){				try {
					value =  new String( value.getBytes("ISO-8859-1"), 
							getRequest().getCharacterEncoding() );
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}			return value;
		}		
		public String[] getParameterValues(String name) {
			String[] values = super.getParameterValues(name);			if(null != values){				for(int i = 0; i < values.length; i++){
					values[i] = getString(values[i]);
				}
			}			return values;
		}		
		public Map<String, String[]> getParameterMap() {
			Map<String, String[]> paramMap = super.getParameterMap();
			Iterator<String[]> it = paramMap.values().iterator();			while(it.hasNext()){
				String[] values = it.next();				if(null != values){					for(int i = 0; i < values.length; i++){
						values[i] = getString(values[i]);
					}
				}
			}			return paramMap;
		}
	}
}

第二步:编写配置文件

  <filter>
  	<filter-name>CharacterEncodingFilter</filter-name>
  	<filter-class>cn.zq.filter.CharacterEncodingFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>CharacterEncodingFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

这个过滤器应该配置在所有过滤器的前面

第三步:测试

package cn.zq.servlet;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DemoServlet extends HttpServlet {

    private static final long serialVersionUID = -4363281555738840730L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {

        doPost(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {
        System.out.println("--------"+request.getMethod()+"--------");
        System.out.println("request = " + request);
        System.out.println("name = " + request.getParameter("name"));
        
        String[] names = request.getParameterValues("name");
        if(names != null && names.length > 0){
            System.out.println("names[0] = " + names[0]);
        }
        Map<String, String[]> parameterMap = request.getParameterMap();
        for(Iterator<String> it = parameterMap.keySet().iterator();
                it.hasNext();){
            String key = it.next();
            String[] values = parameterMap.get(key);
            System.out.println(key+"="+values[0] );
        }
    }

}
 <servlet>
  	<servlet-name>DemoServlet</servlet-name>
  	<servlet-class>cn.zq.servlet.DemoServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>DemoServlet</servlet-name>
  	<url-pattern>/servlet/DemoServlet</url-pattern>
  </servlet-mapping>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
  </head>
  
  <body>
   <a href="<%=basePath%>servlet/DemoServlet?name=中国">Click</a>
   <form action="<%=basePath%>servlet/DemoServlet" method="post">
   		<input type="text" name="name"><br/>
   		<input type="submit"/>
   </form>
  </body></html>

访问并测试:

这个过滤器应该被配置在所有过滤器的前面,就能解决全站的乱码了,这样就不用重复的编写解决乱码问题的代码了。

3.2、设置所有的jsp页面不缓存

因为jsp页面的有些内容是动态生成的,所有混成jsp页面的意义不大,我们通常会设置这些jsp页面不缓存。

第一步:开发Filter

package cn.zq.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DynamicPageCacheFilter extends HttpFilter {	/**	 * 	 */
	private static final long serialVersionUID = -5449451659530735173L;	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {		
		//设置3个响应头
		response.setHeader("pragma", "no-cache");
		response.setHeader("cache-control", "no-cache");
		response.setDateHeader("expires", 0);
		chain.doFilter(request, response);
	}

}

第二步:配置web.xml

  <filter>
  	<filter-name>DynamicPageCacheFilter</filter-name>
  	<filter-class> cn.zq.filter.DynamicPageCacheFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>DynamicPageCacheFilter</filter-name>
  	<url-pattern>*.jsp</url-pattern>
  	<dispatcher>REQUEST</dispatcher>
  	<dispatcher>FORWARD</dispatcher>
  	<dispatcher>INCLUDE</dispatcher>
  </filter-mapping

第三步:打开ie,清空所有的缓存,cookie,访问本项目的jsp文件看是否有缓存文件,将Filter拿到,再访问看是否有缓存文件。

控制是否缓存,也可以在jsp页面中加入这几个头

<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">  

3.3、控制静态页面缓存(如html,图片)

第一步:编写Filter

package cn.zq.filter;
import java.io.IOException;
import java.util.Calendar;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class StaticContentCacheFilter extends HttpFilter{	/**	 * 	 */
	private static final long serialVersionUID = 7660878144738222823L;	@Override
	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {		/*
		 *让图片缓存一个月,html文件缓存一个星期 ,
		 *具体的相关信息可以通过配置文件来配置。
		 */
		String requestURI = request.getRequestURI();		long time = 0;		int day = 0;		if(requestURI.endsWith(".jpg")){
			day = 30;
		}else if(requestURI.endsWith(".html")){
			day = 7;
		}
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DATE, day);
		time = calendar.getTimeInMillis();
		response.setDateHeader("expires", time);
		chain.doFilter(request, response);
	}

}

第二步:配置

  <filter>
  	<filter-name>StaticContentCacheFilter</filter-name>
  	<filter-class>cn.zq.filter.StaticContentCacheFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>StaticContentCacheFilter</filter-name>
	<url-pattern>*.html</url-pattern>
	<url-pattern>*.jpg</url-pattern>  	
  </filter-mapping>

第三步:测试

请求资源,再次请求。查看状态码为304,及缓存文件的日期为N天以后。这是返回的状态码:HTTP/1.1 304 Not Modified

3.4 验证用户是否登录

第一步:开发filter

package cn.zq.filter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/** 
* 验证用户是否登录的过滤器 
* @author Riccio Zhang 
* 
*/

public class LoginFilter extends HttpFilter{	

	private static final long serialVersionUID = -6363929637537263967L;	

	protected void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		
		HttpSession session = request.getSession();
		Object user = session.getAttribute("user");		//没有找到user,则说明用户没有登录,转到登录页面让用户登录
		if(user == null){
			PrintWriter out = response.getWriter();
			out.print("<script>" +					  "alert('您还未登录!');" +					  "window.location.href='"+request.getContextPath()+"/login.jsp'" +					  "</script>");			return;
		}
		chain.doFilter(request, response);
	}

}

第二步:开发登录功能,配置web.xml

package cn.zq.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {	

	private static final long serialVersionUID = 3059445154848670189L;	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {		//让用户退出登录
		request.getSession().invalidate();
		response.sendRedirect(request.getContextPath() + "/login.jsp");
	}	

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {		/*
		 * 让用户登录成功
		 */
		String username = request.getParameter("username");		if(username == null || username.length() == 0){
			request.setAttribute("msg", "用户名不能为空!");
			request.getRequestDispatcher("/login.jsp").forward(request, response);			return;
		}
		request.getSession().setAttribute("user", username);		
		//重定向到主页
		response.sendRedirect(request.getContextPath() + "/page/index.jsp");
	}

}

登录页面:/login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>
  <head>
    <title>My JSP 'login.jsp' starting page</title>
    	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
  </head>
  
  <body>
  		<p style="color:red;font: 12px;">${requestScope.msg }</p>
    	<form action="<%=path%>/login" method="post">
    		username : <input type="text" name="username" ><br/>
    		<input type="submit" value="Sign in">
    	</form>
  </body></html>

登录成功跳转页面:/page/index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<!--
	<link rel="stylesheet" type="text/css" href="styles.css">
	-->
  </head>
  
  <body>
   
     欢迎你,<c:out value="${user }"></c:out><br/>
  <a href="<%=path%>/login">退出</a>
  </body></html>
 <!-- 对/page/*进行过滤 -->
  <filter>
  	<filter-name>LoginFilter</filter-name>
  	<filter-class>cn.zq.filter.LoginFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>LoginFilter</filter-name>
	<url-pattern>/page/*</url-pattern>  	
  </filter-mapping>
  <servlet-mapping>
  	<servlet-name>DemoServlet</servlet-name>
  	<url-pattern>/servlet/DemoServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
  </servlet-mapping>

第三步:测试,

在访问/page/index.jsp页面时,未登录是否会跳转到登录页面。登录时显示用户的名字。

3.5、自动登录

自动登录是为了让用户下次访问时,不用输入用户名和密码。将用户的信息保存到cookie中,下次直接从cookie中取。

第一步:开发登录页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>
  <head>
    <title>My JSP 'login.jsp' starting page</title>
    	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
  </head>
  
  <body>
		<c:choose>
			<c:when test="${empty user }">
				<p style="color:red;font: 12px;">${requestScope.msg }</p>
		    	<form action="<%=path%>/login" method="post">
		    		username : <input type="text" name="username" ><br/>
		    		<fieldset>
		    			<legend>自动登录</legend>
		    			<input type="radio" name="day" value="0">不自动登录<br/>
		    			<input type="radio" name="day" value="1">1天<br/>
		    			<input type="radio" name="day" value="7">一个星期<br/>
		    			<input type="radio" name="day" value="30">一个月<br/>
		    		</fieldset>
		    		<input type="submit" value="Sign in">
		    	</form>
			</c:when>
			<c:otherwise>
				欢迎您,<c:out value="${user }"></c:out><br/>
				<a href="<c:url value='/login' />">退出</a>
			</c:otherwise>
		</c:choose>
  </body></html>

第二步:开发登录servlet

package cn.zq.servlet;
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {	/**	 * 	 */
	private static final long serialVersionUID = 3059445154848670189L;	
        public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {		//让用户退出登录
		request.getSession().invalidate();		//删除cookie
		Cookie cookie = new Cookie("autoLogin", "");		
		/**
		 * 0表示删除文件和缓存
		 * -1表示删除文件,但是还有缓存
		 */
		cookie.setMaxAge(0);
		cookie.setPath("/");
		response.addCookie(cookie);
		response.sendRedirect(request.getContextPath() + "/login.jsp");
	}	
        
        public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {		/*
		 * 让用户登录成功
		 */
		String username = request.getParameter("username");		if(username == null || username.length() == 0){
			request.setAttribute("msg", "用户名不能为空!");
			request.getRequestDispatcher("/login.jsp").forward(request, response);			return;
		}		int day = 0;
		String auto = request.getParameter("day");		try {
			day = Integer.parseInt(auto);
		} catch (Exception e) {
			
		}		
		//对中文要进行编码
		Cookie cookie = new Cookie("autoLogin", URLEncoder.encode(username, request.getCharacterEncoding()));
		cookie.setMaxAge(day*24*3600);
		cookie.setPath("/");
		response.addCookie(cookie);
		
		request.getSession().setAttribute("user", username);
		
		
		response.sendRedirect(request.getContextPath() + "/page/index.jsp");
	}

}
  <servlet-mapping>
  	<servlet-name>DemoServlet</servlet-name>
  	<url-pattern>/servlet/DemoServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
  </servlet-mapping>

第三步:开发自动登录过滤器

package cn.zq.filter;
import java.io.IOException;
import java.net.URLDecoder;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class AutoLoginFilter extends HttpFilter{	

	private static final long serialVersionUID = 5891858915933022714L;	

	@Override
	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {		
		/*
		 * 优化:当用户手动登录或退出时,就不需要自动登录,
		 * 并且用户已经登录,也不需要自动登录,自动登录的代码是
		 * 多此一举
		 */
		HttpSession session = request.getSession();
		String requestURI = request.getRequestURI();
		Object user = session.getAttribute("user");		
		if(!requestURI.contains("/login") && user == null){			
			//获取cookie
			Cookie[] cookies = request.getCookies();			if(cookies != null){				for(Cookie c : cookies){					if("autoLogin".equals(c.getName())){
						String username = c.getValue();
						username = URLDecoder.decode(username, request.getCharacterEncoding());
						session.setAttribute("user", username);						break;
					}
				}
			}
		}
		
		chain.doFilter(request, response);
	}

}
  <filter>
  	<filter-name>AutoLoginFilter</filter-name>
  	<filter-class>cn.zq.filter.AutoLoginFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>AutoLoginFilter</filter-name>
	<url-pattern>/*</url-pattern>  
  </filter-mapping>

3.6、过滤非法语句(脏话)

在过滤器中,包装HttpServletRequest,修改getParameter方法

package cn.zq.filter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

public class DirtyWordsFilter extends HttpFilter{	

        private static final long serialVersionUID = -5025789414017693051L;	
        public void doFilter(HttpServletRequest request,			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		
		request = new MyHttpServletRequest(request);
		chain.doFilter(request, response);
	}

}

class MyHttpServletRequest extends HttpServletRequestWrapper{
	
	List<String> dirtyWords = Arrays.asList(new String[]{"SB", "sb", "傻B", "2B"});	
	public MyHttpServletRequest(HttpServletRequest request) {		
            super(request);
	}	
	public String getParameter(String name) {
		String value = super.getParameter(name);		if(value != null && value.length() > 0){			for(String dw : dirtyWords){
				value = value.replaceAll(dw, "***");
			}
		}		return value;
	}
}

3.7、全站压缩

实现对输出流的压缩:

在tomcat将数据输出到浏览器前,进行压缩,可以减少传送过去的数据,节约成本。如果在流量很少的情况下查看相同的内容和乐而不为呢?

思路:

  • 在调用request.getOutputStream()或request.getWriter()时获取自己的输出流,将数据写到事先准备的缓冲中。
  • 在输出完成后获取我们自己的缓冲数据
  • 然后在对缓冲的数据进行压缩,在过滤器中将数据传输给浏览器

第一步:编写压缩数据的过滤器

package cn.zq.filter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class GzipFilter extends HttpFilter{	

	private static final long serialVersionUID = 3410826595861585118L;	
	
	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		String ac = request.getHeader("Accept-Encoding");		//支持gzip压缩
		if(ac != null && ac.toLowerCase().indexOf("gzip") != -1){
			BufferedHttpServletResponse bRes = new BufferedHttpServletResponse(response);
			chain.doFilter(request, bRes);			
			byte[] data = bRes.getData();
			System.out.println("->压缩前数据大小:" + data.length);
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			GZIPOutputStream gout = new GZIPOutputStream(bos);
			gout.write(data);
			gout.close();			
			byte[] compressedData = bos.toByteArray();
			System.out.println("->压缩后的数据大小:"+compressedData.length);			
			//设置头信息
			response.setContentLength(compressedData.length);
			response.setHeader("Content-Encoding", "gzip");
			ServletOutputStream out = response.getOutputStream();
			out.write(compressedData);
			
		}else{
			chain.doFilter(request, response);
		}
		
	}
	
}
class BufferedHttpServletResponse extends HttpServletResponseWrapper{	
	private ByteArrayOutputStream buf = new ByteArrayOutputStream();	
        private PrintWriter pw;	

        public BufferedHttpServletResponse(HttpServletResponse response) {		

            super(response);
	}	
	public PrintWriter getWriter() throws IOException {
	    pw = new PrintWriter(				
            new OutputStreamWriter(buf, getResponse().getCharacterEncoding()));		return pw;
	}

            	
	public ServletOutputStream getOutputStream() throws IOException {
		ServletOutputStream sos = new ServletOutputStream() {			
			public void write(int b) throws IOException {
				buf.write(b);
			}
		};		return sos;
	}	

            	
	
	public byte[] getData(){		
	
	if(pw != null){
			pw.close();
		}		return buf.toByteArray();
	}
}

第二步:配置对所有的jsp进行压缩

   <filter>
       <filter-name>GzipFilter</filter-name>
       <filter-class>cn.zq.filter.GzipFilter</filter-class>
   </filter>
   <filter-mapping>
       <filter-name>GzipFilter</filter-name>
       <servlet-name>DemoServlet</servlet-name>
       <url-pattern>*.jsp</url-pattern>
   </filter-mapping>

第三步:测试压缩过滤器

使用压缩过滤器应该注意:应该只用这个压缩过滤器对文本进行压缩,例如jsp,html,css,js等进行压缩,对视频和图片的压缩率很低,不要用来压缩视频和图片,如果是下载,那也不应该用来压缩,这样不但压缩率很低,而且还有可能让服务器奔溃。

关于压缩过滤器的优化:

在doFilter方法中先将数据拿出来,然后放到GzipOutputStream中进行压缩,然后得到压缩后的字节再输出给客户端,这样2次都得到了字节,假如数据量较大,这2次都会占用较多的内存,能不能从包装的response拿出来时直接就是压缩过后的数据呢?改造后的代码如下:

package cn.zq.filter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class GzipFilter extends HttpFilter{	

	private static final long serialVersionUID = 3410826595861585118L;	
	
	public void doFilter(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		String ac = request.getHeader("Accept-Encoding");		//支持gzip压缩
		if(ac != null && ac.toLowerCase().indexOf("gzip") != -1){
			BufferedHttpServletResponse bRes = new BufferedHttpServletResponse(response);
			chain.doFilter(request, bRes);			
			byte[] compressedData = bRes.getData();			
			//设置头信息
			response.setContentLength(compressedData.length);
			response.setHeader("Content-Encoding", "gzip");
			ServletOutputStream out = response.getOutputStream();
			out.write(compressedData);
			
		}else{
			chain.doFilter(request, response);
		}
		
	}
	
}

	
class BufferedHttpServletResponse extends HttpServletResponseWrapper{	
	private ByteArrayOutputStream buf = new ByteArrayOutputStream();	
        private GZIPOutputStream gout;	

        private PrintWriter pw;	

        public BufferedHttpServletResponse(HttpServletResponse response) throws IOException {		super(response);
		gout = new GZIPOutputStream(buf);
	}	
	public PrintWriter getWriter() throws IOException {
	    pw = new PrintWriter(				
            new OutputStreamWriter(gout, getResponse().getCharacterEncoding()));		return pw;
	}	

        	public ServletOutputStream getOutputStream() throws IOException {
		ServletOutputStream sos = new ServletOutputStream() {			
			public void write(int b) throws IOException {
				gout.write(b);
			}
		};		return sos;
	}	

        	
	public byte[] getData() throws IOException{		if(pw != null){
			pw.close();
		}
		gout.close();		
	
	return buf.toByteArray();
	}
}

4.总结

利用Filter能对请求和响应进行预处理,在到达目标组件之前,对强求进行处理,诸如:对请求头和响应头进行处理。充分的利用了包装器设计模式,对request或response进行包装,对其方法进行增强。假如我们拒绝某个请求,就可以写一个过滤器对不希望的请求不放行,即不执行chain.doFilter(request, response)方法,过滤器能帮助我们干很多的事情。

作者:RiccioZhang
出处:https://blog.csdn.net/ricciozhang/article/details/43833401

觉得有用就转发分享一下吧

本文分享自微信公众号 - 好好学java(SIHAIloveJAVA)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-09-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • java监听器从入门到放弃?

    监听器就是实现一个特定接口的java程序,此程序专门用来监听另一个类方法的调用。java的awt大量的运用到了此种模式,例如可以给button对象添加一个点击事...

    好好学java
  • 简单的 CAS 实现 SSO 单点登录

    解压缩 cas-4.1.8.zip 并进入 cas-server-webapp 目录,在当前目录打开 cmd 并执行安装命令。

    好好学java
  • servlet就是这么简单

    Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库...

    好好学java
  • Struts1 增删改查

    本篇文章介绍如何使用Struts1进行增删改查,仅是对自己学习的记录,并没有深入分析每个模块(不重复造轮子O(∩_∩)O~)。

    Yano_nankai
  • 设计模式第七讲-责任链模式

    责任链模式的定义:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系

    用户2825413
  • 小朋友学C语言(43):浮点数的深入分析

    IEEE二进制浮点数算术标准(IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式...

    海天一树
  • shiro权限管理框架与springmvc整合

    shiro是apache下的一个项目,和spring security类似,用于用户权限的管理‘

    肖哥哥
  • 爬取网易,搜狐,凤凰和澎湃网站评论数据,正负面情感分析

    基于Scrapy框架的Python新闻爬虫,能够爬取网易,搜狐,凤凰和澎湃网站上的新闻,将标题,内容,评论,时间等内容整理并保存到本地。

    机器学习AI算法工程
  • 新零售时代,三十年国美不玩虚的,怎么玩儿?

    日前,在2017年世界电子商务大会上,国美CFO兼国美互联网CEO方巍发表了演讲,谈到国美的“新零售进化论,以及在后电商时代的新动能。”,强调了互联网技术对于国...

    罗超频道
  • 刚融资1亿美元的rokid要玩儿开放,凭什么跟百度等巨头PK?

    日前,外媒传来消息说:Amazon将全线下架包括Google Home、Nest系列产品在内的谷歌系智能家居硬件。Amazon在Echo大获成功后加速在智能家居...

    罗超频道

扫码关注云+社区

领取腾讯云代金券