我生待明日,万事成蹉跎

关于servlet规范中的几个设计模式解析(摘自刘江华老师博客)

本文属于入门类型文章,给大家简单介绍一下javax.servlet中用到的几个设计模式。

先看职责链模式

这个模式的应用就是大家所熟悉的filter过滤器,演示代码如下:

Filter.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.my.filter;

/**
 * 定义每一个处理者的通用行为,即对传入的参数进行处理
 * @author ljh
 *
 */
public interface Filter {

  public void doFilter(String param, FilterChain fc);

}

  接下来定义一个职责链接口,以规范形为(当然,这个接口也可以不定义,直接给出实现类即可)。

FilterChain.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.my.filter;

/**
 * 过滤器链接口定义
 * @author ljh
 *
 */
public interface FilterChain {

  /**
  * 将请求传给下一个处理者
  * @param param
  */
  public void doFilter(String param);

}

  一个具体的责任链实现(注:这个通常是由服务器去实现的,比如tomcat),里面包含了所有的要承担处理责任的处理者(也就是过滤器)。

ConcreteFilterChain.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.my.server;

import java.util.ArrayList;
import java.util.List;

import com.my.biz.Processor;
import com.my.filter.Filter;
import com.my.filter.FilterChain;
/**
 * 一个职责链具体实现
 * @author ljh
 *
 */
public class ConcreteFilterChain implements FilterChain {

  //链集合
  private List<Filter> filters = new ArrayList<Filter>();
  //初始已处理过滤器下标
  private int processIndex = -1;

  public ConcreteFilterChain(List<Filter> filters) {
      this.filters = filters;
  }

  @Override
  public void doFilter(String param) {
      //处理的过滤器下标
      processIndex = processIndex + 1;

      if (processIndex >= filters.size()) {
          Processor p = new Processor();
          p.working(param);
      } else {
          filters.get(processIndex).doFilter(param, this);
      }

  }

  /**
  * 返回一个新的FilterChain(这个方法保留待用)
  * 因为在多线程环境下,每一个请求会有自己的processIndex
  * 这个新建的processIndex将设置为初始值-1,表示还没有进入任何一个过滤器
  * @return
  */
  public FilterChain cloneFilterChain() {
      return new ConcreteFilterChain(filters);
  }

}

  好了,到这里,服务器上该做的事都已经做完,来看看程序员要做的事吧。我们先写一个业务处理类,模拟最终要进行的操作,如下:

Processor.java
1
2
3
4
5
6
7
8
9
10
package com.my.biz;

public class Processor {

  public void working(String param) {

      System.out.println("最后的业务执行与处理....:" + param);
  }

}

  在working处理消息前,我定义了两个过滤器。在第一个过滤器中,进行了参数检测,如果参数是”abc”,将终止后续业务的执行。同时,两个过滤器都对消息进行了处理,在消息中添加了自己的东西。

MyFilter1.java与MyFilter2.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.my.concretefilter;

import com.my.filter.Filter;
import com.my.filter.FilterChain;
/**
 * 第一个过滤器,会对消息进行处理
 * @author ljh
 *
 */
public class MyFilter1 implements Filter {

  @Override
  public void doFilter(String param, FilterChain fc) {

      System.out.println("进入MyFilter1的处理 ....");
      if ("abc".equals(param)) {
          System.out.println("发现参数是abc,终止执行!!!!");
          return;
      }
      fc.doFilter(param + "[●modify by MyFilter1●]");
      System.out.println("离开MyFilter1的处理 ....");

  }

}

/**
 * 第一个过滤器,会对消息进行处理
 * @author ljh
 *
 */
public class MyFilter2 implements Filter {

  @Override
  public void doFilter(String param, FilterChain fc) {

      System.out.println("进入MyFilter2的处理 ....");
      fc.doFilter(param + "[★modify by MyFilter2★]");
      System.out.println("离开MyFilter2的处理 ....");

  }

}

  接下来又是服务器上的处理代码了,我直接写出简单示例,生产环境中的服务器,肯定是读取web.xml反射创建过滤器对象。

Server.java
1
2
3
4
5
6
7
8
9
    //链集合(读取配置文件,反射创建filter,并加入过滤器链)
  List<Filter> filters = new ArrayList<Filter>();
  filters.add(new MyFilter1());
  filters.add(new MyFilter2());
  FilterChain fc = new ConcreteFilterChain(filters);

  //派发请求
  fc.doFilter("abcd");

  输出的结果是如下,和我们的预期相同。

Server.java
1
2
3
4
5
进入MyFilter1的处理 ....
进入MyFilter2的处理 ....
最后的业务执行与处理....:abcd[●modify by MyFilter1●][★modify by MyFilter2★]
离开MyFilter2的处理 ....
离开MyFilter1的处理 ....

  如果用户的输入参数是abc,即fc.doFilter(“abc”);,执行输出是:

Server.java
1
2
进入MyFilter1的处理 ....
发现参数是abc,终止执行!!!!

  这就有点类似于权限检测的filter一样,呵呵。

