Filter过滤器学习
一、Filter简介
Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,如下所示:
二、Filer是如何实现拦截的?
Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源进行拦截后,web服务器每次在调用web资源的service方法之前,都会先调用一下Filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
(1)、调用目标资源之前,让一段代码执行
(2)、是否调用目标资源(即是否让用户访问web资源)
web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
(3)、调用目标资源之后,让一段代码执行
三、Filter开发入门
Filter开发分为两个步骤:
(1)、编写java类实现filter接口,并实现其doFilter方法。
(2)、在 web.xml 文件中使用和元素对编写的filter类进行注册,并设置它所能拦截的资源
四、Filter链
(1)、在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。
(2)、web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。
五、Filter的生命周期
public void init(FilterConfig filterConfig) throws ServletException;//初始化
和我们编写的Servlet程序一样,Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(注:filter对象只会创建一次,init方法也只会执行一次。 )
开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;//拦截请求
这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法。FilterChain参数用于访问后续过滤器。
public void destroy();//销毁
在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。
六、FilterConfig接口
用户在配置filter时,可以使用为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过filterConfig对象的方法,就可获得:
String getFilterName():得到filter的名称。
String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
public ServletContext getServletContext():返回Servlet上下文对象的引用。
七、Filter的XML配置:
<!-- 演示: 拦截指定的请求 -->
<filter>
<filter-name>hello_filter2</filter-name>
<filter-class>cn.itcast.a_filter_hello.HelloFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>hello_filter2</filter-name>
<!-- 1. 拦截所有
<url-pattern>/*</url-pattern>
-->
<!-- 2. 拦截指定的jsp
<url-pattern>/index.jsp</url-pattern>
<url-pattern>/list.jsp</url-pattern>
-->
<!-- 拦截所有的jsp
<url-pattern>*.jsp</url-pattern>
-->
<!-- 3. 根据servlet的内部名称拦截
<servlet-name>IndexServlet</servlet-name>
-->
<!-- 拦截指定的servlet
<url-pattern>/index</url-pattern>
-->
<!-- 4. 指定拦截指定的类型 -->
<url-pattern>/*</url-pattern>
<!-- 拦截直接访问的请求或者重定向的资源 -->
<dispatcher>REQUEST</dispatcher>
<!--<dispatcher>FORWARD</dispatcher>-->
</filter-mapping>
代码演示:
第一个过滤器:
public class HelloFilter implements Filter {
//创建实例
public HelloFilter(){
System.out.println("1.创建过滤器实例");
}
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("2.执行过滤器初始化方法");
//获取过滤器在web.xml中的配置的初始化参数
String initParameter = filterConfig.getInitParameter("encoding");
System.out.println("encoding:"+initParameter);
//获取过滤器在web.xml中配置的初始化参数的名称
Enumeration initParameterNames = filterConfig.getInitParameterNames();
while(initParameterNames.hasMoreElements()){
String nextElement = (String)initParameterNames.nextElement();
String initParameter2 = filterConfig.getInitParameter(nextElement);
System.out.println(nextElement+":"+initParameter2);
}
}
// 过滤器业务处理方法:在请求到达Servlet之前先进入此方法处理公用的业务逻辑操作
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("3.执行过滤器业务处理方法");
//放行(去到Servlet)
//如果有下一个过滤器,进入下一个过滤器,否则就执行访问Servlet
chain.doFilter(request, response);
System.out.println("6.Servlet处理完成,又回到过滤器");
}
public void destroy() {
// TODO Auto-generated method stub
System.out.println("7.销毁过滤器实例");
}
}
第二个过滤器:
public class HelloFilter2 implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("4.第二个过滤器");
//放行
chain.doFilter(request, response);
System.out.println("5.第二个过滤器执行结束");
}
public void destroy() {
// TODO Auto-generated method stub
}
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
XML配置:
<!--Filter配置 -->
<filter>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>path</param-name>
<param-value>D:\Program Files (x86)</param-value>
</init-param>
<filter-name>HelloFilter.java</filter-name>
<filter-class>cn.chenkefo_01.HelloFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HelloFilter.java</filter-name>
<!-- 拦截所有资源 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>HelloFilter2.java</filter-name>
<filter-class>cn.chenkefo_01.HelloFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>HelloFilter2.java</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
运行结果:
1.创建过滤器实例
2.执行过滤器初始化方法
encoding:UTF-8
path:D:\Program Files (x86)
encoding:UTF-8
3.执行过滤器业务处理方法
4.第二个过滤器
5.第二个过滤器执行结束
6.Servlet处理完成,又回到过滤器
7.销毁过滤器实例
应用实例-编码统一处理:
public class EcodingFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
//转型
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//处理公用业务
//解决中文乱码现象(仅Post有效)
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
/**
* 出现get中文乱码,是因为在request.getParameter方法内部没有进行提交方式判断处理.
* 解决:对指定接口的某一个方法进行功能扩展,可以使用代理,
* 对request对象(目标对象),进行代理对象
*/
HttpServletRequest proxy = (HttpServletRequest) Proxy.newProxyInstance(
request.getClass().getClassLoader(), //指定当前使用的类加载器
new Class[]{HttpServletRequest.class}, //对目标对象实现的接口类型
new InvocationHandler() { //事件处理器
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//定义方法返回值
Object returnValue = null;
//获取方法名称
String methodName = method.getName();
//判断:对getParameter方法的get提交进行中文处理
if("getParameter".equals(methodName)){
//获取请求参数
String value = request.getParameter(args[0].toString());
//获取提交方式
String methodSubmit = request.getMethod();
//判断提交方式,若果是get提交,需要对数据进行处理(post提交以经处理过了)
if("GET".equals(methodSubmit)){
if(value!=null && !"".equals(value.trim())){
//处理get中文问题,先编码,在解码
returnValue = new String(value.getBytes("ISO8859-1"),"UTF-8");
}
}
}else{
returnValue = method.invoke(request, args);
}
return returnValue;
}
});
chain.doFilter(proxy, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("初始化完成");
}
public void destroy() {
// TODO Auto-generated method stub
}
}
过滤器配置:
<filter>
<filter-name>encoding</filter-name>
<filter-class>cn.chenkefo_01.EcodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
上一篇: 万物互联并非物联网精髓所在
下一篇: 车联网正从多角度颠覆传统汽车行业