天天看點

第三次作業

0 小組成員

王田路 / 2017202110104

程環宇 / 2017202110110

1.項目Github位址

https://github.com/Cynnn/JavaWebArithmetic

2.題目

結對項目:四則運算題目生成程式(基于GUI)http://www.cnblogs.com/hyfatwhu/p/7605757.html

3.估計花費時間

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃  10
· Estimate · 估計這個任務需要多少時間
Development 開發  1800
· Analysis · 需求分析 (包括學習新技術)  240
· Design Spec · 生成設計文檔  30
· Design Review · 設計複審 (和同僚稽核設計文檔)
· Coding Standard · 代碼規範 (為目前的開發制定合适的規範)
· Design · 具體設計  60
· Coding · 具體編碼  1200
· Code Review · 代碼複審
· Test · 測試(自我測試,修改代碼,送出修改)  150
Reporting 報告  180
· Test Report · 測試報告  120
· Size Measurement · 計算工作量
· Postmortem & Process Improvement Plan · 事後總結, 并提出過程改進計劃
合計  1990

4.解題思路

l  整體架構:MVC

l  開發架構:Spring boot + Thymeleaf模闆

l  前端:bookstrap + javascript +css

l  決定開發web應用後,我們通過上網查資料以及請教熟悉web開發的同學,選擇使用Spring boot架構來完成本次項目。選擇Spring boot架構的原因如下:

  1. Spring Boot可以以jar包的形式來運作,運作一個Spring Boot項目我們隻需要通過java -jar xx.jar類運作,非常友善。
  2. Spring Boot可以内嵌Tomcat,這樣我們無需以war包的形式部署項目。
  3. 使用Spring或者SpringMVC我們需要添加大量的依賴,而這些依賴很多都是固定的,這裡Spring Boot 通過starter能夠幫助我們簡化Maven配置。

l  要求功能的解決思路:

  1.記錄使用者的對錯總數,程式退出再啟動的時候,能把以前的對錯數量儲存并在此基礎上增量計算。

  • 每次使用者做完題目後都将答題對錯情況發送到伺服器,由伺服器記錄來使用者的對錯數量,再将對錯數量顯示在頁面上。

  2.有計時功能,能顯示使用者開始答題後的消耗時間。

  • 使用Javascript的計時器插件,使用者點選開始答題時,計時器啟動,點選結束答題時,計時器停止。

  3.界面支援中文簡體/中文繁體/英語,使用者可以選擇一種。

  • 為每一個有文字的節點标注id,然後在xml檔案裡為這些節點指派。使用者點選按鈕選擇不同的語言後,将下載下傳對應的xml檔案,解析後顯示使用者想要的語言。

5.設計實作過程

  Spring MVC架構圖,如下:

第三次作業

  背景運算器:

  • Fractions用兩個int變量分别表示分子分母,提供靜态函數maxCommonDivisor(int,int)和minCommonMultiple(int, int),分别是求最大公約數函數和最小公倍數函數,還包含将可轉化為整數的分數轉化為整數的函數changeToInteger()。
  • Question采用兩種數組儲存操作數,分别是分數操作數和整數操作數,又建立兩個括号數組,分别是左括号和右括号,專門的乘除運算符數組以及用于計算的兩個堆棧。包括檢查括号限制情況函數checkBracket()、計算函數calculate()、優先級比較函數compare(str: char)等。
  • Calculate包含四個靜态函數,分别是加減乘除。Control包含main函數,從控制台讀取到題目個數,與使用者進行互動。

  我們的四則運算流程圖如下:

第三次作業

  Spring MVC架構中的controller,service,application類圖如下:

第三次作業

  controller映射并處理使用者請求,包括login,index,getnumber,cheform。

  service為controller提供調用的方法,包括生成随機表達式、讀寫曆史記錄。

  webapplication是主程式,程式的入口。

6.代碼說明

6.1前端

6.1.1 js代碼

