From Gossip@caterpillar

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來處理。