再戰MVC(二)

MVC模式在J2EE技術中的應用

MVC模式並不能自動保證一個結構設計是正確的,如何在一個系統的設計中正確地使用MVC架構模式與系統使用的技術有密切的關系。2EE中有幾個核心的技術:JSP,JavaBean,Servlet,EJB,SessionBean,EntityBean構成了J2EE構架的基石,但是對于一個基于J2EE技術的Web應用來說,如何正確地使用MVC模式不是一句話就能得出結論的。

一般而言,一個J2EE系統應當適當地劃分接收請求,根據請求采取行動,並將結果顯示給用戶等責任。因此也就有了開發Web應用時經常提到的一個概念Model 1/Model 2,它是對采用JSP技術構成Web應用的不同模型的描述。

Model 1架構

<<Java與模式>>提到模型一又稱做以JSP爲中心(JSP Centric)的設計模型,它的架構圖如下圖所示:

王朝网络

從上圖可以看出來,JSP是整個應用系統的門戶。它身兼三職啊。1負責與客戶端的所有通信2處理所有的請求3處理所有的答複。在處理答複的時候,從數據庫中存取數據有兩種方式,可以它自己直接去存取,也可以讓一些JavaBean來完成。因爲JavaBean可以被放在一個請求上下文或者用戶會話中,這樣就可以在不同的JSP之間通信。當然這種模式在進行快速和需求不是很複雜,規模較小的 Web應用是有很大的優勢的,比如說:JSP頁面可以非常容易地結合業務邏輯(jsp:useBean)、服務端處理過程(jsp:scriplet)和HTML(<html>),在JSP頁面中同時實現顯示,業務邏輯和流程控制,從而可以快速地完成應用開發。

但是從工程化的角度考慮,它也有一些不足之處:把表現層和業務邏輯層柔和在一起,不利于以後的維護工作以及開發角色的分配,所以這種模式只能適合于小的系統開發。

Model 2架構

Servlet/JSP 規範的0.92版描述了在一個應用中使用servlet 和 JSP 的架構。在其後的規範中,Model 2 這個叫法消失了,但它已經在Java web 開發人員中非常通用了。 <<Java與模式>>提到模型二又稱做以Servlet爲中心(Servlet Centric)的設計模型, 它的架構圖如下圖所示:

王朝网络

對比這個圖跟Model 1的結構圖,從 JSP這個角度來看,JSP頁面至少少了二個任務即獲取跟處理用戶的請求,因爲Servlet相當于控制器(Controller)角色,它負責接收客戶端請求並處理此請求,將它傳遞給合適的JSP,而JSP則顯示給用戶。所以JSP頁面這時候主要做兩件事情: JavaBean直接與數據庫打交道取得數據後,JSP從JavaBean中讀取數據,這是第一,第二件事情就是把結果返回給客戶端。

根據Model 2,servlet 處理數據存取和導航流, JSP處理表現。Model 2 使Java 工程師和HTML設計者分別工作于它們所擅長和負責的部分。Model 2應用的一部分發生改變並不強求其他部分也跟著發生改變。HTML 開發人員可以改變程序的外觀和感覺,並不需要改變後端servlet的工作方式。

網上找到了一個很好的例子來說聲明:JSP能夠生成HTML,WML甚至XML,它對應于Web應用程序中的View部分。EJB作爲數據庫與應用程序的中介,提供了對數據的封裝。一般SessionBean封裝的是數據,EntityBean是封裝對數據的操作。這兩個部分合起來,對應于Web應用程序的Model部分。在技術上,JSP能夠直接對EJB進行存取,但這並不是好辦法,那樣會混淆程序中的顯示邏輯和控制邏輯,使得JSP的重用性能降低。這時候有兩種解決方法,通過JavaBean或者Servlet作爲中介的控制邏輯,對EJB所封裝的數據進行存取。這時,JavaBean或者Servlet對應于Web引用程序中的Controller部分。兩種類型的Controller各有其優缺點:JSP同Servlet的交互不容易規範化,使得交互的過程變得複雜,但是Servlet可以單獨同用戶交互,實際上JSP的運行時狀態就是Servlet;而由于JavaBean的規範性,JSP同JavaBean的交互很容易,利用JavaBean的get/set方法,JSP不需要過多的語句就可以完成數據的存取,這能夠讓JSP最大限度的集中在其視圖功能上,而且,在桌面應用程序中使用JavaBean也很容易,而用Servlet就相對麻煩許多。根據不同的問題背景,可以選取不同的Controller,有時候也可以兩者混合使用,或者直接在Servlet中調用JavaBean。