第三次作業
第三次作業
1 //秒表函數
  2 $('#runner').runner({
  3 
  4 milliseconds: false,
  5 format: function millisecondsToString(milliseconds) {
  6             var oneHour = 3600000;
  7             var oneMinute = 60000;
  8             var oneSecond = 1000;
  9             var seconds = 0;
 10             var minutes = 0;
 11             var hours = 0;
 12             var result;
 13 
 14             if (milliseconds >= oneHour) {
 15                 hours = Math.floor(milliseconds / oneHour);
 16             }
 17 
 18             milliseconds = hours > 0 ? (milliseconds - hours * oneHour) : milliseconds;
 19 
 20             if (milliseconds >= oneMinute) {
 21                 minutes = Math.floor(milliseconds / oneMinute);
 22             }
 23 
 24             milliseconds = minutes > 0 ? (milliseconds - minutes * oneMinute) : milliseconds;
 25 
 26             if (milliseconds >= oneSecond) {
 27                 seconds = Math.floor(milliseconds / oneSecond);
 28             }
 29 
 30             milliseconds = seconds > 0 ? (milliseconds - seconds * oneSecond) : milliseconds;
 31 
 32             if (hours > 0) {
 33                 result = (hours > 9 ? hours : "0" + hours) + ":";
 34             } else {
 35                 result = "00:";
 36             }
 37 
 38             if (minutes > 0) {
 39                 result += (minutes > 9 ? minutes : "0" + minutes) + ":";
 40             } else {
 41                 result += "00:";
 42             }
 43 
 44             if (seconds > 0) {
 45                 result += (seconds > 9 ? seconds : "0" + seconds);
 46             } else {
 47                 result += "00";
 48             }
 49            
 50             return result;
 51         }  
 52        
 53    });
 54 
 55 //buttons
 56 
 57 $('#startBtn').click(function() {
 58     $('#runner').runner('start');
 59     $(this).addClass('activeBtn');
 60     $('#stopBtn').removeClass('activeBtn');
 61 
 62 });
 63 
 64 $('#stopBtn').click(function() {
 65     $('#runner').runner('stop');
 66     $(this).addClass('activeBtn');
 67     $('#startBtn').removeClass('activeBtn');
 68 });
 69 
 70 $('#resetBtn').click(function() {
 71     $('#runner').runner('reset');
 72     $('#stopBtn').removeClass('activeBtn');
 73     $('#startBtn').removeClass('activeBtn');
 74 });
 75 
 76 $('#enBtn').click(function() {
 77     lang = "en";
 78     ChangeLanguage();
 79 });
 80 
 81 $('#chBtn').click(function() {
 82     lang = "ch";
 83     ChangeLanguage();
 84 });
 85 
 86 $('#hkBtn').click(function() {
 87     lang = "hk";
 88     ChangeLanguage();
 89 });
 90 //獲得題目數的點選事件
 91 $('#numberBtn').click(function(){
 92     var number = document.getElementById("numberText");
 93     var url = "http://localhost:8080/number?Action=getnumber&Number="+number.value;
 94     top.location = url;
 95 });
 96 //擷取曆史記錄
 97 $('#history').click(function(){
 98     var wrong = document.getElementById("wrongSpTxt");
 99     var right = document.getElementById("rightSpTxt");
100     alert("right:"+right.innerHTML+"wrong:"+wrong.innerHTML);
101 });
102 
103 
104 var flag = false;//判斷标志
105 //檢查結果
106 function chkform(){ 
107     if(flag){
108         alert("已經判斷過對錯,請重新整理頁面!");
109         return;
110     }
111     flag=true;
112     var list = document.getElementById("list");
113     var items = list.getElementsByTagName("span");
114     var inputs = list.getElementsByTagName("input");
115     var right = 0;
116     var wrong = 0;
117     for(var i=0;i<items.length;i++){
118         if(i%2==1){
119         var item = items[i];
120         if(item.innerText == inputs[(i-1)/2].value){
121             item.style.display="";
122             right++;
123         }else{
124            var item = items[i];
125            item.style.display="";
126            wrong++;
127         }
128     }
129     }
130     $.post("/index",{Action:"chkform",Right:right,Wrong:wrong},function(data,textStatus){
131         alert("right:"+right+"wrong:"+wrong);});
132     
133 }
134 var lang = "hk";//語言變量
135 //節點内容更改
136 function ChangeLanguage() {  
137     var langpath = lang + ".xml";//資源檔案路徑  
138     TranslateElementsAsy(document, 'SPAN', 'innerHTML', langpath);  
139     TranslateElementsAsy(document, 'INPUT', 'value', langpath);  
140     TranslateElementsAsy(document, 'th', 'innerHTML', langpath); 
141     TranslateElementsAsy(document, 'h3', 'innerHTML', langpath); 
142     TranslateElementsAsy(document, 'h1', 'innerHTML', langpath); 
143     TranslateElementsAsy(document, 'a', 'innerHTML', langpath); 
144     
145 }
146 //擷取xml檔案節點内容
147 function getString(path, req_name, xmlDoc) {  
148     //解析XML  
149     //var oError = xmlDoc.parseError;  
150     var nodeName = xmlDoc.getElementsByTagName(req_name);  
151     if (nodeName[0] == null || nodeName[0] == "undefined") {  
152         return null;  
153     } else {  
154         return nodeName[0].childNodes[0].nodeValue;  
155     }  
156 }  
157 
158 //對不同節點,使用不同屬性
159 function TranslateElementsAsy(targetDocument, tag, propertyToSet, path) {   
160     $.ajax({  
161             url: path,  
162             type: 'get',  
163             async: false,  
164             success: function (data) {  
165                 var e = targetDocument.getElementsByTagName(tag);  
166                 for (var i = 0 ; i < e.length ; i++) {  
167                     var sKey  
168                     sKey = e[i].getAttribute('id');  
169                     if (sKey) {  
170                         var s = getString(path, sKey, data);  
171                         if (s) {  
172                             eval('e[i].' + propertyToSet + ' = s');  
173                         }  
174                     }  
175                 }  
176             }  
177         });  
178     }        

