点击上方“好好学java”,选择“置顶公众号”

优秀学习资源、干货第一时间送达!

精彩内容

java实战练习项目教程

2018微服务资源springboot、springcloud、docker、dubbo实战等倾心分享

2018年java架构师全套学习教程

最新大数据培训完整视频教程

2018年java最新全套培训学习教程

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;  @Overridepublic 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();     //删除cookieCookie 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; @Overridepublic 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){         //获取cookieCookie[] 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

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

1. java设计模式简单工厂模式

2. 一文读懂HttpServletRequest

3. 一文读懂HttpServletResponse

4. tomcat基本使用,就是这么简单

附上热门QQ群,存放资源和历史资料,2000容量(低门槛付费群),长按二维码入群

重温java web过滤器filter相关推荐

  1. java web压缩过滤器_Java Web过滤器Filter(五)

    Filter概述 Filter意为滤镜或者过滤器,用于在Servlet之外对request或者response进行修改.Filter提出滤镜链的概念,一个FilterChain包括多外Filter.客 ...

  2. Java Web过滤器(Filter)

    过滤器(Filter) 过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理 通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理 ...

  3. Java Web idea Filter配置(过滤器配置)

    一.过滤器的概述 1.1过滤器的概念及作用 概念 过滤器是一个能够拦截客户端与服务端请求和响应的web组件(Servlet.Filter.Listener). 2.画图分析 拦截请求:在请求到达客户端 ...

  4. java web过滤器

    java过滤器(imooc学习) 定义:过滤器是一个服务器端的组件,它可以截取用户端的请求与响应信息,并对这些信息过滤. 工作原理 1.过滤器中web容器启动时就进行加载 2.过滤器存在于用户请求和w ...

  5. JAVA incept_java 过滤器(Filter)与springMVC 拦截器(interceptor)的实现案例

    java 过滤器Filter: package com.sun.test.aircraft.filter; import javax.servlet.*; import java.io.IOExcep ...

  6. java web 过滤器 拦截器 监听器_Java中的拦截器和过滤器,可不是同一个东西

    过滤器(Filter) 过滤器就如上面的水质过滤器一样,把管道中的水进行一遍过滤再使用.过滤器基于filter接口中的doFilter回调函数,主要的用途是设置字符集.控制权限.控制转向.做一些业务逻 ...

  7. 详述 Java 中过滤器 Filter 的工作原理及使用方法

    1 简介 Filter 也称之为过滤器,它是 Servlet 技术中最激动人心的技术之一,WEB 开发人员通过 Filter 技术,对 web 服务器管理的所有 web 资源:例如 JSP.Servl ...

  8. 【java】过滤器filter的使用

    一.创建filter的实现类 代码实现 : package com.zzxtit.common.filter;import java.io.IOException;import javax.servl ...

  9. java web 自定义filter

    filter顾名思义,过滤器的意思,在javaweb中的Struts就利用了这种机制去实现视图和业务分离. 这里来配置下自己的Filter来理解下Struts的内在. 在web.xml 中添加下面: ...

最新文章

  1. 非京籍上学有多难?从这些数据看真相
  2. 轻松监听Azure service health 状态
  3. java实现缓存方式_【Java】【器篇】【缓存】一个轻量的缓存实现方式
  4. GDB调试多进程|多线程程序
  5. 求qt如何解决小数计算过程中的精度丢失
  6. swiper 上滑触发_新知 | 为何红酒杯壁挂“眼泪”,骑自行车不会倒,冰面那么滑?...
  7. Spring mvc 拦截静态资源配置管理
  8. git21天打卡-day8 本地分支push到远程服务器
  9. oracle4030,oracle ora-4030错误求解
  10. 霍夫丁不等式及其他相关不等式证明
  11. VAssistX 10.9 和 VS2010破解(win10环境)
  12. SQL基础系列(八)——排序、分组排序(RANK)
  13. centos解压分卷rar_linux命令:tar分卷压缩与合并解压缩
  14. 热点drcom 破解
  15. html广告sdk,腾讯社交联盟广告
  16. 全方位掌握 NSIS 的操作
  17. Babylon.js 深入
  18. SAPMM模块不同维度采购模式分类
  19. 重载函数是什么意思?
  20. 如何选择PMP、IPMP、CPMP?

热门文章

  1. SAP BDC 技术的分类(转)
  2. stm32 GPIO简单介绍及初始化配置(库函数)
  3. 数学建模_随机森林分类模型详解Python代码
  4. 深入解析 Kubebuilder:让编写 CRD 变得更简单
  5. [gic]-ARM gicv2和gicv3的中断模型总结
  6. DjangoRestFramework基本使用
  7. 【攻防世界007】simple-check-100
  8. TLS调试检测和反调试
  9. ncat 重复发送同一个文件
  10. vbs删除非空文件夹