《實施篇》
本篇主要介紹該平臺的具體實現過程。根據軟件工程的相關理論,結合筆者多年的開發經驗,網站開發一般尊循以下六步驟:
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對象里)替換靜態文本,由于這部分相對技術性不強,所以不再詳細贅述了。
通過前面四部分的介紹,基本概述了如易網技術實施的主要過程,在下面的一章里介紹網站技術中的幾個重要技巧。