View Code

6.1.2主要網頁代碼

第三次作業
第三次作業
1 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 2 <head>
 3     <meta charset="UTF-8" />
 4     <title>Arithmetic</title>
 5     <link th:href="@{bootstrap/css/bootstrap.min.css}" rel="stylesheet" />
 6     <link th:href="@{bootstrap/css/bootstrap-theme.min.css}" rel="stylesheet" />  
 7     <link rel="stylesheet" th:src="@{style.css}"/>
 8 <script type="text/javascript">
 9 function toTop(){
10     window.scroll(0,0);
11  }
12 </script>   
13 </head>
14 
15 <body>
16     <nav class="navbar navbar-inverse navbar-fixed-top">
17     <div class="container">
18     <div class="navbar-header">
19         <a class="navbar-brand" id="na1" href="#">四則運算生成程式</a>
20     </div>
21     <div>
22         <ul class="nav navbar-nav navbar-right"> 
23             <li class="active"><a href="login" id="index">首頁</a></li>
24             <li><a href="#" id="history">曆史記錄</a></li>
25             <li class="dropdown">
26                 <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="la">
27                           語言切換 <b class="caret"></b>
28                 </a>
29                 <ul class="dropdown-menu">
30                     <li><a id="chBtn" type="submit">中文簡體</a></li>
31                     <li><a id="hkBtn" type="submit">中文繁體</a></li>
32                     <li><a id="enBtn" type="submit" >英文</a></li>
33 
34                 </ul>
35             </li>
36         </ul>
37     </div>
38     </div>
39 </nav>
40 <div class="jumbotron">
41 <div class="container">
42 <br></br><br></br>
43 <span style="display:inline-block;width:900px;text-align:left;font-size:50px;" id="head" th:text="歡迎來到Arithmetic"></span>
44 <span style="display:inline-block;text-align:left;font-size:25px;" id="text1" th:text="在這裡,你可以進行四則運算練習,記錄自己做題的時間。在這裡,你能夠檢視做題的曆史記錄"></span><br></br>
45 <span style="display:inline-block;text-align:left;font-size:25px;" id="text2" th:text="這裡是Arthimetic"></span><br></br><br></br>
46 <input class="btn btn-primary" id="startBtn" type="submit" value="開始答題>>"></input>
47 <input class="btn btn-primary" id="stopBtn" type="submit" value="結束答題>>"></input>
48           
49 <span id="runner" style="font-size:30px;"></span> 
50 
51 </div>
52 </div>
53 <div class="container">
54     <div th:if="${not #lists.isEmpty(expression)}">
55        <div class="panel panel-default">
56           <div class="panel-heading">
57              <span class="panel-title" id="titleH3">本次測試題目數:</span>
58              <span id="questionNumber" th:text="${expression.size()}"></span>
59              <span style="display:inline-block;width:700px;text-align:left;"></span>
60               <input class="btn btn-default" id="judgeBtn" type="submit" onclick="return chkform()" value="判斷正誤"></input>
61               <input class="btn btn-default" id="refreshBtn" type="submit" onclick="location.reload(true)" value="重新整理"></input>
62           </div>
63               
64 
65              <span id="rightSp" th:text="對:" style="display:none"></span><span id="rightSpTxt" th:text="${right}" style="display:none"></span>
66              <span id="wrongSp" th:text="錯:" style="display:none"></span><span id="wrongSpTxt" th:text="${wrong}" style="display:none"></span>
67 
68           <div class="panel-body">
69               <ul class="list-group" id="list">
70                   <li class="list-group-item" th:each="arithmeticExpression:${expression}">
71                       <span th:text="${arithmeticExpression.expression}" style="display:inline-block;width:400px;text-align:left;"></span>                                       
72                        <input type="text" name="userresult" id="userresult"></input>  
73                        <span th:text="${arithmeticExpression.printResult()}" style="display:none" id="rightresult"></span>                                                          
74                   </li>
75               </ul>
76           </div>
77               <div class="panel-footer">
78               <span style="display:inline-block;width:950px;text-align:left;"></span>
79               <input class="btn btn-default" id="toTop" type="submit" onclick="toTop()" value="傳回頁面頂部"></input>
80               </div>
81       </div>
82   </div>
83 </div>
84 <script th:src="@{jquery-2.1.1.min.js}" type="text/javascript"></script>
85 <script th:src="@{jquery.runner-min.js}" type="text/javascript"></script>
86 <script th:src="@{bootstrap/js/bootstrap.min.js}" type="text/javascript"></script>
87 <script th:src="@{app.js}" type="text/javascript"></script>
88 </body>
89 </html>      

