Servlet之动作框架

参考: Java Servlet 技术简介

概述

动作框架,是指编写一个Servlet(请求入口),解析请求的URI得到动作名称,调用处理用户请求的动作类,完成请求访问。当动作执行完毕后,返回一个指向表示结果的JSP的URL(也可以用模板引擎)。
学习过MVC的同学可以在这里一一对应。Servlet通过调用ActionFactory起到路由的作用,处理用户的动作类即是Controller,Controller会调用Model完成任务处理,处理完毕后,返回的URI指向的JSP就是用于表示的View。

大致框架图如下:
框架图

详述

在这,会具体把实现动作框架所需部件的功能及构成详细叙述一遍,已达到每一部分都尽量清楚的目的。

Servlet

“唯一”的Servlet。所有请求的入口,继承自HttpServlet,解析出动作名称,然后通过动作工厂ActionFactory得到具体的动作对象,执行动作的perform方法,最后转发请求到返回的URL。
示例:

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
package com.example;

import java.io.IOException;
import javax.servlet.ServletException;

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

import com.example.actions.Action;

public class actionServlet extends HttpServlet {
private ActionFactory factory = ActionFactory.getSingleton();

// public void init(ServletConfig config) throws ServletException { ... }

public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// 获得动作的名称
String actionName = getActionName(req);
// 通过动作工厂生成actionName的实例对象
Action action = factory.create(actionName);
// 执行动作,得到返回的URL
String url = action.perform(req, res);
// 通过url显示结果
if (url != null)
getServletContext().getRequestDispatcher(url).forward(req, res);
}

// public void destroy() { ... }

private String getActionName(HttpServletRequest req) {
String path = req.getServletPath();
return path.substring(path.lastIndexOf('/')+1, path.lastIndexOf('.'));
}
}

ActionFactory

记录所有动作,通过Servlet发出的动作名称得到动作类,然后对该类实例化,并返回实例对象。
起到存储所有动作、查找指定动作的目的。
示例:

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
package com.example;

import com.example.actions.*;

import java.util.HashMap;
import java.util.Map;

public class ActionFactory {
private Map actionsMap = defaultMap();
private static ActionFactory singleton;

public static ActionFactory getSingleton() {
if (singleton == null)
singleton = new ActionFactory();
return singleton;
}

public Action create(String actionName) {
Class klass = (Class)map.get(actionName);
if (klass == null) {
throw new RuntimeException(getClass() + " was unable to find an action named '" + actionName + "'.");
}
Action actionInstance = null;
try {
actionInstance = (Action)kalss.newInstance();
} catch (Exception e) {
e.printStackTrace();
}

return actionInstance;
}

private Map defaultMap() {
Map map = new HashMap();

map.put("example1", example1Action.class);
map.put("example2", example2Action.class);
// ...

return map;
}

Action

动作类,继承Action接口,完成请求的各项动作。通过调用其他类来完成请求任务,并返回显示结果的jsp的URL。
Action接口

1
2
3
4
5
6
7
8
package com.example.actions;

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

public interface Action {
public String perform(HttpServletRequest request, HttpServletResponse response);
}

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.example.actions;

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

// import ...

public class exampleAction implements Action {
@Override
public String perform(HttpServletRequest req, HttpServletResponse res) {
// do something ...
return "/example.jsp"
}
}

web.xml

配置当某类url到达服务器时,执行哪个servlet。比如,在这里,我们把所有以.perform为后缀的url都用咱们前面创建的com.example.exampleServlet来处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>com.example.exampleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>*.perform</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>example</servlet-name>
<url-pattern>index.html</url-pattern>
</servlet-mapping>
</web-app>

体会

  • 通过动作框架,可以只编写一个的Servlet来总括系统的构建,这个Servlet为入口,解析url,通过ActionFactory得到动作,然后开始执行动作,最后返回显示结果,就完成了简单的请求访问。
  • 在构建过程中,要对动作的编写分门别类,以达到清晰明了、易于维护的目的。
  • 业务与逻辑不混合原则。专注于逻辑的实现,但不是用servlet来实现,而是用单纯的java来实现,servlet直接或间接的调用。

题外话

  • 文章开头的参考文章写的很好,有一个具体的Demo,请大家一定去看看。
  • 糙汉子,写的不好不对的地方还请您能够予以指正,感激。
  • 记得用IDE,刚开始想用Sublime来试一试,最后崩了。大神请无视。