成員:顧思宇2016011993 程羚2016012050javascript
1.倉庫地址:https://git.coding.net/DandelionClaw/WEB_Calculator.githtml
注:前端
本項目爲web端,而且須要鏈接SQL Server數據庫。java
可以使用已註冊用戶「admin」密碼「admin」登陸,或註冊新用戶登陸。jquery
首頁目錄爲/WEB_Calculator/mysite/WebRoot/index.jsp,虛擬目錄名爲Calculatorgit
tomcat中需加入WEB-INF/lib中的包web
2.PSP:ajax
3. 接口設計:算法
sql
,我對這三個概念比較陌生,查了許久的資料才理解他們的概念。(1)Information hiding 信息隱藏
信息隱藏是程序設計過程當中的一種隔離原則,能夠防止用戶接觸到一個類的某些部分。一個程序模塊能夠將它的信息隱藏起來,對外僅僅展示出一種接口。當這個模塊的具體實現發生改變時,只要保證它的接口不發生變化,則就算不修改模塊外的其餘代碼,程序依舊能夠正確執行。
(2)interface 接口設計
軟件的接口設計元素描述了信息如何流入和流出系統以及被定義爲體系結構一份的構件之間是如何通訊的。此次的做業中用到的主要是各類設計構件之間的內部接口,經過這些接口讓軟件體系結構中的構件之間進行內部通訊與協做。接口實現時,保證全部操做和消息傳遞模式都獲得實現,且不一樣類的操做之間可以進行通訊和協做。
(3)losing coupling 鬆耦合
鬆耦合系統一般是基於消息的系統,此時客戶端和遠程服務並不知道對方是如何實現的。客戶端和服務之間的通信由消息的架構支配。只要消息符合協商的架構,則客戶端或服務的實現就能夠根據須要進行更改,而沒必要擔憂會破壞對方。
對於信息隱藏,我使用了用private封裝重要信息的方法,並設計get、set方法訪問這些隱藏信息。
咱們在進行設計的時候將命令行程序做爲核心程序封裝在package core中,使用servlet在調用該程序,調用時只須要定義一個字符串數組,將命令做爲參數即。而且爲了維護程序的穩定性,我使用了大量的異常處理。而命令行程序即Class Command調用了我上一次我的做業所寫的程序接口。所以,在這次做業中,我用了很短的時間就完成了命令行程序的編寫。
此次的做業讓我充分感覺到了面向對象編程和接口設計的魅力。
4. 計算模塊接口的設計與實現過程:
(1)我設計了4個類,比我的做業時多出了兩個,分別是Command和MyException。
其中Command調用了我的做業所寫的Class Main,它主要負責處理用戶輸入的命令和拋出異常,
而MyException用於異常處理。Main和Formula除了在上次的基礎上優化了一下之外基本沒有改動,在這裏就再也不贅述了。
下圖,圖一爲各種的調用關係,圖二圖三爲Main類和Formula類所包含的成員。
(2)我算法關鍵和獨到之處,除了上次所寫的算式計算外,我以爲就是我此次的異常處理機制了,沒有異常處理的程序是脆弱而不完整的程序,這必然是一個程序的關鍵點。
5. 計算模塊接口部分的性能改進:
在性能改進這一塊我花費了大約2小時,個人主要改進思路是對於內存和運行時間的優化
所以除了將本來的命令行程序擴展命令格式之外,我還優化了字符串存儲方式,詳細內容以下:
1.CPU Views:
由圖可見,消耗最大的是replyonlineFinal.jsp,這個頁面是用於計算用時、獲取正確率和展現錯題,消耗主要在訪問數據庫上。
2. 內存優化:
當輸入參數爲時 效能分析圖爲
經分析String內存佔用較大,緣由是由於我用一個String存儲了所有的算式而且沒有釋放內存,優化代碼後性能明顯改善了許多。
另外我還發現了一個有趣的現象,當代碼執行完成後,內存並無釋放而是疊加了起來,如圖所示:
當題目爲50時內存變化,以後內存不斷攀升達到必定數值後穩定下來。
當我再次輸入50時,內存變化
經研究發現這是由於java特殊的內存釋放機制所致使的。
6. 計算模塊部分單元測試展現:
個人測試思路是測試全部的正常和異常狀況,確保程序可以正常運行。
@Test public void testMain(){//本函數爲正確輸入形式,並打亂了命令輸入順序 String[] args = {"-o","2","-n","20","-c","-b","-m","1","100"}; command.main(args); } @Test public void testMain1(){//本函數只正確輸入了-n命令,但沒有輸入另外一個必須輸入的命令-m String[] args = {"-n","20"}; command.main(args); } @Test public void testMain2(){//本函數測試不輸入任何命令的狀況 String[] args = {}; command.main(args); } @Test public void testMain3(){//本函數測試輸入了必須輸入的-n、-m命令,但-m命令少輸入了一個參數 String[] args = {"-n","20","-m","1"}; command.main(args); } @Test public void testMain4(){//本函數測試輸入錯誤命令 String[] args = {"aaaa"}; command.main(args); } @Test public void testMain5(){//本函數測試輸入了-n命令,但缺乏了參數 String[] args = {"-n"}; command.main(args); } @Test public void testMain6(){//本函數測試輸入了-0命令,但缺乏了參數 String[] args = {"-o"}; command.main(args); } @Test public void testMain7(){//本函數測試輸入了必須輸入的-n、-m命令,但-n參數範圍錯誤 String[] args = {"-n","1000000","-m","1","100"}; command.main(args); } @Test public void testMain8(){//本函數測試輸入了必須輸入的-n、-m命令,但-n參數類型錯誤 String[] args = {"-n","aaa","-m","1","100"}; command.main(args); } @Test public void testMain9(){//本函數測試輸入了必須輸入的-n、-m命令,但-m參數範圍錯誤 String[] args = {"-n","10","-m","100","50"}; command.main(args); } @Test public void testMain10(){//本函數本函數測試輸入了必須輸入的-n、-m命令,但-o參數範圍錯誤 String[] args = {"-n","10","-m","1","100","-o","-100"}; command.main(args); }
11個測試函數均運行正確
覆蓋率達到了90%以上
7. 計算模塊部分異常處理說明:
我設置了大量的異常處理,確保程序不管如何都可以正確運行:
-n 這個命令是伴隨一個參數的,我設計了①用戶沒有輸入參數,②參數範圍不對的狀況
-m 這個命令伴隨了兩個參數,我設計了①用戶沒有輸入參數或只輸入了一個,②參數範圍不對的狀況,③下限數值高於上限。其中第三點明顯是一個老師故意留下的小陷阱,老師題目要求的上限值最低是50,但下限值最高是100。
-o 這個命令是伴隨一個參數的,我設計了①用戶沒有輸入參數,②參數範圍不對的狀況
其餘 除了針對上述命令的處理外,還有參數類型錯誤的處理,兩個必要的命令-n、-m缺乏了任一或都沒出現的處理,沒有輸入命令的處理
爲了不脫離程序而使描述抽象的問題,我將6.代碼中。
和相應錯誤場景以註釋形式寫在了
8. 界面模塊的詳細設計過程:
因爲咱們兩人分工明確,我負責後端,她負責前端,因此全部前端代碼都不是由我完成。可是我做爲後端,也就是功能的實現者天然也負責需求的提出。
登陸和註冊界面,用戶名密碼這個天然是必需要有的
題庫定製界面,咱們設計了導航欄、語言切換、用戶切換、查閱歷史題目以及一個頁內跳轉的按鈕。點擊「開始作題」或滾輪向下滑動,就到定製區,咱們在前端也設計了異常處理,若是用戶輸入的參數格式不對或者範圍不對,前端會顯示提示而且表單將會沒法提交,直至用戶輸入正確參數爲止。
作題界面,除了必要的提交按鈕外,咱們還人性化地設計了「上一題」、「下一題」按鈕,以及「放棄答題」按鈕。
作題完成界面,在本頁面展現了用戶的用時和正確率,而且展現了用戶的全部錯題。
歷史記錄界面,在本頁面展現了當前用戶的全部作題記錄和最佳記錄。
界面展現見9.
下面給出了一個作題界面按鈕的CSS代碼
button{ margin: 20px; } button a{ color: black; } .button{ margin:60px 220px; margin-top: 60px; } .bt{ -webkit-transition: all 300ms cubic-bezier(0.19, 1, 0.22, 1); transition: all 300ms cubic-bezier(0.19, 1, 0.22, 1); -webkit-transform: translateX(47px); will-change: transform; z-index: 3; overflow: hidden; border-radius: 40px; padding: 12px 15px; background: #43CB9D; color: white; font-size: 16px; font-weight: 500; letter-spacing: 1px; line-height: 1; text-transform: uppercase; } .bt:before { -webkit-transition: opacity 300ms ease-out, -webkit-transform 0ms 300ms; transition: opacity 300ms ease-out, -webkit-transform 0ms 300ms; transition: opacity 300ms ease-out, transform 0ms 300ms; transition: opacity 300ms ease-out, transform 0ms 300ms, -webkit-transform 0ms 300ms; opacity: 0; -webkit-transform-origin: center center; transform-origin: center center; -webkit-transform: scale(0); transform: scale(0); will-change: transform, opacity; content: ""; display: block; z-index: -1; top: 0; left: 0; width: 100%; height: 100%; background: #3FE2D9; border-radius: 40px; } .bt{ float: left; }
9. 界面模塊與計算模塊的對接:
(1)UI設計
咱們如今紙上完成了基本的UI 界面設計,而後由個人搭檔負責實現和美化,詳細內容在8.中都已說明。
(2)先後端對接
我採用servlet+JavaBean+form表單的方法將先後端聯繫起來。
例如在產生算式時,用form表單將用戶輸入的參數獲取至servlet,將命令行程序import進servlet中,使用接口調用命令行程序產生算式。而後將生成的算式保存至數據庫中,再在前端使用JavaBean連接數據庫,把算式輸出到前端。用戶註冊、答題等同理。
(3)功能展現
①登陸和註冊功能:
②附加功能1 多語言功能:
③題庫生成功能,若參數錯誤先後端均提供了異常處理,前端顯示提示並使得表單沒法提交,後端throw catch處理異常。
④作題功能,計時功能,本次正確率統計功能,錯題展現功能
⑤上傳題目功能
⑥附加功能2 分用戶歷史作題記錄展現,並顯示最佳記錄
咱們小隊分工比較明確,我主要負責後端,隊友主要負責前端。隊友爲咱們小組的領航員~
咱們的第一步:選擇了個人第一次做業代碼,隊友在本來的基礎上面進行更改,我開始作基本的前端頁面。咱們先本身作本身的,在各自擅長的領域奮鬥前行~
咱們的第二步:隊友開始寫單元測試,她繼續美化咱們的web界面,咱們對web界面有比較高的要求,一致認爲好的界面是吸引用戶的最好手段!
咱們的第三步:初步先後端合體,實現一些基本功能,如:題目定製,在線答題,輸出結果……由於咱們是舍友,進行交流也比較方便,雖然出過一些bug,可是也很快就解決了。開心
咱們的第四步:一塊兒爲模塊增長異常處理,主要爲「生成算式數量」異常和登陸異常,在覈心模塊寫入後,咱們又考慮到用戶體驗,使用jQuery撰寫了相應的及時提醒以及防止跳轉,雙重保障更貼心呢!
咱們的第五步:檢查整個項目,並進行優化。
http://www.cnblogs.com/xinz/archive/2011/08/07/2130332.html
解決,而後有天閒聊,聊着聊着就聊出了一個新的方法。也驗證了那句,語言是思惟碰撞的開始。
3. 最深有感觸的一點:bug解決的更快了!
我可愛的隊友:優勢1. 脾氣好,有幹勁
優勢2. 有耐心,遇到bug也願意一直調,想辦法解決
優勢3. 能力強,提出的需求都完成了
缺點:缺點是木有缺點!
實現原理:經過jquery+ajax實現。核心思想是經過i18n屬性設置多語言的key,而後插件對全部帶i18n屬性的dom進行掃描處理。可是前端多語言並不只僅是這一個需求,進而延伸的還有事件函數中須要使用的消息,好比
新增一條數據後的提示消息「新增成功」。這時,就須要對普通字符串對象,即String對象進行處理,使其支持多語言。
這裏貼出部分代碼:
1. 瀏覽器語言的獲取
/** * 獲取瀏覽器語言 * @returns language */ function getLang(){ if(typeof(cacheLang) != "undefined"){ return cacheLang; } if (navigator.language) { cacheLang = navigator.language.toLowerCase(); return cacheLang; }else { cacheLang = navigator.browserLanguage.toLowerCase(); return cacheLang; } }
2.多語言配置的加載
var url = $.type(p) == "string" ? p : "i18n/" + getLang() + ".json";//p爲參數,可經過p手動指定配置路徑,此時不根據默認路徑加載多語言消息配置 $.ajax({ url : url, dataType : 'json', type : "GET", success : function(data, textStatus, jqXHR) { messages = data;//緩存消息 run(data);//執行dom處理 callback(self);//回調處理,self爲插件自己對象 }, error : function(a, b, c) { throw "Load i18n message error [" + p + "], cause by : " + b; } });
3.DOM處理
/** * 替換國際化消息 * @param ms 消息對象 */ function run(ms){ $("*[i18n]").each(function(){ var o = $(this); var key = o.attr("i18n");//獲取key var val = o.attr("i18n-set");//獲取消息設置目標 var message = _getMessage(ms, key);//取得消息 switch(val){//根據不一樣目標設置到不一樣的地方 case undefined: o.html(message); break; case "append": o.html(o.html() + message); break; case "html": o.html(message); break; case "value": o.val(message); break; default: o.attr(val, message); break; } o.removeAttr("i18n");//移除屬性,避免二次處理 o.removeAttr("i18n-set"); }); }
4. 獲取多語言的方法
/** * 獲取多語言消息 * @param msgs 消息對象 * @param key 消息名稱 * @returns value 消息 */ function _getMessage(msgs, key){ var message; try{ message = msgs[key]; }catch(e){ message = key; } return message; }
5.實現對String對象的改造
/** * 爲String提供local方法獲取多語言消息 * @return value 消息 */ String.prototype.local = function(){ return _getMessage(messages, this); }
主要經過javaBean+JSP鏈接數據庫來實現,創建Users表和Score表,分別記錄用戶信息和得分信息。
在用戶登陸時將用戶名保存在session中,經過在jsp頁面中調用數據庫來得到當前用戶的作題記錄和得分信息。
最佳記錄使用SQL語句排序來得到
String sql = "SELECT TOP 1 per FROM Score where username='"+User+"' ORDER BY per DESC"; ResultSet rs = connDB.executeQuery(sql); String best = ""; if(!rs.next()){ best = "您未作過題目"; } else best=rs.getString(1);