摘要:本文以實例來詳細分析運用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. 任何程序級的修改必須經過測試環境的驗證之后才能發布到生產環境,要有套嚴格的發布流程。

  做好以上三個方面,網站的正常運行基本可以保證。

  結束語:

  本文重點介紹了網站實施過程中的技術框架和實現方法,并結合實例分析了其中運用到的相關技術。實踐證明,這套思路建立起來的網站架構穩定高效,具有很高的應用價值。