- Filter简介
- 从功能角度来说,Filter能做什么?
- 从API角度来说,如何实现Filter?
- 从原理角度来说,Filter是如何实现拦截的?
- Filter生命周期和Filter链
- Filter生命周期的三个方法:init、doFilter和destory
- Filter链及其调用顺序
- Filter高级开发
- HttpServletRequestWrapper
- HttpServletResponseWrapper
- 动态代理
- Filter映射
- Filter案例
3、Filter高级开发
由于开发人员在filter中可以得到代表用户请求和响应的request、response对象,因此在编程中可以使用Decorator(装饰器)模式对request、response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求。
3.1、HttpServletRequestWrapper
HttpServletRequestWrapper类,全名是javax.servlet.http.HttpServletRequestWrapper,它是对HttpServletRequest的一种(装饰模式)实现,便于程序开发者进行扩展。
Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper , (HttpServletRequestWrapper 类实现了request 接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法)以避免用户在对request对象进行增强时需要实现request接口中的所有方法。
用装饰模式解决GET和POST请求编码的问题
CharacterEncodingFilter.java
package com.rk.filter; import java.io.IOException; import java.io.UnsupportedEncodingException; 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.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; public class CharacterEncodingFilter implements Filter { private FilterConfig filterConfig; @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) resp; } catch (Exception e) { throw new RuntimeException("non-http request or response"); } String encoding = this.filterConfig.getInitParameter("encoding"); if(encoding == null) encoding = "UTF-8"; request.setCharacterEncoding(encoding);//解决POST请求参数编码 response.setCharacterEncoding(encoding);//更改响应字符流使用的编码 response.setContentType("text/html;charset="+encoding);//更改响应字符流使用的编码,还能告知浏览器用什么格式进行显示 CharacterEncodingHttpServletRequest myRequest = new CharacterEncodingHttpServletRequest(request); chain.doFilter(myRequest, response); } @Override public void destroy() { } } /** * 使用“装饰模式”定义自己的处理GET请求中字符编码的问题 * @author lsieun * */ class CharacterEncodingHttpServletRequest extends HttpServletRequestWrapper { /** * 构造方法 */ public CharacterEncodingHttpServletRequest(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { String value = super.getParameter(name); if(value == null) return value; //如果是GET请求,则进行转码 if("GET".equalsIgnoreCase(super.getMethod())) { try { byte[] bytes = value.getBytes("ISO-8859-1"); value = new String(bytes,super.getCharacterEncoding()); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } return value; } }
web.xml中的配置
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.rk.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3.2、HttpServletResponseWrapper
HttpServletResponseWrapper类,全名是javax.servlet.http.HttpServletResponseWrapper,它是对HttpServletResponse的一种(装饰模式)实现,便于程序开发者进行扩展。
Servlet API 中提供了response对象的Decorator设计模式的默认实现类HttpServletResponseWrapper , (HttpServletResponseWrapper类实现了response接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 response对象的对应方法)以避免用户在对response对象进行增强时需要实现response接口中的所有方法。
用户装饰模式对响应的内容进行GZIP格式压缩
GZipFilter.java
package com.rk.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.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class GZipFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException { HttpServletRequest request; HttpServletResponse response; try { request = (HttpServletRequest) req; response = (HttpServletResponse) resp; } catch (Exception e) { throw new RuntimeException("non-http request or response"); } MyHttpServletResponse myResponse = new MyHttpServletResponse(response); chain.doFilter(request, myResponse); byte[] bytes = myResponse.getOldData();//获取原始数据是问题关键 System.out.println("压缩前:" + bytes.length); //GZIP压缩 ByteArrayOutputStream out = new ByteArrayOutputStream();//内存字节缓存输出流 GZIPOutputStream gzipOutputStream = new GZIPOutputStream(out); gzipOutputStream.write(bytes);//压缩后的数据写到了ByteArrayOutputStream中了 gzipOutputStream.close(); //取出压缩后的数据 bytes = out.toByteArray(); System.out.println("压缩后:" + bytes.length); //告知客户端正文的压缩方式:gzip response.setHeader("Content-Encoding", "gzip"); response.setContentLength(bytes.length);//响应消息头,告知客户端正文的长度 response.getOutputStream().write(bytes); } @Override public void destroy() { } } class MyHttpServletResponse extends HttpServletResponseWrapper { private ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); private PrintWriter printWriter = null; public MyHttpServletResponse(HttpServletResponse response) { super(response); } @Override public PrintWriter getWriter() throws IOException { printWriter = new PrintWriter(new OutputStreamWriter(outputStream,super.getCharacterEncoding())); return printWriter; } @Override public ServletOutputStream getOutputStream() throws IOException { return new MyServletOutputStream(outputStream); } public byte[] getOldData() { if(printWriter != null) { printWriter.close(); } try { outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } return outputStream.toByteArray(); } } class MyServletOutputStream extends ServletOutputStream { private ByteArrayOutputStream outputStream; public MyServletOutputStream(ByteArrayOutputStream outputStream) { this.outputStream = outputStream; } @Override public void write(int b) throws IOException { this.outputStream.write(b); } }
web.xml中的配置
<filter> <filter-name>GZipFilter</filter-name> <filter-class>com.rk.filter.GZipFilter</filter-class> </filter> <filter-mapping> <filter-name>GZipFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
相关类:
ByteArrayOutputStream类 全名:java.io.ByteArrayOutputStream (1)这是一个输出流(an output stream),可以将数据(data)转换成字节数组(a byte array)。 This class implements an output stream in which the data is written into a byte array. (2)它的缓冲区(buffer)随着数据(data)的写入而不断增长。 The buffer automatically grows as data is written to it. (3)可以通过toByteArray()或toString()方法得到数据(data)。 The data can be retrieved using toByteArray() and toString(). (4)对ByteArrayOutputStream进行关闭,是没有效果的。 Closing a ByteArrayOutputStream has no effect. The methods in this class can be called after the stream has been closed without generating an IOException.
GZIPOutputStream类 全名:java.util.zip.GZIPOutputStream This class implements a stream filter for writing compressed data in the GZIP file format.
3.3、动态代理
用动态代理解决GET和POST请求编码的问题
EncodingFilter.java
package com.rk.filter; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; 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; /** *编码处理统一写到EncodingFilter中(servlet中不需要再处理编码) */ public class EncodingFilter implements Filter { //1. 定义私有成员变量filterConfig private FilterConfig filterConfig = null; @Override public void init(FilterConfig filterConfig) throws ServletException { //2.在init方法中获取FilterConfig对象 this.filterConfig = filterConfig; } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException { //3. 从filter配置中获取encoding参数 String characterEncoding = filterConfig.getInitParameter("encoding"); if(characterEncoding == null) { characterEncoding = "UTF-8"; } final HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; final String encoding = characterEncoding; request.setCharacterEncoding(encoding);//解决POST请求参数编码 response.setCharacterEncoding(encoding);//更改响应字符流使用的编码 response.setContentType("text/html;charset=" + encoding);//更改响应字符流使用的编码,还能告知浏览器用什么格式进行显示 //4. 创建动态代理:处理GET请求参数的编码问题 HttpServletRequest proxy = (HttpServletRequest)Proxy.newProxyInstance( request.getClass().getClassLoader(), // 指定当前使用的类加载器 new Class[]{HttpServletRequest.class}, // 对目标对象实现的接口类型 new InvocationHandler() // 事件处理器 { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 定义方法返回值 Object result = null; // 获取方法名 String methodName = method.getName(); // 判断:对getParameter方法进行GET提交中文处理 if("getParameter".equals(methodName) && request.getMethod()=="GET") { String str = request.getParameter(args[0].toString()); if(str == null || str.equals("")) { result = str; } else { result = new String(str.getBytes("ISO8859-1"),encoding); } } else { result = method.invoke(request, args); } return result; } }); // 5.放行 (执行下一个过滤器或者servlet) chain.doFilter(proxy, response); // 传入代理对象 } @Override public void destroy() { } }
web.xml中的配置
<filter> <filter-name>EncodingFilter</filter-name> <filter-class>com.rk.filter.EncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3.4、Filter配置和映射
Filter配置
<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。 <filter-class>元素用于指定过滤器的完整的限定类名。 <init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。
Filter映射
<filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径 <filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字 <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式) <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。
<url-pattern>的一些示例:
1. 拦截所有 <url-pattern>/*</url-pattern> 2. 拦截jsp <!-- 拦截指定的jsp --> <url-pattern>/index.jsp</url-pattern> <url-pattern>/list.jsp</url-pattern> <!-- 拦截所有的jsp --> <url-pattern>*.jsp</url-pattern> 3. 拦截servlet <!-- 根据servlet的内部名称拦截 --> <servlet-name>IndexServlet</servlet-name> <!-- 拦截指定的servlet --> <url-pattern>/index</url-pattern> 4. 指定拦截指定的类型 <url-pattern>/*</url-pattern> <!-- 拦截直接访问的请求或者重定向的资源 --> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher>
<dispatcher> 子元素可以设置的值及其意义:
REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。 INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。 FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。 ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
4、Filter案例
4.1、根据Cookie自动登录
AutoLoginFilter.java
package com.rk.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.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import sun.misc.BASE64Decoder; /** * @author lsieun *用户自动登录的过滤器:这个过滤器,无论用户登录与否,都会放行;其重点是对带有用户登录信息的Cookie进行处理 * 1、如果用户已经登录(Session当中有用户记录),则不对Cookie进行处理 * 2、如果用户没有登录(Session当中没有用户记录) * 2.1、如果Cookie中含有用户登录信息,则进行登录 * 2.2、如果没有用户登录信息,则不进行处理 */ public class AutoLoginFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException { HttpServletRequest request; HttpServletResponse response; try{ request = (HttpServletRequest)req; response = (HttpServletResponse)resp; }catch(Exception e){ throw new RuntimeException("non-http request or response"); } //获取Session HttpSession session = request.getSession(); //如果在Session中找不到用户登录信息,则查找Cookie if(session.getAttribute("loginInfo") == null) { Cookie[] cookies = request.getCookies(); if(cookies != null) { for(Cookie cookie : cookies) { //如果Cookie中包含用户登录信息,则自动登录 if("loginInfo".equals(cookie.getName())) { String value = cookie.getValue(); BASE64Decoder base64 = new BASE64Decoder(); String username = new String(base64.decodeBuffer(value)); request.getSession().setAttribute("loginInfo", username);//将用户信息保存到Session中 break; } } } } chain.doFilter(request, response); } @Override public void destroy() { } }
web.xml中的配置
<filter> <filter-name>AutoLoginFilter</filter-name> <filter-class>com.rk.filter.AutoLoginFilter</filter-class> </filter> <filter-mapping> <filter-name>AutoLoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
LoginServelt.java
package com.rk.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import sun.misc.BASE64Encoder; public class LoginServelt extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); String username = request.getParameter("username"); String password = request.getParameter("password"); String uri = request.getParameter("uri"); if("小明".equals(username) && "123456".equals(password)) { request.getSession().setAttribute("loginInfo", username); //将用户名进行BASE64编码 BASE64Encoder base64 = new BASE64Encoder(); String base64Str = base64.encode(username.getBytes()); //生成Cookie,并保存到response当中 Cookie cookie = new Cookie("loginInfo", base64Str); cookie.setMaxAge(60 * 60); response.addCookie(cookie); //是否进行URL跳转 if(uri != null && !uri.equals("")) { response.sendRedirect(uri); } else { response.sendRedirect(request.getContextPath() + "/main.jsp"); } } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
4.2、判断用户是否登录
AuthenticationFilter.java
package com.rk.filter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; 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; import javax.servlet.http.HttpSession; /** * 登录的过滤器 * 1、如果用户访问的当前资源时不需要登录,则放行 * 2、如果用户访问的当前资源需要登录 * 2.1、如果当前用户已经登录,则放行 * 2.2、如果当前用户没有登录,则跳转至登录页面 * */ public class AuthenticationFilter implements Filter { private List<String> listOfUnfilterURI = null; @Override public void init(FilterConfig filterConfig) throws ServletException { //获取在web.xml中配置的无需登录的资源信息 String unfilterURI = filterConfig.getInitParameter("unfilteredURI"); listOfUnfilterURI = Arrays.asList(unfilterURI.split("\\|")) ; } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; boolean flag = false;//标识是否放行 //得到用户访问的URI String requestURI = request.getRequestURI(); //1、如果用户访问的当前资源时不需要登录,则放行 if(listOfUnfilterURI != null) { for(String str : listOfUnfilterURI) { if(requestURI.contains(request.getContextPath() + str)) { //如果当前资源不需要登录,则将flag设置为true flag = true; break; } } } //2、如果用户访问的当前资源需要登录 if(flag == false) { HttpSession session = request.getSession(false); //2.1、如果当前用户已经登录 if(session !=null && session.getAttribute("loginInfo")!=null) { flag = true; } //2.2、如果当前用户没有登录(此处不需要写代码,flag默认为false) } if(flag) { //放行 chain.doFilter(request, response); } else { //跳转至登录页面 request.setAttribute("uri", requestURI); request.getRequestDispatcher("login.jsp").forward(request, response); } } @Override public void destroy() { } }
web.xml中的配置
<filter> <filter-name>AuthenticationFilter</filter-name> <filter-class>com.rk.filter.AuthenticationFilter</filter-class> <init-param> <param-name>unfilteredURI</param-name> <param-value>/login.jsp|/login</param-value> </init-param> </filter>
4.3、对动态资源不进行缓存
DynamicResourceNoCacheFilter.java
package com.rk.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; /** * @author lsieun *控制动态资源不要缓存的过滤器 */ public class DynamicResourceNoCacheFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException { HttpServletRequest request = null; HttpServletResponse response = null; try { request = (HttpServletRequest) req; response = (HttpServletResponse) resp; } catch (Exception e) { throw new RuntimeException("non-http request or response"); } response.setDateHeader("Expires", -1); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); chain.doFilter(request, response); } @Override public void destroy() { } }
web.xml中的配置
<filter> <filter-name>DynamicResourceNoCacheFilter</filter-name> <filter-class>com.rk.filter.DynamicResourceNoCacheFilter</filter-class> </filter> <filter-mapping> <filter-name>DynamicResourceNoCacheFilter</filter-name> <url-pattern>*.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping> <filter-mapping> <filter-name>DynamicResourceNoCacheFilter</filter-name> <url-pattern>/servlet/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>
4.5、对静态资源进行缓存
StaticResourceCacheFilter.java
package com.rk.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; /** * @author lsieun *控制静态资源的缓存时间 */ public class StaticResourceCacheFilter implements Filter { private FilterConfig filterConfig; @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String requestURI = request.getRequestURI(); // 截取后缀名 String extensionName = requestURI.substring(requestURI.lastIndexOf(‘.‘)+1); String strTime = "0"; // 根据用户访问的资源类型,html css js的缓存时间都不同. if("html".equals(extensionName)) { strTime = this.filterConfig.getInitParameter("html"); } else if("css".equals(extensionName)) { strTime = this.filterConfig.getInitParameter("css"); } else if("js".equals(extensionName)) { strTime = this.filterConfig.getInitParameter("js"); } long time = Integer.parseInt(strTime) * 1000 * 60 * 60;// 缓存的时间(单位:毫秒) response.setDateHeader("Expires", System.currentTimeMillis() + time); chain.doFilter(request, response); } @Override public void destroy() { } }
web.xml中的配置
<filter> <filter-name>StaticResourceCacheFilter</filter-name> <filter-class>com.rk.filter.StaticResourceCacheFilter</filter-class> <init-param> <param-name>html</param-name> <param-value>1</param-value> </init-param> <init-param> <param-name>css</param-name> <param-value>2</param-value> </init-param> <init-param> <param-name>js</param-name> <param-value>3</param-value> </init-param> </filter> <filter-mapping> <filter-name>StaticResourceCacheFilter</filter-name> <url-pattern>*.html</url-pattern> </filter-mapping> <filter-mapping> <filter-name>StaticResourceCacheFilter</filter-name> <url-pattern>*.css</url-pattern> </filter-mapping> <filter-mapping> <filter-name>StaticResourceCacheFilter</filter-name> <url-pattern>*.js</url-pattern> </filter-mapping>
4.6、总结
在一次网络访问中,Tomcat会将请求和回应分别封装为request和response,而Filter能够起作用,正是对request和response中的信息加以利用。例如:
(1)用Filter解决字符乱码的问题,是对request和response中的字符编码进行设置;
(2)用Filter判断是否自动登录,是对request中Cookie信息进行处理;
(3)用Filter判断用户是否登录,是对request中Session进行处理;
(4)用Filter对动态资源(JSP、Servlet)不进行缓存,是对response的响应头进行处理;
(5)用Filter对静态资源(HTML、JS、CSS)进行缓存,也是对response的响应头进行处理;
(6)用Filter对响应内容进行GZIP压缩,是对response的响应体进行处理。
通过上述这几个经典应用,可以总结出:Filter只是利用request和response的信息进行预先或滞后处理,解决一些通用性的问题,并不会处理业务逻辑的内容。
在网络编程中,一般是先对request(输入)进行处理,再对response(输出)进行处理;当存在多个Filter的时候,也应该把处理request的Filter放在前面,处理response的Filter放在后面。
如果让我进行排序,我就这样排序:字符编码>自动登录>用户是否登录>动态资源不缓存>静态资源缓存>内容GZIP压缩。