任何一種解決方案都是雙刃劍,在我們獲得的同時必須有一定的付出。這種模式也帶來了如下一些實際的問題:1. 必須基于MVC組件的方式重新思考和設計應用結構。原來通過建立一個簡單的JSP頁面就能實現的應用現在變成了多個步驟的設計和實現過程。 2.所有的頁面和組件必須在MVC框架中實現,所以必須進行附加地開發工作。

對于用原生的Servlet API來開發Model 2的程序的例子我將轉載JavaResearch論壇上的文章,研究下對MVC模式在J2EE系統中的應用有很大幫助的。

(轉載自“用實例學習MVC模式” nepalon 原作 )

下面以J2EE開發進行介紹。

Model層實現系統中的業務邏輯,通常可以用JavaBean或EJB來實現。

View層用于與用戶的交互,通常用JSP來實現。

Controller層是Model與View之間溝通的橋梁,它可以分派用戶的請求並選擇恰當的視圖以用于顯示,同時它也可以解釋用戶的輸入並將它們映射爲模型層可執行的操作。

現在來看一個例子,看MVC模式是怎樣工作的。

1.1.1一個實例

例1-a:

<servlet>

<servlet-name>Controller</servlet-name>

<servlet-class>nepalon.simplestruts.Controller</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>Controller</servlet-name>

<url-pattern>/simplestruts/servlet/control/Controller</url-pattern>

</servlet-mapping>

上面是web.xml文件的片段,在這裏定義了一個servlet用于處理請求。

例1-b(Test.jsp文件):

<html>

<%@ page contentType="text/html;charset=gb2312"%>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>實例首頁</title>

</head>

<body>

<table border="0" width="100%">

<tr>

<td><div align="center">

<a href="/simplestruts/servlet/control/Controller?command=showarticle">顯示文章</a>

</div></td>

</tr>

</table>

</body>

</html>

在這個JSP中,我們並沒有直接去調用JSP或JavaBean,而是把請求分送到Servlet中。下面,我們來看看Servlet的代碼。

例1-c:

package nepalon.simplestruts;

/**

* <p>Title: MVC framework</p>

* <p>Description: Controller<p>

* <p>Copyright: R2003</p>

* @author Nepalon

* @version 1.0

*/

import javax.servlet.*;

import javax.servlet.http.*;

import java.io.*;

import java.util.*;

public class Controller extends HttpServlet

