Author:相忠良
Email: ugoood@163.com
起始于:June 17, 2018
最后更新日期:June 18, 2018css
声明:本笔记依据传智播客方立勋老师 Java Web 的授课视频内容记录而成,中间加入了本身的理解。本笔记目的是强化本身学习所用。如有疏漏或不当之处,请在评论区指出。谢谢。
涉及的图片,文档写完后,一次性更新。html
创建 day19 web工程。java
Filter 简介:
Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员经过Filter技术,对web服务器管理的全部web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
Servlet API中提供了一个Filter接口,开发web应用时,若是编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。经过Filter技术,开发人员能够实现用户在访问某个目标资源以前,对访问的请求和响应进行拦截,以下所示:
web
入门例子:
需求:拦截index.jsp浏览器
1.创建cn.wk.web.filter.FilterDemo1
拦截器:缓存
public class FilterDemo1 implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("haha!!!"); chain.doFilter(request, response); // 放行 System.out.println("wowo!!!"); } public void init(FilterConfig filterconfig) throws ServletException {} public void destroy() {} }
2.在 web.xml 中配置拦截器:服务器
<filter> <filter-name>FilterDemo1</filter-name> <filter-class>cn.wk.web.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo1</filter-name> <url-pattern>/index.jsp</url-pattern> </filter-mapping>
3.index.jsp:app
<head> <title>Filter入门</title> </head> <body> <% System.out.println("index!!!"); %> </body>
控制台输出结果为:jsp
haha!!! index!!! wowo!!!
观察结果,了解到:
web 浏览器 -> web 服务器 -> filter -> index.jsp -> filter -> web 服务器 -> web 浏览器
post
filter在开发中的常见应用:
解决乱码问题:
弄一个filter拦截全部资源:
<filter> <filter-name>FilterDemo1</filter-name> <filter-class>cn.wk.web.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在FilterDemo1这个filter里写:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); chain.doFilter(request, response); // 放行 }
这样,全部资源全UTF-8编码,完全解决乱码问题。
Filter 链:
多个filter组成链,顺序由 web.xml 文件中 filter-mapping 的顺序来决定,以下:
filter-mapping 顺序为:
<filter-mapping> <filter-name>FilterDemo1</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>FilterDemo2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
结果为(即filter链里的filter顺序为先 filter1 后 filter2):
filterdemo1以前!!! filterdemo2以前!!! index!!! filterdemo2以后!!! filterdemo1以后!!!
Filter 的生命周期:
filter 的生命周期和 web 应用是同样的。
一个拦截器,服务器中只有1个拦截器对象。不一样拦截器有与之对应的不一样的拦截器对象。
注意到public void init(FilterConfig filterconfig) {}
中的FilterConfig
对象,这是初始化filter的一个对象。这个对象在web.xml中配置。当filter初始化时,web.xml中相应的配置会被自动读取。以下:
<filter> <filter-name>FilterDemo1</filter-name> <filter-class>cn.wk.web.filter.FilterDemo1</filter-class> <init-param> <param-name>xxx</param-name> <param-value>yyy</param-value> </init-param> </filter>
程序中输出初始化参数:
public void init(FilterConfig filterconfig) throws ServletException { String value = filterconfig.getInitParameter("xxx"); System.out.println(value); }
当服务器启动时,初始化该过滤器同时打印yyy
。有些内容不想在程序中固定,就可经过这种配置的方式设置。
有时咱们想在 doFilter 方法中使用初始化参数,作法是:
FilterDemo1
中定义成员变量private FilterConfig config;
String value = this.config.getInitParameter("xxx");
得到参数值。package cn.wk.web.filter.example; public class CharacterEncodingFilter implements Filter { private FilterConfig config; private String defaultCharset = "UTF-8"; // <- 默认 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { // 获取要设置的字符集 String charset = this.config.getInitParameter("charset"); if (charset == null) charset = defaultCharset; HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; request.setCharacterEncoding(charset); response.setCharacterEncoding(charset); response.setContentType("text/html;charset" + charset); chain.doFilter(request, response); } public void destroy() {} public void init(FilterConfig arg0) throws ServletException {} }
web.xml配置,还配置了初始化参数charset,以下:
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>cn.wk.web.filter.example.CharacterEncodingFilter</filter-class> <init-param> <param-name>charset</param-name> <!--charset 设置--> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
这样,该 web 应用之后不用再考虑乱码问题,且可在 web.xml 文件中的过滤器中灵活设置 charset。
常见应用2,故事:
因为 jsp 显示内容来源于 servlet,内容是动态的,因此缓存 jsp 文件没意义。因此,如今要作一个不缓存jsp文件的过滤器。
控制不缓存的过滤器:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 设定3头,不留缓存 response.setDateHeader("Expires", -1); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); chain.doFilter(request, response); }
web.xml中cache-mapping的配置:
<filter-mapping> <filter-name>NoCacheFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
常见应用3:控制浏览器缓存页面中的静态资源的过滤器
场景:有些动态页面中引用了一些图片或css文件以修饰页面效果,这些图片和css文件常常是不变化的,因此为减轻服务器的压力,可使用 filter 控制浏览器缓存这些文件,以提高服务器的性能。
灵活的过滤器:
<filter> <filter-name>CacheFilter</filter-name> <filter-class>cn.wk.web.filter.example.CacheFilter</filter-class> <init-param> <param-name>css</param-name> <param-value>10</param-value> <!--css 缓存10分钟--> </init-param> <init-param> <param-name>jpg</param-name> <param-value>1</param-value> <!--jpg 缓存1分钟--> </init-param> <init-param> <param-name>js</param-name> <param-value>20</param-value> <!--js 缓存1分钟--> </init-param> </filter> <!--同一个 filter,三种 mapping--> <filter-mapping> <filter-name>CacheFilter</filter-name> <url-pattern>*.jpg</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CacheFilter</filter-name> <url-pattern>*.css</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CacheFilter</filter-name> <url-pattern>*.js</url-pattern> </filter-mapping>
cn.wk.web.filter.example.CacheFilter
代码:
// 控制浏览器缓存的过滤器 public class CacheFilter implements Filter { private FilterConfig config; public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 1. 获取用户想访问的资源 String uri = request.getRequestURI(); // 2. 获取该资源的缓存时间 int expires = 0; if (uri.endsWith(".jpg")) { expires = Integer.parseInt(this.config.getInitParameter("jpg")); } else if (uri.endsWith(".js")) { expires = Integer.parseInt(this.config.getInitParameter("js")); } else { expires = Integer.parseInt(this.config.getInitParameter("css")); } response.setDateHeader("expires", System.currentTimeMillis() + expires * 60 * 1000); chain.doFilter(request, response); } public void init(FilterConfig filterconfig) throws ServletException { this.config = filterconfig; } public void destroy() {} }
略
<filter-mapping>
元素用于设置一个 Filter 所负责拦截的资源。
一个Filter拦截的资源可经过两种方式来指定:Servlet 名称 和 资源访问的请求路径。
<filter-name>
子元素用于设置filter的注册名称。该值必须是在<filter>
元素中声明过的过滤器的名字<url-pattern>
设置 filter 所拦截的请求路径(过滤器关联的URL样式)<servlet-name>
指定过滤器所拦截的Servlet名称。<dispatcher>
指定过滤器所拦截的资源被 Servlet 容器调用的方式,能够是 REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户能够设置多个
一个资源被调用的方式共有四种:REQUEST, INCLUDE, FORWARD 和 ERROR。
例子,如图:
上图中表示:servlet forward(request, response) 到一个jsp页面。此时,若作对jsp拦截器,控制缓存的话,就需在拦截器中设置<dispatcher>FORWARD</dispatcher>
,才能触发这个拦截器。
部署案例:
<filter-mapping> <filter-name>testFilter</filter-name> <url-pattern>/test.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>testFilter</filter-name> <url-pattern>/index.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>
下面代码解决了包括post和get请求在内的全部乱码问题。
HttpServletRequestWrapper
包装类,避免本身一个个覆盖不想加强的方法!注意:request.setCharacterEncoding("UTF-8");
只解决 post,不能解决 get 乱码问题。
本案例经过重写 getParameter() 方法,调整得到值得编码从 iso8859-1 到 request.getCharacterEncoding() 方法所指定的编码方式完成 get 请求方式下的乱码解决问题。
//真正解决全站乱码 public class CharacterEncodingFilter2 implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; request.setCharacterEncoding("UTF-8"); // 只解决 post,不能解决 get response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); chain.doFilter(new MyRequest(request), response); //request.getparameter("password"); } /* 1.写一个类,实现与被加强对象相同的接口 2.定义一个变量,记住被加强对象 3.定义一个构造方法,接收被加强对象 4.覆盖想加强的方法 5.对于不想加强的方法,直接调用被加强对象(目标对象)的方法 */ class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; public MyRequest(HttpServletRequest request) { super(request); this.request = request; } public String getParameter(String name) { String value = this.request.getParameter(name); if(!request.getMethod().equalsIgnoreCase("get")) {return value;} if(value==null){return null;} try { return value = new String(value.getBytes("iso8859-1"), request.getCharacterEncoding()); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e);}}} public void destroy() {} public void init(FilterConfig filterConfig) throws ServletException {} }
不要忘记在 web.xml 中配置这个过滤器,配置方法略。
之后再说。