j2ee|電子商務
摘要:本文以執行個體來詳細分析運用J2EE技術架構來搭建企業級電子商務網站的全過程,並對關鍵組件的實現以及相關技術進行具體剖析,同時結合筆者經驗,提出很多有價值的思路和方法。
一. 前言:
近年來,隨著互連網業務的迅猛發展,企業間、企業與消費者間實現電子商務已經成為可能,建立企業級的電子商務平台不僅可以拓寬企業的營銷渠道,而且對提升企業品牌形象等方面有重要的戰略意義。
本文將以目前國內最大服務交易平台如易網(http://www.routease.com/)為例,來深入剖析一個電子商務交易平台搭建的全過程。
《準備篇》
一個項目的實施首先確定項目目標、項目需求與開發環境(為方便理解,將如易網作為項目來描述)。本篇主要討論這三個方面:
一.實施目標
如易網的創辦目標:建設為國內最大的服務類交易平台和線上工作平台。由於本篇以技術講解為主,如要瞭解更多的背景資料,可以訪問:http://www.routease.com/AboutUs.htm 。
二.實施需求
目標決定需求,定製清晰明確的項目需求是整個項目成敗的關鍵。可以使用Rose工具來建立項目對象實體圖,這裡就不再贅述了,以下就幾個重要對象做一些描述:(可以對照http://www.routease.com/來瀏覽下面內容):
TotradeEntity:交易實體物件。該對象為核心對象,標識交易的服務物件。比如翻譯服務,開鎖服務等。
ServiceRequirement:服務需求對象。該對象標識使用者需求。比如需要電腦維修的資訊等。
SHOP:店鋪對象。該對象為中小企業或者個人開的網店,一個店鋪對應多個交易實體。
USER:使用者物件。該對象標識從事網站的合法註冊使用者,它保留使用者資訊。
Account:帳戶對象。該對象標識使用者的帳戶資訊。
Message:訊息對象。該對象標識使用者之間交流的資訊。
Credit:信譽對象。該對象標識使用者交易的信譽等級資訊,為交易提供有力參考。
三.開發/運行環境
基於以上需求分析,本站採用J2EE/Structs應用架構,伺服器主機採用WIN2003 SERVER+APACHE2.0.54+TOMCAT 5.5.4的系統內容,開發環境:Eclipse+JDK1.5,資料庫DAO採用的著名的ORM工具TopLink9.0.4.5。以下對相應開發技術及其工具做一個簡要介紹:
1. Structs技術
Web應用的開發經曆了一個由P2P(Page to Page)到MVC(model view controller)的發展過程。早期的Web應用對使用者請求的處理和響應均是在頁面上完成的,如圖1-1所示,即所的JSP1.0。這樣的Web架構最大的好處就是開發效率較高,然後近幾年隨著互連網的迅猛發展,網站功能日益增強,而這種P2P的網站架構(因為其商務規則代碼與頁面代碼混為一團,不利於維護)已經不再適應大規模應用的發展要求,取而代之的是基於MVC的Web架構。MVC的核心思想是將應用分為模型、視圖和控制器三部分。模型是指應用程式的資料,以及對這些資料的操作;視圖是指使用者介面;controller負責使用者介面和程式資料之間的同步,也就是完成兩個方向的動作:a.在根據使用者介面(view)的操作完成對程式資料(model)的更新,b.將程式資料(model)的改變及時反應到使用者介面(view)上。通過MVC的Web架構,可以弱化各個部分的耦合關係,並將商務邏輯處理與頁面以及資料分離開來,這樣當其中一個模組的代碼發生改變時,並不影響其他模組的正常運行,所以基於MVC的Web架構更適應於大規模軟體應用開發的潮流。
圖1
圖2
目前基於MVC的開發架構主要有Structs、Spring等。本站選用其中的Structs作為開發架構,採用Structs應用程式框架開發應用程式,將開發人員從繁瑣的代碼編製中解放出來,取而代之的是配置一些含有對應關係的XML檔案,這樣當應用環境發生變化時,不需重新編譯器即可運行,並且使得應用更加靈活、高效,而且重用度高。
從開發角度,Struts主要有如下的功能:
·包含一個controller servlet,能將使用者的請求發送到相應的Action對象。通過Web.xml檔案來配置其相關參數。
·tag庫,並且在controller servlet中提供關聯支援,協助開發人員建立互動式表單應用。
·通過配置Structs-config.xml檔案,將Action對象與使用者請求以及請求結果頁面關聯起來。
如需更多瞭解Structs的相關資訊,請其官方網站:http://jakarta.apache.org/struts
2.TopLink技術
過去,對模型資料的存取訪問往往是直接是應用通過ODBC這樣的資料庫介面訪問資料庫。但是這樣處理並不符合OOP的精神,而且應用開發人員必須熟悉後台資料庫的模型構造,這就加大開發的難度。為此,ORM(Object Relational Mapping)技術應運而生.ORM技術實際是一個對象持久化的架構,其核心思想是建立了Java對象與後台資料庫之間的映射關係。這樣對這些Java對象的訪問實際就是對後台資料庫的訪問,從而屏蔽了資料庫訪問的細節,開發人員甚至可以在不瞭解後台資料庫的情況下進行開發工作。此外,Toplink在資料緩衝最佳化上也有很好的表現。本項目採用著名的ORM工具Toplink進行開發。
《實施篇》
本篇主要介紹該平台的具體實現過程。根據軟體工程的相關理論,結合筆者多年的開發經驗,網站開發一般尊循以下六步驟:
1. 收集、整理網站需求。
2. 根據網站需求,構想網頁的互動情景(即USE CASE),並設計出網站的原形(Prototype)。
3. 設計出執行個體化對象以及後台資料庫結構。
4. 採用ORM工具,建立執行個體化對象與後台資料庫之間的映射關係。
5. 根據網站互動需求,定製後台Action,以處理使用者動作。
6. 修改網站原形(Prototype)為動態網頁面(JSP檔案),將Action處理結果嵌入到動態網頁面中返回給用戶端。
在這六個步驟中,第一步實際已經在《準備篇》裡已經給出了,下面重點講解後面幾個步驟。
1. 網站原形(Prototype)
網站原形是對一個網站功能的頁面級描述,即看到網站原形就好比看到一個真實的網站一樣,只是網站原形並沒有嵌入動態代碼,而且頁面之間也缺乏關聯而已。
網站原形的開發為純靜態頁面的開發,製作網站原形的關鍵在於將網站功能需求轉化為人機介面。
如易網的網站原形製作下載地址:http://www.routease.com/download/ruyinew924.rar
2. OOP設計與後台資料庫設計
藉助強大的ORM開發工具,可以將OOP與資料庫的設計同時進行(即可以同時實施上面步驟的3,4步),這也是ORM工具最大特點。本項目採用Oracle公司的Toplink作為ORM開發工具。以下簡要介紹Toplink開發過程。
1) 開啟Toplink的Mapping Workbench組件,然後建立一個Mapping 工程。
2) 配置工程的屬性,即在"選項"面板上設定工程路徑以及Java對象原始碼的路徑。
3) 設定資料庫登陸參數,包括應用訪問資料庫的URL、使用者名稱、密碼等。
完成以上三步,就可以根據應用的需求來開發Java類。在Mapping Workbench裡建立一個描述符(實際就是有一個Java類),根據需求來添加屬性,並自動產生Set/Get方法。一旦完成Java類的開發後,選擇"自動對應到資料庫"的選項,即可實現資料庫表的自動建立。(Toplink的最大優勢就是在定製好Java類之後可以自動產生資料庫的表結構)。
鑒於國內Toplink方面的資料較少,這裡介紹一下Toplink產生的工程檔案RouteaseMappingProject,該工程檔案在web伺服器啟動的時候裝載,可以理解為客戶程式對資料庫訪問的介面程式,他有三類方法:
·建構函式
主要是調用oracle.toplink.sessions.Project的addDescriptor方法,其作用是將資料庫和Java對象之間的映射關係加入到Project 中。代碼示範如下:
public RouteaseMappingProject() {
addDescriptor(buildAccountDescriptor());
addDescriptor(buildPhoneDescriptor());
…….
}
·applyLogin方法
它處理客戶程式登陸資料,並配置一些存取資料庫的參數,比如緩衝池等。代碼示範為:
public void applyLogin() {
//設定資料庫訪問參數
DatabaseLogin login = new DatabaseLogin();
login.usePlatform(new oracle.toplink.oraclespecific.Oracle9Platform());
login.setDriverClassName("oracle.jdbc.driver.OracleDriver"); login.setConnectionString(ApplicationConfiguration.get(ConfigurationConstants.DB_CON_STR)); login.setUserName(ApplicationConfiguration.get(ConfigurationConstants.DB_USER)); login.setPassword(ApplicationConfiguration.get(ConfigurationConstants.DB_ENCRYPTED_PASSWORD));
// 設定資料庫參數
login.setUsesNativeSequencing(true);
login.setSequencePreallocationSize(1);
login.setShouldBindAllParameters(false);
login.setShouldCacheAllStatements(false);
login.setUsesByteArrayBinding(true);
login.setUsesStringBinding(false);
if (login.shouldUseByteArrayBinding()) { // Can only be used with binding.
login.setUsesStreamsForBinding(false);
}
login.setShouldForceFieldNamesToUpperCase(false);
login.setShouldOptimizeDataConversion(true);
login.setShouldTrimStrings(true);
login.setUsesBatchWriting(false);
if (login.shouldUseBatchWriting()) { // Can only be used with batch writing.
login.setUsesJDBCBatchWriting(true);
}
login.setUsesExternalConnectionPooling(false);
login.setUsesExternalTransactionController(false);
setLogin(login);
}
·建立映射關係
Toplink通過類似於builXXXDescriptor方法來建立Java對象與資料庫表欄位之間的對應關係,示範代碼如下:
public Descriptor buildAccountDescriptor() {
Descriptor descriptor = new Descriptor();
descriptor.descriptorIsAggregate();
descriptor.setJavaClass(com.routease.db.vo.user.Account.class);
descriptor.setAlias("Account");
// Mappings.
//建立Account 對象的deposit屬性與資料庫表的DEPOSIT欄位的對應關係
DirectToFieldMapping depositMapping = new DirectToFieldMapping();
depositMapping.setAttributeName("deposit");
depositMapping.setFieldName("DEPOSIT");
descriptor.addMapping(depositMapping);
…
return descriptor;
}
3. 定製後台Action
根據MVC的精神,View和Model設計好之後應該是將開發重點轉移到控制器的開發上。控制器是根據使用者行為進行響應的處理模組,比如使用者通過首頁的搜尋條對服務資訊進行檢索,這時,web服務中的SearchToTradeEntityAction(對應SearchToTradeEntityAction.java檔案)會對使用者這一動作進行處理。以下對這一Action進行詳細分析:
package com.routease.action.totradeentity;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import com.routease.action.PagingAction;
import com.routease.action.helper.UserHelper;
import com.routease.db.dao.DataSource;
import com.routease.db.dao.totradeentity.SearchingCriteria;
import com.routease.db.dao.totradeentity.ToTradeEntityDAO;
import com.routease.db.util.Constants;
import com.routease.db.util.Page;
public class SearchToTradeEntityAction extends PagingAction {
public SearchToTradeEntityAction()
{
super();
}
// executeWithDataSource方法為該Action預設執行的方法
public ActionForward executeWithDataSource(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response, DataSource ds) throws Exception {
//首先接受使用者提交的表單資料
String objective = (String) PropertyUtils.getSimpleProperty(actionForm, "objective");
String keyWords = (String) PropertyUtils.getSimpleProperty(actionForm, "keyWords");
String keyWordsRange = (String) PropertyUtils.getSimpleProperty(actionForm, "keyWordsRange");
if (StringUtils.isEmpty(keyWordsRange)) {
keyWordsRange = SearchingCriteria.KEY_WORDS_RANGE_NAME;
}
String industryLevel1 = (String) PropertyUtils.getSimpleProperty(actionForm, "industryLevel1");
String industryLevel2 = (String) PropertyUtils.getSimpleProperty(actionForm, "industryLevel2");
String startingPrice = (String) PropertyUtils.getSimpleProperty(actionForm, "startingPrice");
String endingPrice = (String) PropertyUtils.getSimpleProperty(actionForm, "endingPrice");
String city = (String) PropertyUtils.getSimpleProperty(actionForm, "city");
String province = (String) PropertyUtils.getSimpleProperty(actionForm, "province");
String startNoStr = (String) PropertyUtils.getSimpleProperty(actionForm, "startNumber");
String lengthStr = (String) PropertyUtils.getSimpleProperty(actionForm, "length");
if (StringUtils.isEmpty(startNoStr)) {
startNoStr = "1";
}
//根據使用者提交的資料,建立查詢運算式對象SC
int startNumber = Integer.parseInt(startNoStr);
int length = UserHelper.getPagingLength(ds, request);
ToTradeEntityDAO serviceDAO = new ToTradeEntityDAO(ds);
SearchingCriteria sc = new SearchingCriteria();
sc.setCity(city);
sc.setProvince(province);
sc.setEndingPrice(endingPrice);
sc.setIndustryLevel1(industryLevel1);
sc.setIndustryLevel2(industryLevel2);
sc.setKeyWords(keyWords);
sc.setKeyWordsRange(keyWordsRange);
sc.setObjective(objective);
sc.setStartingPrice(startingPrice);
if (Constants.IS_TEST) {
System.out.println("start of page:" + startNumber);
}
//提交查詢對象SC,並獲得查詢結果集,將其結果集放入Request對象中,便於返回
Page result = serviceDAO.searchToTradeEntities(sc, startNumber, length);
Collection industries = serviceDAO.findIndustryDistribution(sc);
result.setSizePerPage(length);
request.setAttribute(Constants.TO_TRADE_ENTITY, result);
request.setAttribute("MY_INDUSTRIES",industries);
request.setAttribute("MY_PAGE", result);
//商務邏輯處理完畢之後,返回成功頁面
return actionMapping.findForward("SUCCESS_PAGE");
}
}
SearchToTradeEntityAction是一個典型的Action,由前面註解不難看出,一般Action分為三部分:
a. 接受使用者表單資料
b. 處理使用者表單資料
c. 返回處理結果及頁面
4. 修改頁面為JSP檔案
凡是涉及到與使用者狀態相關的頁面均應改造為動態網頁面(JSP檔案),改造是在前面靜態檔案的基礎上進行的,用伺服器端返回的資料(存放在Request對象裡)替換靜態文本,由於這部分相對技術性不強,所以不再詳細贅述了。
通過前面四部分的介紹,基本概述了如易網技術實施的主要過程,在下面的一章裡介紹網站技術中的幾個重要技巧。
《完結篇》
本篇主要介紹網站實施過程中的幾個重要技巧和思路,最後還將介紹網站維護方面的內容。
一. 加快網站速度
盡量以靜態html檔案為主,由於靜態檔案不需要WEB伺服器解析而直接返回給用戶端,所以速度更快。
對網站即時性不強的動態檔案可以採用後台定期重新整理的機制來轉化為靜態檔案或者js檔案,如易網首頁中的"建議服務"欄目實際就是採用這種機制,但是對即時性要求較強的交易環節是不適合用這種方式的。
另外一種加快網站速度的方法就是將頻繁訪問資料庫的資訊放在記憶體中,在web伺服器啟動的時候載入進來,這種以為空白間換時間的思路也值得借鑒。
二. 伺服器監測管理流程
一般企業級伺服器都是採用獨立伺服器,需要專人維護,但是這樣成本較高,有必要開發一套後台監控程式來對系統資源,資料/程式備份做監測,用技術手段來降低成本。
如易網後台監控程式實現思路是:分兩個線程,一個進程監測伺服器的記憶體、磁碟資源以及資料庫、Web服務等相關應用的狀態,一旦發現有異常,將以Email或簡訊的形式通知系統管理員;另外一個進程主要對資料進行周期性的備份,並將備份通過ftp上傳至指定待命伺服器。
本系統管理程式在網站運行期間起到重要的安全保障作用,而且也基本不需要人工幹預,減少了人力成本,值得中小企業借鑒。
三. 自助營銷平台
對企業電子商務平台,營銷尤為重要。通過不同路徑收集營銷資料庫,並定期給使用者發送企業產品資訊,這一切過程採用程式的方式實現,方便,省事。
最後,簡要介紹一下網站維護的事宜。網站一旦運營起來,必須保證其7*24小時的全天候正常運行。所以,網站後期的維護極為重要。根據筆者經驗,主要需要做好以下幾個方面:
1. 定期做好資料備份和程式備份。
2. 做好網站安全防護工作,對重要檔案和目錄設定存取權限,架設防火牆,關閉不用的連接埠。定期更改伺服器的密碼,防止駭客入侵。
3. 任何程式級的修改必須經過測試環境的驗證之後才能發布到生產環境,要有套嚴格的發布流程。
做好以上三個方面,網站的正常運行基本可以保證。
結束語:
本文重點介紹了網站實施過程中的技術架構和實現方法,並結合執行個體分析了其中運用到的相關技術。實踐證明,這套思路建立起來的網站架構穩定高效,具有很高的應用價值。