6.2背景

6.2.1 application

第三次作業
第三次作業
1 package com.example.ArithmeticWeb;
 2 
 3 import java.util.Arrays;
 4 
 5 import org.springframework.boot.CommandLineRunner;
 6 import org.springframework.boot.SpringApplication;
 7 import org.springframework.boot.autoconfigure.SpringBootApplication;
 8 import org.springframework.context.ApplicationContext;
 9 import org.springframework.context.annotation.Bean;
10 @SpringBootApplication
11 public class ArithmeticWebApplication {
12     
13     @Bean
14     public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
15         return args -> {
16 
17             System.out.println("Let's inspect the beans provided by Spring Boot:");
18 
19             String[] beanNames = ctx.getBeanDefinitionNames();
20             Arrays.sort(beanNames);
21             for (String beanName : beanNames) {
22                 System.out.println(beanName);
23             }
24 
25         };
26     }
27     public static void main(String[] args) {
28         SpringApplication.run(ArithmeticWebApplication.class, args);
29     }
30 }      

6.2.2 controller

第三次作業
第三次作業
1 package com.example.ArithmeticWeb;
 2 import java.util.ArrayList;
 3 
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.stereotype.Controller;
 6 import org.springframework.ui.Model;
 7 import org.springframework.web.bind.annotation.RequestMapping;
 8 import org.springframework.web.bind.annotation.RequestMethod;
 9 import org.springframework.web.bind.annotation.RequestParam;
