大可制作:QQ群:31564239(asp|jsp|php|mysql)

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来处理。