赞
踩
Java Web之使用过滤器
write:2022-4-22
前文我们学习了JSP页面引用Java Bean:Java Web之JSP使用Java Bean,这节课我们学习Java Web的过滤器。
在实际应用中,每个web组件都需要检查客户请求的代码,如果每个web组件都编写请求的代码,显然重复编码降低开发效率和可维护性,为了解决这个问题,过滤器产生,过滤器是Servlet规范2.3才产生的技术。
过滤器能够对一部分客户请求进行预处理操作,然后再把请求转发给实际上对应的web组件,对于生成的响应结果,过滤器还能进行检查和修改,再把修改后的结果响应给客户。
过滤器是在Java Servlet规范2.3中定义的,它能够对客户请求和web组件生成的响应对象进行检查和修改(预处理)。
过滤器本身并不生成请求和响应对象,它只提供过滤作用。
过滤器能够在Web组件被调用之前检查Request对象,修改Request Header和Request内容;
在Web组件被调用之后检查Response对象,修改Response Header和Response内容。
过滤器可以为Servlet、JSP或HTML文件等Web组件提供过滤。
所有的过滤器类都必须实现javax.servlet.Filter接口。这个接口含有3个过滤器类必须实现的方法,三个方法分别在过滤器不同生命周期被调用:
init()
doFilter()
destroy()
(1)init(FilterConfig):这是过滤器的初始化方法,Servlet容器创建过滤器实例后将调用这个方法。在这个方法中可以读取web.xml 文件中过滤器的初始化参数
(2)doFilter(ServletRequest, ServletResponse,FilterChain):
这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain参数用于访问后续过滤器或者web组件;上面方法的三个参数是由Servlet容器传的
(3)destroy():Servlet容器在销毁过滤器实例前调用该方法,在这个方法中可以释放过滤器占用的资源
下面创建一个NoteFilter过滤器,它可以拒绝列在黑名单上的客户访问留言簿,而且能将Web组件响应客户请求所花的时间写入日志。
假定客户真正请求的web组件是NoteServlet,而NoteServlet前面有一个NoteFilter过滤器:
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class NoteFilter implements Filter { private FilterConfig config = null; private String blackList=null; public void init(FilterConfig config) throws ServletException { this.config = config; blackList=config.getInitParameter("blacklist"); } public void destroy() { config = null; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String username =((HttpServletRequest) request).getParameter("username"); if (username!=null )username=new String(username.getBytes("ISO-8859-1"),"GB2312"); if (username!=null && username.indexOf(blackList) != -1 ) { response.setContentType("text/html;charset=GB2312"); PrintWriter out = response.getWriter(); out.println("<html><head></head><body>"); out.println("<h1>对不起,"+username + ",你没有权限留言 </h1>"); out.println("</body></html>"); out.flush(); return; } long before = System.currentTimeMillis(); config.getServletContext().log("NoteFilter:before call chain.doFilter()"); chain.doFilter(request, response); config.getServletContext().log("NoteFilter:after call chain.doFilter()"); long after = System.currentTimeMillis(); String name = ""; if (request instanceof HttpServletRequest) { name = ((HttpServletRequest)request).getRequestURI(); } config.getServletContext().log("NoteFilter:"+name + ": " + (after - before) + "ms"); } }
代码流程分析:
当NoteFilter初始化时,调用init()方法,有一个FilterConfig参数,它包含了配置信息,而这些配置信息一开始存放在web.xml文件中,它调用config.getInitParameter(“blacklist”)方法,从web.xml文件中读取初始化参数blacklist,这个参数表示被禁止访问留言簿的客户黑名单。
在NoteFilter的doFilter()方法中首先从request对象中读取客户姓名,然后将客户姓名转换为中文字符编码。如果客户姓名中包含黑名单里的字符串,那么将直接向客户端返回一个拒绝网页。
由于在这种情况下没有调用chain.doFilter()方法,因此客户请求不会到达客户请求真正所访问的Web组件。
所以根据条件就有过滤器拒绝请求和转发请求两种情况:
假定姓名中包含“捣蛋鬼”字符串的客户将被禁止访问留言簿,并且留言簿由NoteServlet类来实现,当名叫“捣蛋鬼2000”的客户访问留言簿时,将被NoteFilter过滤器拒绝访问。返回结果:
当名叫“捣蛋鬼2000”的客户访问留言簿时NoteFilter的工作流程:
“捣蛋鬼2000”的客户请求的web组件是NoteServlet,但有NoteFilter过滤器在,根本没有到NoteServlet,返回结果的拒绝网页也是有NoteFilter生成的;
当不在黑名单中的客户请求访问,调用doFilter()方法,在此方法中,又会调用chain.doFilter()方法:
long before = System.currentTimeMillis();//调用chain.doFilter()方法前的时间
config.getServletContext().log(
"NoteFilter:before call chain.doFilter()");
chain.doFilter(request, response);//如果当前过滤器与后续过滤器有关联,就转发给后续过滤器,如果没有就把请求转发给后续的web组件
config.getServletContext().log(
"NoteFilter:after call chain.doFilter()");
long after = System.currentTimeMillis();//调用chain.doFilter()方法后的时间
String name = "";
if (request instanceof HttpServletRequest) {
name = ((HttpServletRequest)request).getRequestURI();
}
config.getServletContext().log("NoteFilter:"+name + ": " + (after - before) + "ms");//相减计算出NoteServlet响应客户请求所花的时间
当名叫“小精灵”的客户访问留言簿时,将被NoteFilter过滤器转发请求访问。返回结果:
计算调用chain.doFilter()方法之前和之后的时间:
当名叫“小精灵”的客户访问留言簿时NoteFilter的工作流程:
(1)发布过滤器时,必须在web.xml文件中加入< filter>元素和< filter-mapping>元素。< filter>元素用来定义过滤器,< filter-mapping>元素用于将过滤器和URL映射:
<filter-mapping>
<filter-name>NoteFilter</filter-name>
<url-pattern>/note</url-pattern>
</filter-mapping>
在上面的例子中:
<filter>
<filter-name>NoteFilter</filter-name>
<filter-class>mypack.NoteFilter</filter-class>
<init-param> //设置参数
<param-name>blacklist</param-name>
<param-value>捣蛋鬼</param-value>
</init-param>
</filter>
通过config.getInitParameter(“blacklist”)就可以得到参数值;
(2)< filter-mapping>元素用于将过滤器和URL映射,如果希望过滤器能为所有的URL过滤,那么可以把< url-pattern>的值设为“/* ”。这样,当客户请求访问Web应用中的任何一个Web组件时,Servlet容器都会先把请求交给过滤器处理;
(3)在web.xml文件中,必须先配置过滤器,再配置Servlet;
创建一个Servlet类NoteServlet,它实现一个简单的留言簿。它提供了一个表单,让客户输入姓名和留言,客户提交表单后,再将用户输入的信息显示在客户端的网页上。
NoteServlet.java:
import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class NoteServlet extends HttpServlet { private static final String CONTENT_TYPE = "text/html;charset=GB2312"; public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(CONTENT_TYPE); PrintWriter out = response.getWriter(); out.println("<html>"); out.println("<head><title>留言薄</title></head>"); out.println("<body>"); String username=request.getParameter("username"); String content=request.getParameter("content"); if(username!=null)username=new String(username.getBytes("ISO-8859-1"),"GB2312"); if(content!=null)content=new String(content.getBytes("ISO-8859-1"),"GB2312"); if(content!=null && !content.equals("")) out.println("<p>"+username+"的留言为:"+content+"</P>"); out.println(" <FORM action="+request.getContextPath()+"/note method=POST>"); out.println("<b>姓名:</b>"); out.println("<input type=text size=10 name=username ><br>"); out.println("<b>留言:</b><br>"); out.println("<textarea name=content rows=5 cols=20 wrap></textarea><br>"); out.println("<BR>"); out.println("<input type=submit value=提交>"); out.println("</form>"); out.println("</body></html>"); } public void destroy() { } }
NoteServlet的配置代码:
<servlet>
<servlet-name>NoteServlet</servlet-name>
<servlet-class>mypack.NoteServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>NoteServlet</servlet-name>
<url-pattern>/note</url-pattern>//映射路径与NoteFilter一致
</servlet-mapping>
访问NoteServlet:
http://localhost:8080/应用名/note(先处理NoteFilter再处理NoteServlet)
(1)串联过滤器的工作流程
过滤器1和过滤器2都为Servlet工作,先调用过滤器1再调用过滤器2
(2)配置串联的过滤器
因为是先调用过滤器1再调用过滤器2,所以先配置过滤器1再配置过滤器2
<filter> <filter-name>Filter1</filter-name> <filter-class>Filter1</filter-class> </filter> <filter-mapping> <filter-name>Filter1</filter-name> <url-pattern>/note</url-pattern> </filter-mapping> <filter> <filter-name>Filter2</filter-name> <filter-class>Filter2</filter-class> </filter> <filter-mapping> <filter-name>Filter2</filter-name> <url-pattern>/note</url-pattern> </filter-mapping>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。