10 import org.springframework.web.bind.annotation.ResponseBody;
11 
12 import question.Question;
13 
14 @Controller
15 public class ArithmeticController {    
16     
17     @Autowired
18     private ArthmeticService arthmeticService;
19     
20     //擷取傳入個數的question
21     @RequestMapping(value = "/getNumber",method = RequestMethod.GET)
22     public String login(Model model,@RequestParam(value="Action",required=true) String action,
23             @RequestParam(value="Number",required=true)String number){  
24         int num = Integer.parseInt(number);
25         ArrayList<Question> Expression = arthmeticService.getQuestionList(num);
26         model.addAttribute("expression", Expression);
27         int right=0;
28         int wrong=0;
29         String str =arthmeticService.readTxtFile();
30         if(str!=null&&!str.equals("")){
31         String[] splits = str.split("\t");
32         right = Integer.parseInt(splits[0]);
33         wrong = Integer.parseInt(splits[1]);
34         }
35         model.addAttribute("right", right);
36         model.addAttribute("wrong", wrong);
37         return "index";
38     }
39     //登入界面映射
40     @RequestMapping(value = "/login")
41     public String login(){
42         return "login";
43     }
44     //主界面的傳輸
45     @RequestMapping(value ="/number",method = RequestMethod.GET)
46     public String getNumber(Model model,@RequestParam(value="Action",required=true) String action,
47             @RequestParam(value="Number",required=true)String number) {
48         int num = Integer.parseInt(number);
49         ArrayList<Question> Expression = arthmeticService.getQuestionList(num);
50         model.addAttribute("expression", Expression);
51         int right=0;
52         int wrong=0;
53         String str =arthmeticService.readTxtFile();
54         if(str!=null&&!str.equals("")){
55         String[] splits = str.split("\t");
56         right = Integer.parseInt(splits[0]);
57         wrong = Integer.parseInt(splits[1]);
58         }
59         model.addAttribute("right", right);
60         model.addAttribute("wrong", wrong);
61         return "index";
62     }
63     @RequestMapping(value ="/Arithmetic")
64     public String index(Model model) {
65         ArrayList<Question> Expression = arthmeticService.getQuestionList(10);
66         model.addAttribute("expression", Expression);
67         int right=0;
68         int wrong=0;
69         String str =arthmeticService.readTxtFile();
70         if(str!=null&&!str.equals("")){
71         String[] splits = str.split("\t");
72         right = Integer.parseInt(splits[0]);
73         wrong = Integer.parseInt(splits[1]);
74         }
75         model.addAttribute("right", right);
76         model.addAttribute("wrong", wrong);
77         return "index";
78     }
79     //獲得使用者的對錯數
80     @RequestMapping(value ="/index",method = RequestMethod.POST)
81     public String chkform(@RequestParam(value="Action",required=true)String action,
82             @RequestParam(value="Right",required=true)int right,
83             @RequestParam(value="Wrong",required=true)int wrong) {
84         String str =arthmeticService.readTxtFile();
85         if(str!=null&&!str.equals("")){
86         String[] splits = str.split("\t");
87         int r = Integer.parseInt(splits[0]);
88         int w = Integer.parseInt(splits[1]);
89         right+=r;
90         wrong+=w;
91         }
92         arthmeticService.writeTxtFile(right, wrong);
93         return "login";
94     }
95 
96 }      

6.2.3 service

第三次作業
第三次作業
1 package com.example.ArithmeticWeb;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.File;
 5 import java.io.FileOutputStream;
 6 import java.io.FileReader;
 7 import java.util.ArrayList;
 8 import java.util.Random;
 9 
