转载

Http Servlet Request对象介绍

简介

Servlet规范中所引入的filter令人心动不已,因为它引入了一个功能强大的拦截模式。Filter是这样一种Java对象,它能在request到达servlet的服务方法之前拦截Http Servlet Request对象,而在服务方法转移控制后又能拦截HttpServletResponse对象。你可以使用filter来实现特定的任务,比如验证用户输入,以及压缩web内容。但你拟富有成效地使用过滤器的念头却被你不能改变Http Servlet Request对象的参数的现实扫了兴,因为java.util.Map所包装的Http Servlet Request对象的参数是不可改变的。这极大地缩减了filter的应用范围。至少在一半的时间里,你希望可以改变准备传送给filter的对象。如果在Http Servlet Request对象到达Struts的action servlet之前,我们可以通过一个filter将用户输入的多余空格去掉,难道不是更美妙吗?这样的话,你就不必等到在Struts的action表单验证方法中才进行这项工作了。

幸运的是,尽管你不能改变不变对象本身,但你却可以通过使用装饰模式来改变其状态。

装饰模式

在继承中,你可以通过继承一个父类并覆盖你希望改变的方法来改变对象状态。然而,如果这个对象是由程序的另一个子模块,例如对象工厂 (这里所说的工厂是工厂模式中的术语,下同。译者注) 或是servlet容器所产生的,继承就无能为力了。

装饰模式可用来增加一个现有对象的功能,或是改变其状态。与其使用继承方式来扩展此类,这个模式将一个对象包装成另外一个对象。装饰模式的UML类图。

Http Servlet Request对象介绍

装饰模式


Component是一个接口,其具体实现是ConcreteComponent。要改变Component的状态,你可以修改 ConcreteComponent或是扩展它 (通过继承或实现接口的方式,译者注)。然而,如果ConcreteComponent来自于一个工厂,你却无计可施。你所能做的,就是创建一个同为实现了Component接口的装饰类。这个装饰类的角色就由Decorator来扮演,在程序中通常表现为接口或抽象类。Decorator类的一个特性就是,它有一个接收Component对象的构造方法。你将拟装饰的对象传递给这个构造方法。在本例中,这个对象就是从工厂获得的 ConcreteComponent对象。通过将此装饰对象传递给Decorator的一个类变量,你可以访问Decorator中的任何方法。这就使你得以改变对象的状态了。

Decorator类不一定是接口或抽象类。如果你的程序不是很复杂,你可以将其转化为一个具体的Decorator类。

举个例子,考虑这样一个简单的消息传递程序,其主要部分是Messenger接口及其实现类MessengerImpl。让我们假设 MessengerImpl对象来自于一个工厂,因此你不能改变其状态。如果你准备增加或改变Messenger对象的功能,你可以创建一个 MessengerDecorator类。此例子的类图。

Http Servlet Request对象介绍

Messenger装饰类


我们来看程序的代码。给出了Messenger接口的代码,MessengerImpl类的代码。

