过滤器Filter
一、过滤器是什么?有什么用?
过滤器是什么?
过滤器是一个可以对请求相应进行拦截的程序。
作用:
拦截一些信息,比如请求参数有相关不符合请求的。。。
二、过滤器的编码步骤
新建类,实现filter接口,会有三个为实现的方法,destroy,init,doFilter。在doFilter中编写逻辑。之后利用chain.doFilter(request,response)方法放行。
在xml中配置过滤器。
写个demo测试下:
Filter
public class FilterDemo1 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化了");
}
//针对过滤范围内的资源的每次访问都会执行该方法,由服务器调用
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("FilterDemo1执行前");
chain.doFilter(request, response);//放行。让下一个执行
System.out.println("FilterDemo1执行后");
}
public void destroy() {
System.out.println("销毁了");
}
}
再写一个Servlet
public class ServletDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("ServletDemo1执行了");
}
配置xml文件
<filter>
<filter-name>FilterDemo1</filter-name>
<filter-class>wsj.filter1.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<!-- 过滤器过滤资源 -->
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
打印输出:
总结:
你会发现在运行Servlet之前走了一遍过滤器,然后Servlet之后再次走了一遍过滤器。。注意:再次走过滤器是走了chain.doFilter(request, response);之后的代码。
三、过滤器的执行过程(生命周期)
生命周期
诞生:应用加载时(服务器开启时)就完成实例化,并由服务器调用init初始化方法。
走的Filter的init方法
活着:应用活着他就活着
死亡:应用被卸载时,就死亡,并由服务器调用destory方法。
走Destory方法:
在控制台输入指令:
然后代码就会走销毁方法:
四、串联过滤器
串联过滤器是指多个过滤器多个过滤器多某些资源进行过滤。编写多个过滤器,在xml文件中配置多个过滤器。执行顺序是先配置的过滤器先执行
写个demo2
public class FilterDemo2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("FilterDemo2执行前");
chain.doFilter(request, response);//放行。让下一个执行
System.out.println("FilterDemo2执行后");
}
整个过程:
五、过滤器的简单案例:
1解决全站中文乱码问题。除了GET请求方式
public class SetCharacterEncodingFilter implements Filter {
private FilterConfig filterConfig;//代表者过滤器的参数配置
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//参数不存在,返回null
String encoding = filterConfig.getInitParameter("encoding");
//给出默认编码
if(encoding == null){
encoding = "UTF-8";
}
request.setCharacterEncoding(encoding);//解决POST请求参数的中文编码
response.setCharacterEncoding(encoding);//更改输出字符流的编码
response.setContentType("text/html;charset="+encoding);//告知客户端使用字符编码
chain.doFilter(request, response);
}
public void destroy() {
}
}
xml配置
<filter>
<!-- POST请求和响应的编码过滤器 -->
<filter-name>SetCharacterEncodingFilter</filter-name>
<filter-class>com.itheima.filter.SetCharacterEncodingFilter</filter-class>
<!-- 过滤器参数配置 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SetCharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
分别控制html、css、js的静态资源的缓存时间
public class StaticResourcesNeedCacheFilter implements Filter {
private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
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");
}
long time = 0;//缓存时间的偏移量
//根据用户访问的资源,获取参数的值,从而设置缓存的时间
String uri = request.getRequestURI();//
String resourceType = uri.substring(uri.lastIndexOf(".")+1);// html
// if("html".equals(resourceType)){
// String value = filterConfig.getInitParameter("html");//得到配置的html的缓存时间,单位是小时
// time = Long.parseLong(value)*60*60*1000;
// }
//
// if("css".equals(resourceType)){
// String value = filterConfig.getInitParameter("css");//得到配置的html的缓存时间,单位是小时
// time = Long.parseLong(value)*60*60*1000;
// }
// if("js".equals(resourceType)){
// String value = filterConfig.getInitParameter("js");//得到配置的html的缓存时间,单位是小时
// time = Long.parseLong(value)*60*60*1000;
// }
String value = filterConfig.getInitParameter(resourceType);
if(value!=null){
time = Long.parseLong(value)*60*60*1000;
}
response.setDateHeader("Expires", System.currentTimeMillis()+time);
chain.doFilter(request, response);
}
public void destroy() {
}
}
xml配置
<!-- 控制静态资源的缓存时间 -->
<filter>
<filter-name>StaticResourcesNeedCacheFilter</filter-name>
<filter-class>com.itheima.filter.StaticResourcesNeedCacheFilter</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>StaticResourcesNeedCacheFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>StaticResourcesNeedCacheFilter</filter-name>
<url-pattern>*.js</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>StaticResourcesNeedCacheFilter</filter-name>
<url-pattern>*.css</url-pattern>
</filter-mapping>
不缓存
public class DynamicResourcesNoCacheFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
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");
}
response.setHeader("Expires", "-1");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
chain.doFilter(request, response);
}
public void destroy() {
}
}
xml配置
<!-- 控制动态资源不要缓存 -->
<filter>
<filter-name>DynamicResourcesNoCacheFilter</filter-name>
<filter-class>com.itheima.filter.DynamicResourcesNoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>DynamicResourcesNoCacheFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>DynamicResourcesNoCacheFilter</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
六、过滤器的高级配置
REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:
以上都会出现不会过滤的情况
设置方式:
<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
<!-- 如果一个dispatcher都不写:默认是REQUEST -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
Gzip压缩
1 import java.io.ByteArrayOutputStream;
2 import java.io.IOException;
3 import java.io.OutputStreamWriter;
4 import java.io.PrintWriter;
5 import java.util.zip.GZIPOutputStream;
6
7 import javax.servlet.Filter;
8 import javax.servlet.FilterChain;
9 import javax.servlet.FilterConfig;
10 import javax.servlet.ServletException;
11 import javax.servlet.ServletOutputStream;
12 import javax.servlet.ServletRequest;
13 import javax.servlet.ServletResponse;
14 import javax.servlet.http.HttpServletRequest;
15 import javax.servlet.http.HttpServletResponse;
16 import javax.servlet.http.HttpServletResponseWrapper;
17
18 public class GzipFilter implements Filter {
19
20 public void init(FilterConfig filterConfig) throws ServletException {
21
22 }
23
24 public void doFilter(ServletRequest req, ServletResponse resp,
25 FilterChain chain) throws IOException, ServletException {
26 HttpServletRequest request;
27 HttpServletResponse response;
28
29 try {
30 request = (HttpServletRequest) req;
31 response = (HttpServletResponse) resp;
32 } catch (ClassCastException e) {
33 throw new ServletException("non-HTTP request or response");
34 }
35
36 GzipHttpServletResponse mresponse = new GzipHttpServletResponse(response);
37 chain.doFilter(request, mresponse);
38 //在此处完成压缩
39 byte b[] =mresponse.getBytes();//得到原来要输出的数据是关键
40 System.out.println("数据原来大小:"+b.length);
41
42 ByteArrayOutputStream baos = new ByteArrayOutputStream();// 带有缓存的字节内存输出流
43 GZIPOutputStream gout = new GZIPOutputStream(baos);
44 gout.write(b);
45 gout.close();//数据用gzip压缩到了baos中
46
47 b = baos.toByteArray();//取出的压缩后的字节
48 System.out.println("数据压缩后的大小:"+b.length);
49
50 //告知客户端编码方式
51 response.setHeader("Content-Encoding", "gzip");
52 response.setContentLength(b.length);//告知正文的长度
53
54 ServletOutputStream sos = response.getOutputStream();
55 sos.write(b);
56
57 }
58
59 public void destroy() {
60
61 }
62
63 }
64 class GzipHttpServletResponse extends HttpServletResponseWrapper{
65 private ByteArrayOutputStream baos = new ByteArrayOutputStream();//临时仓库,存放截获的原始数据
66 private PrintWriter pw;
67 public GzipHttpServletResponse(HttpServletResponse response){
68 super(response);
69 }
70 //截获原来的数据:字节流
71 public ServletOutputStream getOutputStream() throws IOException {
72 return new MyServletOutputStream(baos);
73 }
74 //截获原来的数据:字符流
75 public PrintWriter getWriter() throws IOException {
76 pw = new PrintWriter(new OutputStreamWriter(baos, super.getCharacterEncoding()));//字符流--->字节流:查码表。
77 return pw;
78 }
79 //返回原始的数据
80 public byte[] getBytes(){
81 try {
82 if(pw!=null){
83 pw.close();
84 }
85 baos.flush();
86 } catch (IOException e) {
87 e.printStackTrace();
88 }
89 return baos.toByteArray();
90 }
91 }
92 class MyServletOutputStream extends ServletOutputStream{
93 private ByteArrayOutputStream baos;
94 public MyServletOutputStream(ByteArrayOutputStream baos){
95 this.baos = baos;
96 }
97 public void write(int b) throws IOException {
98 baos.write(b);
99 }
100
101 }
压缩结果: