ITEEDU

JSP/Servlet: 控制器(Servlet)

Model 2 架构将应用程序的 Web 层区分为 Controller、Model与View三个角色,使用JSP/Servlet技术,可以很适切的实现这个架构。
JSP/Servlet对于Model 2架构的实现对应分别为:

  • Servlet 实现 Controller 角色
  • JavaBean或其它自订值对象实现 Model 角色
  • 没有程序逻辑的 JSP 实现 View 角色

首先使用Servlet来实现一个简单的控制器,在这之前,您需要先了解 Command 模式。使用 Command 模式,可以使控制器的实现更具弹性,不过作为一个范例,这边仅实作出概念,因而接下来会简化一些实作内容。
首先,实作Command 模式中实际执行请求的对象,先定义一个IAction接口:

IAction.java
package onlyfun.caterpillar;

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

public interface IAction {
public void execute(HttpServletRequest req, 
HttpServletResponse res);
}

真正执行客户端请求的对象必须实作 IAction 接口,具体要实作的Action留在下一个主题,先来看看如何实现Command 模式中的Invoker类:

Invoker.java
package onlyfun.caterpillar;

import java.io.IOException;
import java.util.*;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Invoker {
private Map actions;

private String defaultPage;

public Invoker() {
actions = new HashMap();
}

public void addCommand(String actionName,
IAction action) {
actions.put(actionName, action);
}

public void request(HttpServletRequest req, 
HttpServletResponse res) 
throws ServletException, IOException {
IAction action = 
(IAction) actions.get(req.getServletPath());

if(action != null) {
action.execute(req, res);
}
else {
RequestDispatcher dispatcher = 
req.getRequestDispatcher(defaultPage);
dispatcher.forward(req, res);
}
}

public String getDefaultPage() {
return defaultPage;
}

public void setDefaultPage(String defaultPage) {
this.defaultPage = defaultPage;
}
}

这是一个很简单的控制转发类,这个类将根据客户端请求的Servlet路径来了解实际该调用的Action对象,如果找不到,则转发至预设的页面。

接下来在 Controller 中使用 Invoker 类,Controller 使用 Servlet 来实现:

DispatcherServlet
package onlyfun.caterpillar;

import java.io.*; 
import javax.servlet.*; 
import javax.servlet.http.*; 

public class DispatcherServlet extends HttpServlet {
private Invoker invoker;

public void init() throws ServletException {
invoker = new Invoker();
invoker.addCommand("/welcome.action", 
new WelcomeAction());
invoker.addCommand("/login.action", 
new LoginAction());
invoker.setDefaultPage("/welcome.action");
}
public void doPost(HttpServletRequest req, 
HttpServletResponse res) 
throws ServletException, IOException {
invoker.request(req, res);
}
public void doGet(HttpServletRequest req, 
HttpServletResponse res) 
throws ServletException, IOException {
doPost(req, res);
} 
} 

为了简化程序以方便说明,直接将可用的请求路径写在init()中,目前只有两个可用的请求路径,实际上设计时,这个部份该可以在属性档案中设定,以这个Model 2架构的程序更有弹性而可以重用。
这边实现Model 2架构的方式将采用前端控制器(Front Controller)模式,客户端所有的请求将透过上面这个DispatcherServlet,在web.xml中可以这么设定来达到目的:

web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 
version="2.4">
<description> 
Model 2 Example 
</description> 
<display-name>Model 2 Examples</display-name>
<servlet> 
<servlet-name>dispatcher</servlet-name> 
<servlet-class>
onlyfun.caterpillar.DispatcherServlet
</servlet-class> 
</servlet> 
<servlet-mapping> 
<servlet-name>dispatcher</servlet-name> 
<url-pattern>*.action</url-pattern> 
</servlet-mapping>
</web-app> 

按照这个web.xml的设定,所有以*.action结尾的请求都将由DispatcherServlet来处理。