黃河笑 楊煥宇 陳海建 王 磊 鄭任兒
摘要 :本文論述了在設(shè)計(jì)與開發(fā)“軟件工程”網(wǎng)絡(luò)課程中采用的基于案例的教學(xué)內(nèi)容設(shè)計(jì),該教學(xué)設(shè)計(jì)以同一個(gè)案例貫穿所有章節(jié),增進(jìn)了學(xué)生對(duì)知識(shí)點(diǎn)的掌握和理解;開發(fā)環(huán)境使用Dorado MVC架構(gòu)(Struts+Hibernate+Spring),獲得了好的效果。與傳統(tǒng)的開發(fā)模式比較,這種開發(fā)模式最大的優(yōu)勢在于可以節(jié)省開發(fā)人員在開發(fā)Web應(yīng)用表現(xiàn)層時(shí)的工作量,同時(shí)又為用戶提供非常友好的交互界面。
關(guān)鍵詞 :網(wǎng)絡(luò)課程;案例;樹型結(jié)構(gòu)
中圖分類號(hào):G642 文獻(xiàn)標(biāo)識(shí)碼:B
1引言
在開放教育和遠(yuǎn)程教育中,網(wǎng)絡(luò)教學(xué)正被越來越多地使用,開發(fā)適用于網(wǎng)絡(luò)教學(xué)的高質(zhì)量的網(wǎng)絡(luò)課程已經(jīng)成為發(fā)
展網(wǎng)絡(luò)教育的一個(gè)非常重要的課題。
《現(xiàn)代遠(yuǎn)程教育技術(shù)標(biāo)準(zhǔn)體系和11項(xiàng)試用標(biāo)準(zhǔn)(簡介)》中對(duì)網(wǎng)絡(luò)課程進(jìn)行了定義。網(wǎng)絡(luò)課程是通過網(wǎng)絡(luò)表現(xiàn)的某門學(xué)科的教學(xué)內(nèi)容及實(shí)施的教學(xué)活動(dòng)的總和,它包括兩個(gè)組成部分:按一定的教學(xué)目標(biāo)、教學(xué)策略組織起來的教學(xué)內(nèi)容和網(wǎng)絡(luò)教學(xué)支撐環(huán)境。
“軟件工程”課程是本科計(jì)算機(jī)專業(yè)的一門重要課程。在當(dāng)前的教學(xué)中,特別是開放教育和遠(yuǎn)程教育中還存在著很多欠缺,案例太少,或者各章中的案例相互割裂,使得學(xué)生學(xué)完該課程之后無法形成整體的軟件工程概念和思想。因此設(shè)計(jì)和開發(fā)貫穿整個(gè)教學(xué)過程的案例成為“軟件工程”網(wǎng)絡(luò)課程的必然選擇。
2 “軟件工程”網(wǎng)絡(luò)課程的教學(xué)內(nèi)容設(shè)計(jì)
2.1以案例為中心
當(dāng)前的計(jì)算機(jī)相關(guān)專業(yè)實(shí)踐教學(xué)環(huán)境存在諸多薄弱環(huán)節(jié),特別是在軟件工程教學(xué)中,很難為學(xué)生提供一個(gè)全面的感性認(rèn)識(shí)。而當(dāng)前的教學(xué)是離散的過程,沒有提供一個(gè)完整的商業(yè)軟件的實(shí)例來講解商業(yè)軟件開發(fā)的全部過程。經(jīng)過調(diào)查研究、綜合對(duì)比和專家論證,我們選擇了某
軟件公司的商務(wù)軟件“應(yīng)急系統(tǒng)”作為整個(gè)軟件工程網(wǎng)絡(luò)課程的案例。選擇該軟件的原因是該系統(tǒng)在Windows平臺(tái)上基于C++開發(fā),而C++是大部分計(jì)算機(jī)科學(xué)與技術(shù)專業(yè)的學(xué)生都學(xué)習(xí)過的第四代開發(fā)平臺(tái),不足的地方是部分學(xué)生不了解應(yīng)急系統(tǒng)。在教學(xué)內(nèi)容設(shè)計(jì)中我們先對(duì)此公司“應(yīng)急系統(tǒng)”的相關(guān)知識(shí)作了簡單介紹,然后把軟件工程的各個(gè)階段與該軟件的相關(guān)內(nèi)容進(jìn)行了一一映射和組合,公開了大部分相關(guān)設(shè)計(jì)和源代碼。
2.2兼顧面向過程和面向?qū)ο?/p>
當(dāng)前軟件設(shè)計(jì)與開發(fā)的手段一般采用面向過程和面向?qū)ο筮@兩種方法。雖然“應(yīng)急系統(tǒng)”是采用面向?qū)ο蠓椒ㄔO(shè)計(jì)的,但是我們補(bǔ)充了面向過程的設(shè)計(jì)內(nèi)容,這樣學(xué)生通過比較,既能熟悉和了解面向過程和面向?qū)ο蟮脑O(shè)計(jì)方法,又增強(qiáng)了理解,從而獲得了比較好的教學(xué)效果。
3網(wǎng)絡(luò)課程支撐環(huán)境的設(shè)計(jì)
3.1總體結(jié)構(gòu)
系統(tǒng)設(shè)計(jì)應(yīng)由上而下進(jìn)行。首先設(shè)計(jì)總體結(jié)構(gòu),然后再逐層深入,直至進(jìn)行每一個(gè)模塊的設(shè)計(jì)??傮w設(shè)計(jì)主要是在系統(tǒng)分析的基礎(chǔ)上,將整個(gè)系統(tǒng)劃分為若干子系統(tǒng),子系統(tǒng)則由若干模塊組成。數(shù)據(jù)的存儲(chǔ)以及整個(gè)系統(tǒng)實(shí)現(xiàn)等方面都進(jìn)行了合理的安排。圖1所示為“軟件工程網(wǎng)絡(luò)”課程開發(fā)與設(shè)計(jì)的總體結(jié)構(gòu)圖。
3.1系統(tǒng)開發(fā)平臺(tái)——Dorado MVC架構(gòu)
Dorado全稱“Dorado Web應(yīng)用開發(fā)套件”,包含:Dorado Web UI控件集及UI引擎(Dorado Web UI Components and UI Engine),Dorado可視化集成開發(fā)工具 (Dorado Studio),Dorado MVC開發(fā)框架和Dorado Web應(yīng)
用框架。其中Dorado MVC開發(fā)框架的主要功能有:提供類似Struts的MVC開發(fā)框架,以便更加方便地利用Dorado套件進(jìn)行基于MVC架構(gòu)的開發(fā);提供性能監(jiān)控控制臺(tái),可以方便地對(duì)系統(tǒng)運(yùn)行過程中各功能點(diǎn)的運(yùn)行效率進(jìn)行統(tǒng)計(jì)和分析;支持國際化資源配置;支持模塊化配置。Dorado MVC開發(fā)框架是一個(gè)可選件。Dorado套件完全支持各種第三方開發(fā)框架,如Struts、WebWork等。我們利用Dorado與目前較為流行的Struts+Hibernate+Spring進(jìn)行協(xié)同開發(fā)。
3.2系統(tǒng)主要模塊算法與設(shè)計(jì)
(1) 集合混淆算法
客觀題測試用于學(xué)生自測。題目是隨機(jī)排列的,順序與數(shù)據(jù)庫的存儲(chǔ)順序不同,它使用了Java.util.Collections中的shuffle(Listlist)方法來實(shí)現(xiàn),下面是其在JDK 6.0中的算法和代碼。
使用指定的隨機(jī)源隨機(jī)更改指定列表的序列。所有序列更改發(fā)生的可能性都是相等的,假定隨機(jī)源是公平的。
此實(shí)現(xiàn)向后遍歷列表,從最后一個(gè)元素向前一直到第二個(gè)元素,將隨機(jī)選擇的元素重復(fù)交換到“當(dāng)前位置”。元素是從列表中隨機(jī)選擇的,從第一個(gè)元素運(yùn)行到當(dāng)前位置。
此方法以線性時(shí)間運(yùn)行。如果指定列表沒有實(shí)現(xiàn)RandomAccess接口并且是一個(gè)大型列表,則此實(shí)現(xiàn)在改組列表前將指定列表轉(zhuǎn)儲(chǔ)到該數(shù)組中,并將改組后的數(shù)組轉(zhuǎn)儲(chǔ)回列表中。這避免了二次型行為,該行為是因?yàn)樵谶m當(dāng)位置改組一個(gè)“有序訪問”列表而引起的。
private static Random r;
public static void shuffle(Listlist) {
if (r == null) {
r = new Random();
}
shuffle(list, r);
}
public static void shuffle(Listlist, Random rnd) {
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i));
} else {
Object arr[] = list.toArray();
// Shuffle array
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i));
// Dump array back into list
ListIterator it = list.listIterator();
for (int i=0; i it.next(); it.set(arr[i]); } } } (2)DES加密算法 由于客觀題的隨機(jī)排列,使得試題的排列次序與數(shù)據(jù)庫中有所不同。同時(shí),考慮到通過逐條在數(shù)據(jù)庫中查詢來校驗(yàn)答案對(duì)數(shù)據(jù)庫的壓力過大,所以事先查詢出試題的答案,然后根據(jù)打亂后的試題次序把正確答案拼成一個(gè)字符串,然后加密放到頁面的隱藏域中。這樣一來,當(dāng)提交試題查看結(jié)果時(shí)不用再次查詢數(shù)據(jù)庫,只要把答案字符串解密,然后分割成數(shù)組校驗(yàn)即可。
這里的加解密采用了DES算法。
DES算法的入口參數(shù)有三個(gè):Key、Data、Mode。其中Key為8字節(jié)共64位,是DES算法的工作密鑰;Data也為8字節(jié)64位,是要被加密或被解密的數(shù)據(jù);Mode為DES的工作方式,有兩種:加密或解密。
DES算法是這樣工作的:如Mode為加密,則用Key去把數(shù)據(jù)Data進(jìn)行加密,生成Data的密碼形式(64位)作為DES的輸出結(jié)果;如Mode為解密,則用Key去把密碼形式的數(shù)據(jù)Data解密,還原為Data的明碼形式(64位),作為DES的輸出結(jié)果。在通信網(wǎng)絡(luò)的兩端,雙方約定一致的Key,在通信的源點(diǎn)用Key對(duì)核心數(shù)據(jù)進(jìn)行DES加密,然后以密碼形式在公共通信網(wǎng)(如電話網(wǎng))中傳輸?shù)酵ㄐ啪W(wǎng)絡(luò)的終點(diǎn)。數(shù)據(jù)到達(dá)目的地后,用同樣的Key對(duì)密碼數(shù)據(jù)進(jìn)行解密,便再現(xiàn)了明碼形式的核心數(shù)據(jù)。這樣便保證了核心數(shù)據(jù)(如PIN、MAC等)在公共通信網(wǎng)中傳輸?shù)陌踩院涂煽啃浴?/p>
下面是加密算法的部分代碼(解密原理類似):
public class DesEncrypt {
private Key key;
/**
* 根據(jù)參數(shù)生成KEY
*
* @param strKey
*/
public void getKey(String strKey) {
try {
KeyGenerator _generator = KeyGenerator. getInstance("DES");
_generator.init(new SecureRandom (strKey.getBytes()));
this.key = _generator.generateKey();
_generator = null;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 加密 String明文輸入,String密文輸出
*
* @param strMing
* @return
*/
public String getEncString(String strMing) {
byte[] byteMi = null;
byte[] byteMing = null;
String strMi = "";
BASE64Encoder base64en = new BASE64Encoder();
try {
byteMing = strMing.getBytes("UTF8");
byteMi = this.getEncCode(byteMing);
strMi = base64en.encode(byteMi);
} catch (Exception e) {
e.printStackTrace();
} finally {
base64en = null;
byteMing = null;
byteMi = null;
}
return strMi;
}
/**
* 解密 以String密文輸入,String明文輸出
*
* @param strMi
* @return
*/
public String getDesString(String strMi) {
BASE64Decoder base64De = new BASE64Decoder();
byte[] byteMing = null;
byte[] byteMi = null;
String strMing = "";
try {
byteMi = base64De.decodeBuffer(strMi);
byteMing = this.getDesCode(byteMi);
strMing = new String(byteMing, "UTF8");
} catch (Exception e) {
e.printStackTrace();
} finally {
base64De = null;
byteMing = null;
byteMi = null;
}
return strMing;
}
(3) 章節(jié)維護(hù)算法
本網(wǎng)絡(luò)課程中的課程章節(jié)、目錄均為樹形結(jié)構(gòu),其數(shù)據(jù)模型采用了樹的模型,然后通過遞歸從根開始逐層遍歷顯示每個(gè)節(jié)點(diǎn),便于導(dǎo)航學(xué)生學(xué)習(xí)。
下面是顯示樹形結(jié)構(gòu)的代碼,由于樹形結(jié)構(gòu)的顯示使用了ExtJs(Ajax)框架來渲染,所以代碼最終將產(chǎn)生JavaScript代碼的字符串,交由ExtJs框架完成最后顯示工作。
public String getExtTreeString(String prexHref ,String target ,boolean allowEdit ) {
......
//查詢根節(jié)點(diǎn)(包含子節(jié)點(diǎn)層次)
Course rootWithHierarchy = treeNodeDao. getTreeRootWithHierarchy();
StringBuffer rootInfo = new StringBuffer();
//構(gòu)造ExtJs的樹形代碼
appendInfo(rootWithHierarchy , rootInfo);
StringBuffer treeInfo = new StringBuffer("new Ext. tree.AsyncTreeNode(" + Constants.PLACEHOLDER + rootInfo + ")");
return ExtUtil.formatExtStr(treeInfo);
}
private void appendInfo(Course node , StringBuffer buf){
if(node == null) return ;
//如果是葉子節(jié)點(diǎn),構(gòu)造葉子信息
if(node.getIsLeaf()) appendLeaf(node,buf);
//如果是目錄,構(gòu)造目錄信息
else appendFolder(node , buf);
}
private void appendFolder(Course node , StringBuffer buf){
buf.append(",{text:'" + node.getText() + "',");
if(allowEdit){
buf.append("href:'"+prexHref+node.getId()+"',");
buf.append("hrefTarget:'" + target + "',");
}
buf.append("id:'" + node.getId() + "',");
buf.append("leaf:false,");
buf.append("children:[" + Constants.PLACEHOLDER);
//遍歷子節(jié)點(diǎn),構(gòu)造子節(jié)點(diǎn)信息
for(Course child: node.getChildren()){
appendInfo(child , buf);
}
buf.append("]}");}
private void appendLeaf(Course node , StringBuffer buf){
buf.append(",{text:'" + node.getText() + "',");
buf.append("id:'" + node.getId() + "',");
buf.append("iconCls:'user',");
buf.append("href:'"+prexHref + node.getId() + "',");
buf.append("hrefTarget:'" + target + "',");
buf.append("leaf:true");
buf.append("}");
}
從上述代碼中可以看出,首先找出(包含子節(jié)點(diǎn)信息的)根節(jié)點(diǎn),然后通過appendInfo方法來產(chǎn)生ExtJs的JavaScirpt代碼,appendInfo會(huì)根據(jù)節(jié)點(diǎn)類型(葉子或目錄)來調(diào)用appendLeaf或appendFolder方法,其中appendFolder首先生成該目錄的信息,然后逐個(gè)顯示子節(jié)點(diǎn)信息,子節(jié)點(diǎn)又會(huì)調(diào)用appendInfo方法。就是這樣遞歸的調(diào)用,形成了最終的字符串,然后通過服務(wù)器傳到表現(xiàn)層,通過ExtJs來顯示整棵樹。
4結(jié)束語
我們?cè)谠O(shè)計(jì)和開發(fā)“軟件工程”網(wǎng)絡(luò)課程時(shí),采用基于案例的教學(xué)內(nèi)容設(shè)計(jì),同一個(gè)案例貫穿所有章節(jié),增強(qiáng)了學(xué)生對(duì)知識(shí)點(diǎn)的掌握和理解。開發(fā)環(huán)境采用Dorado MVC架構(gòu)(Struts+Hibernate+Spring),獲得了好的效果。這種開發(fā)模式與傳統(tǒng)MVC的開發(fā)模式比較,其最大的優(yōu)勢在于可以節(jié)省開發(fā)人員在開發(fā)Web應(yīng)用表現(xiàn)層式的工作量,同時(shí)又為用戶提供非常友好的交互界面。
從表1中可以看出,本文采用的方法在開發(fā)工作量、用戶界面、軟件可擴(kuò)展性等三個(gè)方面都具有相當(dāng)大的優(yōu)勢。
本網(wǎng)絡(luò)課程的設(shè)計(jì)和開發(fā)是從教學(xué)內(nèi)容和網(wǎng)絡(luò)教學(xué)支撐環(huán)境兩個(gè)方面展開的,已在教學(xué)中使用一年,收到了較好的教學(xué)效果。特別是課程章節(jié)采用樹型結(jié)構(gòu),使得學(xué)生在自主學(xué)習(xí)的過程中獲得了更好的導(dǎo)航效果,提高了學(xué)習(xí)效率。下一步的工作是多增加藝術(shù)性方面的內(nèi)容,尤其是媒體素材設(shè)計(jì)方面。
參考文獻(xiàn):
[1] 林惠強(qiáng),劉財(cái)興,林丕源. “軟件工程”課程啟發(fā)式教學(xué)的研究與實(shí)踐[J]. 計(jì)算機(jī)教育,2008(11):40-42.
[2] 佚名. Dorado與Strats、Hibernare、Spring的集成開發(fā)模式[EB/OL]. [2009-6-10].http://www.javaeye.com/topic/141135.