Messenger接口

  1. public interface Messenger {   
  2. public String getMessage()  

MessengerImpl类

  1. public class MessengerImpl   
  2. implements Messenger {  
  3. private String message  
  4. public MessengerImpl(String message) {  
  5. this.message = message  
  6. }  
  7. public String getMessage() {  
  8. return message  
  9. }  

Messenger对象由一个名为MessengerFactory的工厂创建。

MessengerFactory类

  1. public class MessengerFactory {  
  2. public static Messenger getMessenger()  
  3. {  
  4. return new MessengerImpl("secrets")  
  5. }  

对每一个所创建的Messenger对象,此工厂通过某个未知的操作,初始化了getMessage()方法所返回的字符串。换句话说,你不能自己创建Messenger对象。

在程序中,Messenger对象的主要用途是被传递给一个名为Util的类中的broadcast()静态方法。

Util类

  1. public class Util {  
  2. public static void broadcast(Messenger messenger) {  
  3. System.out.print(messenger.getMessage());  
  4. }  
  5. // other methods here  

在你自己的类中,你可能会有这样的代码:

  1. Messenger messenger = MessengerFactory.getMessenger();  
  2. Util.broadcast(messenger); 

假设你希望对broadcast()方法所打印出的消息做一小改动。你拟将其转为大写,怎么做?表面上看,你可以继承Messenger,实例化其子类,并将返回的对象传给Util.broadcast()。但是,这种做法毫无意义,因为只有工厂才知道如何初始化Messenger对象,并通过其 getMessage()方法返回正确的值。

使用装饰模式,你可以创建一个MessengerDecorator类。

MessengerDecorator类

  1. public class MessengerDecorator implements Messenger {   
  2. private Messenger messenger;  
  3. public MessengerDecorator(Messenger messenger) {  
  4. this.messenger = messenger;  
  5. }  
  6. public String getMessage() {  
  7. return messenger.getMessage().toUpperCase();  
  8. }  

因为MessengerDecorator实现了Messenger,Util.broadcast()将接受一个MessengerDecorator 的实例。然而,MessengerDecorator不仅仅是一个接口的实现,它还是一个MessengerImpl对象的装饰器。正因如此,MessengerDecorator就必须有一个接收拟被装饰的Messenger对象的构造方法。

这个构造方法将参数传给变量。你现在可以覆盖MessengerDecorator中的getMessage()方法,以便将消息转为大写后再打印出来。因为你持有原来Messenger对象的引用,你可以这样写getMessage()方法:

  1. public String getMessage() {  
  2. return this.messenger.getMessage().toUpperCase()  

MessengerDecorator中的getMessage()方法返回原始消息的大写版本。

在你的类中,就像往常一样,你得到一个Messenger对象,并将Decorator传给Util.broadcast()。

Messenger messenger = factory.getMessenger();
Util.broadcast(new MessengerDecorator(messenger));

你并不将原始对象传给原先的目标,相反,你将其传给了该对象的装饰器。

应用装饰模式于Servlet

以上Messenger类的例子与servlet容器所构造的ServletRequest对象是一样的。当收到一个HTTP请求时,servlet容器就会创建ServletRequest对象及ServletResponse对象(分别是ServletRequestImpl及ServletResponseImpl的实例),并将这两个对象传递给特定的servlet服务方法。现在,如果你为ServletRequest创建一个装饰角色,并将其传给servlet服务方法,你就应用了装饰模式。

对ServletRequest很容易应用装饰模式,因为servlet API已经为其提供了一个包装类:ServletRequestWrapper。servlet装饰模式的类图。

Http Servlet Request对象介绍

Servlet API中的装饰模式


别为过多的类搞晕了头,只管注意虚线框中的三个类就行了:Http Servlet Request, Http Servlet RequestImpl, Http Servlet RequestWrapper。

Http Servlet Request对象介绍

Servlet API (HTTP)的装饰模式


情况与前面所举例子类似。你拥有一个ServletRequest的实现,而它是由servlet容器产生的。你可以使用所提供的ServletRequestWrapper来装饰这些ServletRequest对象。

这个模式很简单,在实际应用中可以派上用场。实际上,一些很有名的应用就使用了此模式。这些应用包括:

Struts - Struts是当前开发Java Web应用最受欢迎的基于MVC(模型-视图-控制)模式的框架。Struts提供了相当于ServletRequest 包装类的org.apache.struts.upload.MultipartRequestWrapper类。 MultipartRequestWrapper覆盖了getParameter(),getParameterNames(),及 getParameterValues()等方法来实现文件上传。

Apache Beehive ?C 这个源于BEA的WebLogic专题小组的开源项目,构建于Struts之上,并简化了web应用及web服务的开发。与ServletRequest包装类一样,org.apache.beehive.netui.pageflow.internal包中的PageFlowRequestW

正文到此结束
Loading...