{

public void init(ServletConfig config) throws ServletException

{

super.init(config);

}

public void destroy() {}

/** 用于處理HTTP的GET和POST請求的函數

* @param request servlet request

* @param response servlet response

*/

protected void processRequest(HttpServletRequest request,HttpServletResponse response)

throws ServletException, java.io.IOException

{

//代碼(1)通過if來實現對不同請求的分發

if(request.getParameter("command").equals("showarticle"))

{

ArticleCommand command = new ArticleCommand();

next = command. getAllArticle (request, response);

}

//代碼(2)

dispatch(request, response, next);

}

protected void doGet(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, java.io.IOException

{

processRequest(request, response);

}

protected void doPost(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, java.io.IOException

{

processRequest(request, response);

}

/** 一個實現了分發者模式的函數

* @param request servlet request

* @param response servlet response

*/

protected void dispatch(HttpServletRequest request,

HttpServletResponse response,

String page)

throws javax.servlet.ServletException, java.io.IOException

{

RequestDispatcher dispatcher =

getServletContext().getRequestDispatcher(page);

dispatcher.forward(request, response);

}

}

在Servlet中並沒有直接處理所提交的請求,而是把請求的處理推後到ArticleCommand類中,通過ArticleCommand對象來執行,如代碼(1)。在處理完請求後,轉到相應的頁面中,如代碼(2)。下面,我們看一下ArticleCommand類的代碼。

例1-d:

package nepalon.simplestruts;

/**

* <p>Title: MVC framework</p>

* <p>Description: 文章業務類<p>

* <p>Copyright: R2003</p>

* @author Nepalon

* @version 1.0

*/

import java.util.*;

import javax.servlet.*;

import java.io.*;

import java.lang.*;

import java.sql.*;

import javax.sql.*;

public class Contribute

{

public Contribute() {}

public String getAllArticle(HttpServletRequest request, HttpServletResponse response)

throws javax.servlet.ServletException, java.io.IOException

{

Connection conn=null;

String con_user = "example1";

String con_password = "example1";

String con_dburl = "jdbc:oracle:thin:@localhost:iasdb";

String con_driver = "oracle.jdbc.driver.OracleDriver";

PreparedStatement pstmt=null;

ResultSet rsComment=null;

Vector vectorComment = new Vector();

String selectSQL= "SELECT content, time FROM article ORDER BY time DESC";

try

{

DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

Class.forName(con_driver);

conn = DriverManager.getConnection(con_dburl,con_user,con_password);

pstmt=conn.prepareStatement(selectSQL);

rsComment=pstmt.executeQuery();

while(rsComment.next())

{

CommentItem commentItem = new CommentItem();

commentItem.setContent(rsComment.getString(1));

commentItem.setTime(rsComment.getDate(2));

vectorComment.add(commentItem);

}

vectorComment.trimToSize();

}

catch (Exception e){//做相應的處理}

//代碼(1)保存處理結果並返回跳轉頁面

request.setAttribute("vectorComment ", vectorComment);

return "/simplestruts/showallarticle.jsp";

}

……

public String getNewArticle(HttpServletRequest request, HttpServletResponse response)

throws javax.servlet.ServletException, java.io.IOException

{…}

}

在這個類中進行的是取得所有文章的業務,最後返回如果成功執行操作後要跳轉到的頁面。當然,這個類中可能還有別的業務的相應函數,讀者可自己實現。下面看一下要跳轉到的頁面的代碼。

例1-e(showallarticle.jsp文件):

<html>

<%@ page contentType="text/html;charset=gb2312"%>

<%@ page import="java.util.*, java.lang.*"%>

<jsp:useBean id="vectorComment" type="java.util.Vector" scope="request"/>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>顯示文章</title>

</head>

<body>

<table border="0" width="100%">

<tr>

<td>發表時間</td>

<td>文章內容</td>

</tr>

<%

if (vectorComment!=null && vectorComment.size()>0)

{

int counter=vectorComment.size();

CommentItem commentlist = null;

for (int i=0;i<counter;i++)

{

commentlist=null;

commentlist=(CommentItem)(vectorComment.get(i));

%>

<tr>

<td><%=commentlist.getCmTime()%></td>

<td><%=commentlist.getCmContent()%></td>

</tr>

<%

}

}

%>

</table>

</body>

</html>

在這個JSP中我們要做的只是取得結果並顯示,沒有涉及到相應的業務邏輯。

1.1.2實例分析

首先,我們看一下這個例子的序列圖

王朝网络

圖1.1.2-1

1) 首先在Veiw層的test.jsp中提交一個請求/simplestruts/servlet/control/Controller?command=showarticle;

2) 在Controller層的Controller對象中,根據請求的類型來調用相應的業務處理類,在這裏,command值爲showarticle的請求的業務處理類爲ArticleCommand類,所以調用該類的對象的相應函數;

3) 在Model層的ArticleCommand類主要實現請求的取得所有文章的業務功能,把結果保存在request中,並返回跳轉頁面作爲返回值;

