• 第三次作业


    0 小组成员

    王田路 / 2017202110104

    程环宇 / 2017202110110

    1.项目Github地址

    https://github.com/Cynnn/JavaWebArithmetic

    2.题目

    结对项目:四则运算题目生成程序(基于GUI)http://www.cnblogs.com/hyfatwhu/p/7605757.html

    3.估计花费时间

    PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
    Planning 计划  10  
    · Estimate · 估计这个任务需要多少时间  10  
    Development 开发  1800  
    · Analysis · 需求分析 (包括学习新技术)  240  
    · Design Spec · 生成设计文档  30  
    · Design Review · 设计复审 (和同事审核设计文档)  30  
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范)  30  
    · Design · 具体设计  60  
    · Coding · 具体编码  1200  
    · Code Review · 代码复审  60  
    · Test · 测试(自我测试,修改代码,提交修改)  150  
    Reporting 报告  180  
    · Test Report · 测试报告  120  
    · Size Measurement · 计算工作量  30  
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划  30  
    合计    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;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;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;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;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>
    View Code

    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 }
    View Code

    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("	");
    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("	");
    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("	");
    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("	");
    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 }
    View Code

    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 +"	"+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("璇诲彇鍑烘潵鐨勬枃浠跺唴瀹规槸锛�"+"
    "+result);  
    70           return result;  
    71          }  
    72 
    73 }
    View Code

    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表格

    PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
    Planning 计划  10  10
    · Estimate · 估计这个任务需要多少时间  10  10
    Development 开发  1800  1900
    · Analysis · 需求分析 (包括学习新技术)  240  300
    · Design Spec · 生成设计文档  30  35
    · Design Review · 设计复审 (和同事审核设计文档)  30  35
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范)  30  40
    · Design · 具体设计  60  70
    · Coding · 具体编码  1200  1220
    · Code Review · 代码复审  60  60
    · Test · 测试(自我测试,修改代码,提交修改)  150  150
    Reporting 报告  180  240
    · Test Report · 测试报告  120  180
    · Size Measurement · 计算工作量  30  30
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划  30  30
    合计    1990  2110

    10.结对照片

  • 相关阅读:
    常用数据库排名及分类介绍
    Python之jinja2模板引擎生成HTML
    ResNet网络结构详解与模型的搭建
    window.location各属性
    php练习算法1000题
    在C#中使用 SendMessage 实现操作外部其他程序上的控件教程
    .net 使用FtpClient进行附件的上传
    Exp5 信息搜集与漏洞扫描
    Git 日志提交规范
    [Javascript摸鱼记录] 关于js简单字符删减替换增加插入追加前中后处理
  • 原文地址:https://www.cnblogs.com/zgjssqchy/p/7643176.html
Copyright © 2020-2023  润新知