第七部分_深度剖析Filter

使用Servlet过滤器

  • 了解Servlet过滤器的概念:Servlet过滤器本身并不生成请求和响应对象,他只提供过滤作用,能够对Servlet容器的请求和响应对象进行检查和修改。能够在Servlet被调用之前检查Request对象,修改Request Header和Request内容;能够在Servlet被调用之后检查Response对象,修改Response Header和Response内容。Servlet过滤器负责过滤的Web组件可以使Servlet、JSP或者HTML文件。
  • 了解Servlet过滤器的工作过程
  • 掌握创建Servlet过滤器的方法:所有的Serlvet过滤器类都必须实现javax.servlet.Filter接口。这个接口含有3个过滤器类必须实现的方法:init()、doFilter()、destroy()
  • 掌握发布Servlet过滤器的方法

过滤器的例子:下面创建一个NoteFilter过滤器,它可以拒绝列在黑名单上的客户访问留言簿

首先是过滤器类NoteFilter:

package com.test.filter;

import java.io.IOException;
import java.io.PrintWriter;

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;

public class NoteFilter implements Filter
{
	private FilterConfig config = null;

	private String blackList = null;

	public void init(FilterConfig config) throws ServletException
	{
		this.config = config; // 保存为成员变量是为了在这个类的其他方法中使用,如doFilter方法
		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初始化时,它调用config.getInitParameter("blacklist")方法,从web.xml文件中读取初始化参数blacklist,这个参数表示被禁止访问留言簿的客户黑名单。
	如果客户不在黑名单中,NoteFilter的doFilter方法就会调用chain.doFilter()方法,这个方法用于调用过滤器链中后续过滤器的doFilter()方法。假如没用后续过滤器,那么就把客户请求传给相应的Web组件。
	在本例中,在调用chain.doFilter()方法前后记录了调用的时间,从而计算出Web组件响应客户所花的时间。
*/

接下来是NoteServlet:

package com.test.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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()
				+ "/NoteServlet 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()
	{
	}
}

最后再web.xml中进行相关的配置(注意:在web.xml文件中,必须先配置Servlet过滤器,再配置Servlet):

<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.test.filter.NoteFilter</filter-class>
<init-param>
<param-name>blacklist</param-name>
<param-value>hello</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/NoteServlet</url-pattern> <!-- 准备过滤的地址模式 -->
</filter-mapping>

输入姓名为hello或者hello123等等:

小练习

练习题1:在Servlet过滤器中能否访问application范围内的共享数据?

答案:可以的,先调用FilterConfig的getServletContext()方法获得ServletContext,再调用ServletContext的getAttribute()方法来获得application范围内的共享数据。

练习题2:Servlet过滤器只能对Servlet进行过滤,这句话是否正确?

答案:不正确。Servlet过滤器可以对Servlet、JSP和HTML文件过滤。

如:

<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/NoteServlet</url-pattern> <!-- 准备过滤的地址模式 -->
</filter-mapping>

更改为:

<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- 准备过滤的地址模式 -->
</filter-mapping>

表示过滤整个web应用下所有的内容。

最后,我们举一个例子说明过滤器在实际开发中的作用:

假设用户访问我们的web应用,首先需要登录,然后在登录之后用户可以通过地址栏的方式访问这个web应用下的其他页面,如果未登录用户通过地址栏访问这个页面需要跳转到登录页面,这样的话我们在每个页面中都需要写一个判断用户登录状态的逻辑,使得整个开发繁琐,此时,过滤器就派上了用场,我们只需要在过滤器中写一次判断,然后过滤应用下的所有页面即可。

时间: 2024-11-03 22:36:17

第七部分_深度剖析Filter的相关文章

libevent源码深度剖析七

libevent源码深度剖析七 --事件主循环张亮 现在我们已经初步了解了libevent的Reactor组件--event_base和事件管理框架,接下来就是libevent事件处理的中心部分 --事件主循环,根据系统提供的事件多路分发机制执行事件循环,对已注册的就绪事件,调用注册事件的回调函数来处理事件. 1 阶段性的胜利 Libevent将I/O事件.定时器和信号事件处理很好的结合到了一起,本节也会介绍libevent是如何做到这一点的.     在看完本节的内容后,读者应该会对Libev

java-反射深度剖析

Java反射是Java语言一个很重要的特征,简单剖析下反射的定义.原理.使用.性能及应用场景. (一)定义 程序运行时,允许改动程序结构或变量类型,这种语言称为动态语言.java不属于动态语言,但提供了RTTI(Run-time Type Identification)运行时类别识别.RTTI分为两种方式,一种是编译运行时已知悉类型,一种是反射机制. (二)原理 在<深入java虚拟机>中提到,java文件被编译成class文件,JVM类加载器加,载class字节码到方法区,然后在堆中生成Cl

libevent学习笔记(参考libevent深度剖析)

最近自学libevent事件驱动库,参考的资料为libevent2.2版本以及张亮提供的<Libevent源码深度剖析> libevent好处之类的就不赘述了,libevent和libiop,redis等一样都是采用事件回调机制,这种模式 被称作Reactor模式.正常事件处理流程是应用程序调用某个接口触发某个功能,而Reactor模式需要 我们将这些接口和宿主指针(谁调用这些接口)注册在Reactor,在合适的时机Reactor使用宿主指针 调用注册好的回调函数. 一: Reactor基本知

编程珠玑之关键字(1)--《c语言深度剖析》整理(转)

一.最快关键字register 关键字regiter请求编译器尽可能的将变量存在CPU的寄存器中.有几点注意的地方. 1.register变量必须是能被CPU寄存器所接受的类型,这通常意味着register变量必须是一个单个的值,并且其长度应小于或等于整型的长度. 但是,有些机器的寄存器也能存放浮点数. 2.register变量可能不存放在内存中,所以不能用取址符运算符“ & ”. 3.只有局部变量和形参可以作为register变量,全局变量不行. 4.静态变量不能定义为register.  总

Spark2.0从入门到精通:Scala编程、大数据开发、上百个实战案例、内核源码深度剖析视频教程

38套大数据,云计算,架构,数据分析师,Hadoop,Spark,Storm,Kafka,人工智能,机器学习,深度学习,项目实战视频教程 视频课程包含: 38套大数据和人工智能精品高级课包含:大数据,云计算,架构,数据挖掘实战,实时推荐系统实战,电视收视率项目实战,实时流统计项目实战,离线电商分析项目实战,Spark大型项目实战用户分析,智能客户系统项目实战,Linux基础,Hadoop,Spark,Storm,Docker,Mapreduce,Kafka,Flume,OpenStack,Hiv

[ 1011] &lt;&lt;C语言深度剖析&gt;&gt; 测试 TEST

/******************************** **  wzsts<C语言深度剖析>2016 ** **                    ** **     fun1~fun6代表6章节内容 ** **fun10~fun19代表fun1所调用函数 ** **                    ** **     世界因规则而美好     ** ** #if(1)可运行,#if(0)不运行. ** ** Data  Author   PC       ** **16

横瓜先生深度剖析QQ空间前端后端技术AJAX与FORM等等

[皇帝]北京-横瓜-7年(601069289)  22:06:34 [元帅]横瓜-PHP教父(601069289)  21:35:29 这里是QQ空间的图片上传方法 是FLASH 我草 [元帅]横瓜-PHP教父(601069289)  21:36:31 竟然不是JS QQ空间用FLASH 图片上传方法 [元帅]横瓜-PHP教父(601069289)  21:37:35 至此,整个QQ空间的技术,已经全部被我破解 @IT柏拉图 [元帅]IT柏拉图(2500875)  21:38:11 你真是天才,

【源码】StringBuilder和StringBuffer源码深度剖析

//------------------------------------------------------------------------ 写篇博客不容易,请尊重作者劳动成果.转载请注明出处:http://blog.csdn.net/chdjj //------------------------------------------------------------------------ 我觉得要通过源码研究一个类,应该先从整体上了解这个类,比如说这个类的继承体系,有哪些超类,继承

深度剖析WordPress主题结构(转)

利用强大的技术,可以把基于wordpress的网站做成各种各样的形式,这除了要求wordpress主题开发人员精通html,PHP,JS,CSS等技术,还需要开发者掌握WordPress主题的框架. Gevin今天结合The anatomy of a WordPress theme这篇文章,和大家一起剖析WordPress主题的结构.原文作者用图文形式,分别从网站外观.页面组成和后台文件三个方面,形象的向大家展示了WordPress的架构,下面Gevin和大家一起分析WordPress是如何架构