4) 回到Controller層的Controller對象,根據上一步驟的返回值進行頁面轉發。

5) 轉發到View層的showallarticle.jsp頁面,這個頁面從request中取得結果並進行顯示。在這個JSP中雖然也有Java代碼,但這些代碼只是用于顯示結果,並沒有涉及到任何業務邏輯。

(轉載完查看原文)

MVC本身就是一個非常複雜的系統,所以采用MVC實現Web應用時,如果采用現成的MVC框架,在此之下進行開發,能夠達到事半功倍的效果。

MVC漸行漸進(二)
ActionRouter類 示例:/WEB-INF/classes/actions/ActionFactory.java package actions; import javax.servlet.GenericServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletReque...查看完整版>>MVC漸行漸進(二)
 
分層體系結構(MVC)二
二、EntityClassEntityClass中的每一個文件對應數據庫中的一張表,對應其字段,以及對表的操作的封裝,如查詢,增加、刪除等。所有的EntityClass繼承了一個基類BaseEntity,基類的代碼如下,主要是一些接口Imports S...查看完整版>>分層體系結構(MVC)二
 
分層體系結構(MVC)二
二、EntityClassEntityClass中的每一個文件對應數據庫中的一張表,對應其字段,以及對表的操作的封裝,如查詢,增加、刪除等。所有的EntityClass繼承了一個基類BaseEntity,基類的代碼如下,主要是一些接口Imports S...查看完整版>>分層體系結構(MVC)二
 
再戰MVC(-)
  前言  之所以說是再戰,是因爲在沒有學習設計模式之前已經基于MVC體系結構做過一些項目,主要是小項目,當初理解MVC有一些困難。現在已經把Gof所說的相對簡單但是最常見的這些設計模式: Abstract Factory ...查看完整版>>再戰MVC(-)
 
MVC 構架學習之漸行漸進(二)
  MVC:模型-視圖-控制器結構,這種構架在VC中我們可以體會得更深一些。在Java中實現這種構架的目的是實現網頁制作人員和開發人員的分工。然而這一知識點並不輕易把握,所需要讀者了解的知識點尤其是對servlet的理...查看完整版>>MVC 構架學習之漸行漸進(二)
 
MVC構架學習之漸行漸進(二)
  MVC:模型-視圖-控制器結構,這種構架在VC中我們可以體會得更深一些。在JAVA中實現這種構架的目的是實現網頁制作人員和開發人員的分工。然而這一知識點並不容易掌握,所需要讀者了解的知識點尤其是對servlet的理...查看完整版>>MVC構架學習之漸行漸進(二)
 
在ASP.NET中實現MVC模式(二)
在ASP.NET中實現Model-View-Controller模式(二) MVC模式形容這種實現方式是一種被動的實現機制,ASP.NET充當了程序執行中的控制器的角色,但程序員必須將具體的事件處理方法添加到事件的響應函數中。如在這個例子中...查看完整版>>在ASP.NET中實現MVC模式(二)
 
用PHP開始你的MVC(二)抽象數據庫接口
二、抽象數據庫接口(利用數據操作管理類)在用mvc模式開發的時候,model層負責數據庫的所有操作,爲了對數據庫的操作進行統一的管理,我們需要定義一個數據庫操作管理類,由他來接替所有的數據庫操作,也就是整個系統...查看完整版>>用PHP開始你的MVC(二)抽象數據庫接口
 
PHP.MVC的模板標簽系統(二)
PHP.MVC的模板標簽系統(二)
The php.MVC Tag Action Dispatcher TagActionDispatcher是一個標准的ActionDispatcher類的實現,它支持訪問基本模板標簽.TagActionDispatcher類支持相同的ActionObjects集合和ViewResourcesConfig屬性作爲默認的A...查看完整版>>PHP.MVC的模板標簽系統(二)
 
 
回到王朝網路移動版首頁