10 import org.springframework.stereotype.Service;
11 
12 import question.Question;
13 @Service
14 public class ArthmeticService {
15     
16     public ArrayList<Question> getQuestionList(int size){
17         ArrayList<Question> Expression = new ArrayList<>();
18         Random random = new Random();
19         for(int i=0;i<size;i++){
20             int operators_num = random.nextInt(6)+1;
21             Expression.add(new Question(operators_num));
22         }
23         return Expression;
24     }
25     
26     public boolean writeTxtFile(int right,int wrong){
27         File fileName = new File("d:/record.txt");
28         String content = right +"\t"+wrong;
29         try{
30             if(!fileName.exists()){  
31                 fileName.createNewFile();
32             }
33             FileOutputStream o=new FileOutputStream(fileName);
34             o.write(content.getBytes("GBK"));  
35             o.close();  
36             return true;
37         }catch(Exception e){
38             e.printStackTrace();
39             return false;
40         }
41     }
42     
43     public String readTxtFile(){  
44           String result=null;  
45           FileReader fileReader=null;  
46           BufferedReader bufferedReader=null;  
47           File fileName = new File("d:/record.txt");
48           System.out.println(fileName.getAbsolutePath());
49           try{  
50               if(!fileName.exists()){  
51                     fileName.createNewFile();
52                     return "";
53                 }           
54            fileReader=new FileReader(fileName);  
55            bufferedReader=new BufferedReader(fileReader);  
56            String read=null;  
57             while((read=bufferedReader.readLine())!=null){  
58              result=read; 
59             }
60             if(bufferedReader!=null){  
61                 bufferedReader.close();  
62                }  
63                if(fileReader!=null){  
64                 fileReader.close();  
65                }  
66           }catch(Exception e){  
67            e.printStackTrace();  
68           } 
69           System.out.println("璇誨彇鍑烘潵鐨勬枃浠跺唴瀹規槸锛�"+"\r\n"+result);  
70           return result;  
71          }  
72 
73 }      

7.測試運作

7.1 歡迎頁

第三次作業

7.2 首頁面

第三次作業
第三次作業

 7.3 多語言+判斷正誤

第三次作業

 7.4 曆史記錄功能

第三次作業

 7.5 計時功能

第三次作業

 7.6 單元測試+代碼覆寫率

第三次作業

8.合作情況

  王田路:主要負責前端網頁界面開發,運用html和JavaScript設計網站精美的界面,測試運作網站,優化網站,保證網站正常運作。

  在領航員的陪伴下,前端排除掉了大量的文法錯誤和算法錯誤。後端作為領航員,解答駕駛員的問題,共同查找資料,一起學習新知識。

  程環宇:主要負責背景伺服器開發,映射并處理使用者不同請求,傳回前端需要的資料,完成使用者功能。

  在前端作為領航員,幫助駕駛員檢查,做總體設計。在後端作為駕駛員,與領航員共同進步。

9.項目小結

9.1 王田路

  首先通過這次的結對項目,我對兩人合作開發項目的整個流程有了清晰的認識。結對程式設計是我之前沒有接觸過的,駕駛員和領航員角色的設定讓整個程式設計過程更加順利。在本次項目的開發過程中我負責的是前端的實作,之前對Javascript/css并不是特别熟悉,通過這次項目也使自己的能力得到了提升。

  然後要感謝我的搭檔,我之前的程式設計經驗可能主要注重的是實作功能,對代碼的結構和項目的架構考慮的比較少,而這也是一個軟體非常重要的部分。這次是我的搭檔首先提出使用Spring boot架構,并且他上一次作業的代碼有非常好的封裝性,并且在編碼過程中就想到了提供接口以便于擴充,這些都是我需要學習的。

  由于時間的問題,這次項目中用到的新知識我沒有進行系統的學習,用到的會去網上重點查一下資料,今後有時間會繼續學習,提高自己的能力。

9.2 程環宇

  這次的作業給了我很大的啟發和幫助。

  通過這次的項目,不但學習了 spring boot架構,還熟悉了 JavaScript 的編寫,大大提高了自己的編碼能力。

  結對程式設計可以提高代碼的品質,以前被忽略的問題,partner會幫助找到并給出修改意見。代碼複審階段,partner會對代碼結構提出意見,幫助修改,使得代碼更加清晰易懂。

  結對程式設計可以互補知識,一些我不懂的知識,partner可能會知道,省去了查閱知識的時間,大大提高了開發效率。

  以後,我會和partner繼續合作,共同學好這門課。

9.3 PSP表格

 1900
 300
 35
 40
 70
 1220
 2110

10.結對照片

第三次作業
第三次作業