另一个是监听器(观察者模式)

通过监听器,容器会把我们感兴趣的事告诉我们,当然前提是我们必须先向服务器注册。监听器使用了观察者模式。下面我定义了一个会话监听器。

HttpSessionListener.java
1
2
3
4
5
6
7
8
9
10
11
12
package com.my.listener;
/**
 * 会话监听器
 * @author Administrator
 *
 */
public interface HttpSessionListener {

  public void sessionCreated(String  event);
  public void sessionDestroyed(String  event);

}

  接下来由程序员定义自己的监听器,并在配置文件中进行配置。

MyHttpSessionListener1.java和MyHttpSessionListener2.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.my.concretelistener;

import com.my.listener.HttpSessionListener;

/**
 * 我的会话监听器1
 * @author Administrator
 *
 */
public class MyHttpSessionListener1 implements HttpSessionListener {

  private String myName = "监听器1";

  @Override
  public void sessionCreated(String event) {

      System.out.println(myName + " 监听到创建事件:" + event);

  }

  @Override
  public void sessionDestroyed(String event) {

      System.out.println(myName + "监听到销毁事件:" + event);

  }

}

/**
 * 我的会话监听器2
 * @author Administrator
 *
 */
public class MyHttpSessionListener2 implements HttpSessionListener {

  private String myName = "监听器2";

  @Override
  public void sessionCreated(String event) {

      System.out.println(myName + " 监听到创建事件:" + event);

  }

  @Override
  public void sessionDestroyed(String event) {

      System.out.println(myName + "监听到销毁事件:" + event);

  }

}

  服务器上的处理代码如下:

Server.java
1
2
3
4
5
6
7
8
9
10
11
12
     //监听器对队
      HttpSessionListener[] listeners = new HttpSessionListener[2];
      listeners[0] = new MyHttpSessionListener1();
      listeners[1] = new MyHttpSessionListener2();

      //当容器中发生事件的时候,进行通知
      //比如:创建事件
      System.out.println("服务器发生创建事件!");
      for (HttpSessionListener listener : listeners) {
          listener.sessionCreated(new Date() + "创建事件发生了!" );
      }

  下面就是运行的结果,我们可以发现,这就是一个观察者模式的标准应用。

Server.java
1
2
3
服务器发生创建事件!
监听器1 监听到创建事件:Thu Jan 23 15:34:14 CST 2014创建事件发生了!
监听器2 监听到创建事件:Thu Jan 23 15:34:14 CST 2014创建事件发生了!

最后,给大家说一下包装器

包装器,也叫装饰器,这个模式的本意是在不改变原有类的情况下,增强类的功能(包括添加行为或添加状态)。

Request.java
1
2
3
4
5
6
7
8
9
10
11
package com.my.wrapper;
/**
 * 抽象请求对象
 * @author ljh
 *
 */
public interface Request {
  //得到内容
  public String getContent();

}
OriginalRequest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.my.wrapper;

/**
 * 原始请求
 * @author ljh
 *
 */
public class OriginalRequest implements Request {

  private String content;

  public OriginalRequest(String content) {
      this.content = content;
  }

  @Override
  public String getContent() {
      // TODO Auto-generated method stub
      return content;
  }

}
RequestWrapper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.my.wrapper;

/**
 * 包装对象,其它的包装类,都从这个类继承
 * @author ljh
 *
 */
public class RequestWrapper implements Request {

  private Request request;

  public RequestWrapper(Request request) {
      super();
      this.request = request;
  }

  @Override
  public String getContent() {
      //此处暂时不做任何处理,直接返回
      String content = request.getContent();
      return content;
  }

}

  上面三个类,都是由服务器端已经定义好的(也就是先把基本的架子搭起来)。下面这个方法才是我最终要执行的一个目标业务方法。

1
2
3
4
5
6
7
8
 /**
  * 此访求接收request接口类型,并感知不到对象已被包装
  * @param req
  */
  public static void display(Request req) {
      System.out.println(req.getContent());
  }

  接下来,大家看看我实现了一个对敏感关键词进行处理的包装器:

MyRequestWrapper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.my.concretewrapper;

import com.my.wrapper.Request;
import com.my.wrapper.RequestWrapper;

public class MyRequestWrapper extends RequestWrapper {

  public MyRequestWrapper(Request request) {
      super(request);
  }

  //添加行为或改变现在行为,或新的属性

  //比如:我下面进行敏感字符过滤
  @Override
  public String getContent() {
      String content = super.getContent();
      content = content.replaceAll("江泽民", "***");
      return content;
  }
}

  最后是对目标方法的调用了,输入结果是:我是国家主席***。

MyRequestWrapper.java
1
2
3
4
 Request req = new MyRequestWrapper(new OriginalRequest("我是国家主席江泽民"));
  //目标方法的调用
  display(req);
  

未经允许不得转载:徐宏涛博客 » 关于servlet规范中的几个设计模式解析(摘自刘江华老师博客)

分享到:更多 ()

评论 抢沙发

评论前必须登录!