结对项目
Posted 陈芳1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了结对项目相关的知识,希望对你有一定的参考价值。
目录:
一、相关地址
二、 预计在程序的各个模块开发上耗费的时间(psp):
三、接口设计
四、计算模块接口的设计和实现过程。
五、计算模块接口部分的性能改进
六、计算模块部分单元测试展示
七、模块部分异常处理:
十二、在程序的各个模块开发实际上耗费的时间(psp):
十三、总结
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
一、相关地址:
项 目 测 试 地 址: http://39.105.6.214/PairProgram2_war/
Coding.net 项目地址:https://git.coding.net/chenf640/pairProgram.git
(参考学号:2016011001 密码:123123)
(命令行测试:
1.进入src文件夹;
2.在命令行输入javac -encoding utf-8 Command.java;
3.回车再输入 java Command -n 10 -m 1 100 (或其他命令)
回车,result.txt文件创建成功
- result.txt文件在与src同级目录下
)
二、 预计在程序的各个模块开发上耗费的时间:
PSP2.1 |
任务内容 |
计划共完成需要的时间(min) |
Planning |
计划 |
1*60 |
· Estimate |
· 估计这个任务需要多少时间,并规划大致工作步骤 |
1*60 |
Development |
开发 |
50*60 |
· Analysis |
· 需求分析 (包括学习新技术) |
5*60 |
· Design Spec |
· 生成设计文档 |
2*60 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
1*60 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
1*60 |
· Design |
· 具体设计 |
3*60 |
· Coding |
· 具体编码 |
26*60 |
· Code Review |
· 代码复审 |
4*60 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
8*60 |
Reporting |
报告 |
7*60 |
· Test Report |
· 测试报告 |
5.5*60 |
· Size Measurement |
· 计算工作量 |
30 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
1*60 |
三、接口设计
首先,虽然以前用过接口,但并不知接口到底要怎么进行设计才更合理。于是,在设计接口之前我先去了解了关于老师提出的几个英文词组。
1.Information Hiding(信息隐藏)
什么是信息隐藏:信息隐藏是指在设计和确定模块时,使得一个模块内包含的特定信息(过程或数据),对于不需要这些信息的其他模块来说,是不可访问的。
为什么要信息隐藏:
-
隐藏复杂度:这样你就不用再去应付它,除非你要特别关注的时候;
-
隐藏变化源:这样当变化发生时,其影响就能被限制在局部范围内。复杂度的根源包括复杂的数据类型、文件结构、布尔判断以及晦涩的算法等等。
信息隐藏的特点:(1)不可感知性(2)鲁棒性(反映了信息隐藏技术的抗干扰能力)(3)隐藏容量(应用于隐蔽通信中时,为了提高通信的效率)
2. Interface Design(接口设计)
接口的特点
-
接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
-
接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
-
接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
3.Loose Coupling(松耦合)
松耦合就是降低系统部件和部件之间的耦合性,也就是降低部件的依赖性,使得部件之间相对独立,这样对于日后系统的维护及扩展都是很有好处的。在J2EE中可以使用接口来降低程序的耦合度,因为多态的特性,父类或者接口的引用是可以接受子类对象的。
综上,在设计接口时,首先,我们进行了模块化设计,对一类功能的函数进行封装。其次,我们将代码量比较多,代码逻辑比较复杂的按要求产生四则运算的相关程序实行接口设计。虽然,功能程序内部很复杂,但是用户只需调用一个方法即可。只需输入相关参数,至于参数的名称、内部的实现,用户并不知道。这也为程序以后的维护和扩展提供了方便。
四、计算模块接口的设计和实现过程。
接口的设计和实现过程主要涉及到3个类,一个接口,10个函数和一个主函数。
Command类:包含主函数,生成四则运算模块的入口。通过该类从后台获取参数要求,并进行判断参数是否符合要求,若符合,则将通过调用接口产生符合要求的运算式。若不符合要求,则抛出异常,给出提示重新输入;
IsRight类:将从后台输入的自妇产进行解析,看是否符合生成运算式的要求,若符合,则将符合的参数返回到Command类,若不符合,则将提示参数不符合要求,重新输入;
Algorithm接口:主要包含生成带括号的运算式和不带括号的运算式两个函数,还有在生成运算式过程中会用到的判断符号优先级和将代表运算符的数字转换为相应的字符的函数(0-"+",1-"-",2-"*",3-"÷");
AlgorithmImpl类:Algorithm接口的具体实现。
类之间的关系如下:
五、计算模块接口部分的性能改进
在接口的性能改进上,我大概用了4个小时,我的思路主要就是尽量缩短生成特定要求的运算式的时间。
比如说:我以前在判断条件时,如果产生的不符合要求,则重新产生随机数,直至符合要求为止。这样有时就会一直随机产生,需要好久可能才产生一个符合要求的运算式。因此,在改进时,我主要是将不符合要求的直接舍弃,重新生成。这样会在一定程度上节约时间并且不会产生死循环。
关于性能分析图,我以前没有接触过,因此我上网搜了一下,发现关于java的性能分析工具在jdk的bin目录直接有,只需按自己的需求下载相应的插件即可。我看了一下博客,关于java VisualVM的推荐使用最多。关于这个工具的使用方法,推荐这篇博客【Java VisualVM】使用 VisualVM 进行性能分析及调优,是我看过比较详细比较详细的一篇啦。
部分截图:
关于程序中消耗最大的函数就是 生成不产生括号,运算符大于一位的符合要求的运算式 的函数。
六、计算模块部分单元测试展示
单元测试主要分为Algorithm接口的实现AlogriyhmImpl类中的方法测试和IsRight类中的方法测试
AlgorithmTest类部分代码:
1 @Test
2 public void algorithm() throws Exception {
3 Algorithm algorithm =new AlgorithmImpl();
4 for(int i =0;i<12;i++){
5 System.out.println(algorithm.algorithm(1,100,1,1));
6 System.out.println(algorithm.algorithm(10,200,2,1));
7 System.out.println(algorithm.algorithm(5,200,4,1));
8 System.out.println(algorithm.algorithm(5,100,7,1));
9 System.out.println(algorithm.algorithm(10,200,1,2));
10 System.out.println(algorithm.algorithm(10,100,2,2));
11 System.out.println(algorithm.algorithm(1,100,4,2));
12 }
13 }
14
15 @Test
16 public void bracketsAlgo() throws Exception {
17 Algorithm algorithm =new AlgorithmImpl();
18
19 for(int i =0;i<10;i++){
20 System.out.println(algorithm.BracketsAlgo(10,100,1,1));
21 System.out.println(algorithm.BracketsAlgo(1,100,5,1));
22 System.out.println(algorithm.BracketsAlgo(10,100,1,2));
23 System.out.println(algorithm.BracketsAlgo(5,200,4,2));
24 }
25 }
IsRightTest测试类中的部分代码:
1 @Test
2 public void cTest() throws Exception {
3 IsRight isRight = new IsRight();
4 String s[]={ "-n","12", "-m","1","100","-c","-o"};
5 String s1[]={ "-n","12", "-m","1","100"};
6 System.out.print(isRight.cTest(s));
7 System.out.print(isRight.cTest(s1));
8 }
9
10 @Test
11 public void mTest() throws Exception {
12 IsRight isRight = new IsRight();
13 String s[]={ "-n","12", "-m","1","100","-c","-o"};
14 String s1[]={ "-n","12", "-m","1","100"};
15 String s2[]={ "-n","12", "-m","1","10000"};
16 String s3[]={ "-n","12", "-m","333","100"};
17 String s4[]={ "-n","12", "-m","60","100"};
18 String s5[]={ "-n","12", "-m","1","2"};
19 System.out.print(isRight.mTest(s));
20 System.out.print(isRight.mTest(s1));
21 System.out.print(isRight.mTest(s2));
22 System.out.print(isRight.mTest(s3));
23 System.out.print(isRight.mTest(s4));
24 System.out.print(isRight.mTest(s5));
25 }
构造测试数据的思路:尽可能多的把可能出现得情况列举出来,提高代码覆盖率。又因为产生的符号的随机数都是随机的,因此应该在测试时多测试几次,降低偶然性。
单元测试的测试覆盖率截图:
七、模块部分异常处理:
在设计异常时,我将异常都封装到一个名为MyExpection类中,让代码更加简洁。
异常一:输入参数错误。
- 设计目标:当用户输入不符合要求的参数时,程序可以捕获该异常,给出用户反馈,告诉用户错误出现在哪,提示用户重新输入参数。
- 对应单元测试部分代码:
1 @Test 2 public void mTest() throws Exception { 3 IsRight isRight = new IsRight(); 4 String s1[]={ "-n","12", "-m","1","rrrr"}; 5 String s4[]={ "-n","12", "-m","ww","100"}; 6 System.out.print(isRight.mTest(s1)); 7 System.out.print(isRight.mTest(s4)); 8 }
- 对应结果:
- 错误对应的场景:用户输入不符合要求的参数时。
如在命令行输入时:
异常二:result.txt文件创建失败
- 设计目标:创建result.txt,将内容写入到result.txt过程中,出现异常进行捕获,并提示用户result.txt创建失败。
- 错误对应的场景:文件创建失败,文件写入异常等。
- 对应单元测试:
1 @Test 2 public void creatFile() throws Exception { 3 CreatFile creatFile = new CreatFile(); 4 creatFile.creatFile(10,1,100,4,1,1); 5 }
如果错误,抛出异常:
其他的异常,主要是利用了java自带的异常。比如说ServletException, IOException, ScriptException等。
1.index.jsp
关于选择语言这个功能,我采用的是将选择的值存在session。只要在该页面选择了 中文/English ,在以后的页面,显示内容前都会加一个判断,判断session中的值对应的选择的语言是中文还是英文。
1 <form action="${pageContext.request.contextPath}/Algo?state=langu" method="post"> 2 <font size="3" color="" style="margin-top: 20px">请选择支持的语言</font> 3 <font size="3" >(Please select the supported language)</font> 4 <select style="height:20px;width:60px;margin-top:35px" name="language"> 5 <option value="1" selected="selected">中文</option> 6 <option value="2">English</option> 7 </select><br> 8 <input type="submit" value="确定(confirm)" style="width:100px;height:25px;margin-top:20px"> 9 </form>
2.login.jsp
该页面用户可以进行登录,登录成功后跳转到welcome.jsp页面,并提供前往登录页面的按钮。
3、register.jsp
该页面可进行用户注册,注册成功后跳转到登录页面,进行用户登录。
4.welcome.jsp
- 选择完需要的语言将会跳转到该页面。该页面可进行我们这个程序的两个功能的选择。题目生成还是上传文件。
- 点击“题目生成” 跳转到 Algo.jsp 页面。
- 点击 " 上传文件 " ,如果上传的是空文件,则出现提示,提醒用户重新上传。
- 点击“查看个人历史记录”,跳转到用户记录页面。
- 点击“查看全部用户历史记录”,跳转到全部用户历史记录页面。
- 点击“退出登录”,跳转到用户登录界面,并将存在session中的会话销毁。
1 <div style="margin-top: 130px;margin-left: 300px"> 2 <c:if test="${language==1}"> 3 <a href="${pageContext.request.contextPath}/Algo?state=Algo1" ><button><font size="4" >题目生成</font></button> </a> 4 <br><br> 5 <font size="5" ><strong>OR</strong></font><br><br> 6 <table border="1" > 7 <tr> 8 <td> 9 <font size="4" >上传文件</font> 10 </td> 11 <td> 12 <form action="${pageContext.request.contextPath}/upTitle?state=up" enctype="multipart/form-data" method="post"> 13 <input type="file" name="file2" value="选择文件" required="required"/><br/><br> 14 <input type="submit" size="3"/> 15 </form> 16 </td> 17 </tr> 18 </table><br><br> 19 <font color="red">${msg1}</font> 20 </c:if> 21 </div>
5.Algo.jsp
- 在该页面,可以填写生成运算式的要求。 如果不符合要求,则提示用户,重新填写。
- 如果成功生成写有符合要求的文件,则提醒用户点击“下载文件”按钮进行下载文件。
- 在该页面,通过对文本框添加一些属性,进行限制。保证必填项必填,而且填入的必须为整数。
1 <form action="${pageContext.request.contextPath}/Algo?state=AlgoTest" method="post" > 2 <font color="red">*</font>生成的题目数:<input type="text" name="n" style="height:35px;width:60px;margin-top:25px" required="required" placeholder="1-10000" onkeyup="(this.v=function(){this.value=this.value.replace(/[^0-9-]+/,\'\');}).call(this)" onblur="this.v();"> <br> 3 <font color="red">*</font> 4 题目的上下限:<input type="text" name="m1" style="height:35px;width:60px;margin-top:25px" required="required" placeholder="1-100" onkeyup="(this.v=function(){this.value=this.value.replace(/[^0-9-]+/,\'\');}).call(this)" onblur="this.v();">——<input type="text" name="m2" style="height:35px;width:60px;margin-top:25px" required="required" placeholder="50-1000" onkeyup="(this.v=function(){this.value=this.value.replace(/[^0-9-]+/,\'\');}).call(this)" onblur="this.v();"><br> 5 符号的数量:<select style="height:20px;width:50px;margin-top:25px" name="o"> 6 <option value="1" selected="selected">1</option> 7 <option value="2">2</option> 8 <option value="3">3</option> 9 <option value="4">4</option> 10 <option value="5">5</option> 11 <option value="6">6</option> 12 <option value="7">7</option> 13 <option value="8">8</option> 14 <option value="9">9</option> 15 <option value="10">10</option> 16 </select><br><br> 17 是否有乘除法: 18 否<input type="radio" name="c" value="2"checked="checked"/> 19 是<input type="radio" name="c" value="1" /><br><br> 20 是否含有括号: 21 否<input type="radio" name="b" value="2" checked="checked" /> 22 是<input type="radio" name="b" value="1"/><br><br> 23 <font color="red" size="2">(*为必填,且为正整数)</font><br> 24 <input type="submit" value="生成题目" style="width:100px;height:35px;margin-top:25px"><br><br> 25 ${msg} 26 </form> 27 <form action="${pageContext.request.contextPath}/Algo?state=downFile" method="post"> 28 <input type="text" name="filename" value="${filename}" hidden> 29 <c:if test="${not empty filename}"> 30 <button>点击下载文件</button> 31 </c:if> 32 </form>
6.successUpload.jsp
如果文件上传成功则跳转到该页面,提示用户做题时选择题目显示的方式(题目一次全部显示/题目一道做完后显示下一道),并且点击开始做题时,开始计时。
7.doAlgo.jsp
- 在该页面将用户上传文件的内容全部显示出来。
- 为了使页面更美观,我用了<div>标签将页面进行了布局。根据上传的题目的数量进行不同的布局。主要分为小于等于10、11-40、41-60、61-80、大于80这5个部分。
- 在该页面,有计时器功能。从刚进入该页面时开始计时,到做完全部题目,离开该页面时停止计时。(关于js的部分要感谢工作室前端的小伙伴 吕国馨 啦)
1 <script src="../../js/text.js"></script> 2 <%--、、计时--%> 3 <script> 4 function start(){ 5 var today=new Date() 6 var h=today.getHours() 7 var m=today.getMinutes() 8 var s=today.getSeconds() 9 m=checkTime(m) 10 s=checkTime(s) 11 document.getElementById(\'txt\').innerhtml=h+":"+m+":"+s; 12 t=setTimeout(\'start()\',500) 13 } 14 15 function checkTime(a){ 16 if(a<10){ 17 a="0" + a 18 } 19 return a 20 } 21 </script>
8.doLogin2.jsp
- 该页面将用户上传文件中的运算式,一个接一个的显示出来,做完一道题点击下一题,才会出现下一题。该页面不仅显示当前在做的题目,而且显示一共几道题,当前为第几道题。
- 当做完最后一道题点击作答完毕,将跳转到result.jsp中,显示作答的情况。
9.result.jsp
- 该页面主要显示用户做题的情况。将显示原题和用户提交的答案。还有用户共答对几道题,用时多长时间、以及作答错误的题号。让用户对本次答题情况一目了然,也便于用户查看自己做错的题目。
- 在该页面显示原题跟用户提交的答案时,采用的方式跟doAlgo.jsp页面所采取的方式一致,用<div>来布局。
显示结果部分代码:
1 <%--显示结果--%> 2 <div style="margin-top: 30px;"> 3 <%--语言为英语--%> 4 <c:if test="${language==2}"> 5 Altogether <strong>${count}</strong> questions,The number of correct questions is <strong>${right}</strong>,<br> 6 The number of incorrect answers is <strong>${count-right}</strong> 7 ,total time <strong>${allTime2}</strong> 8 <br> 9 The wrong number is: 10 </c:if> 11 <%--语言为中文--%> 12 <c:if test="${language==1}"> 13 一共<strong>${count}</strong> 道题 , 作对 <strong>${right}</strong>道 ,<br> 14 做错<strong>${count-right}</strong> 道 ,共用时 <strong>${allTime1}</strong> 15 <br> 做错的题号是: 16 </c:if> 17 <c:forEach items="${rightNum}" var="rightNum" varStatus="status"> 18 <c:if test="${rightNum!=0}"> 19 <font color="red"><strong> ${rightNum} </strong></font> 20 </c:if> 21 </c:forEach> 22 </div>
10.allScore.jsp
该页面看看到全部用户的做题记录及成绩
11.studentScore.jsp
该页面可以查看登录用户以往的做题记录,包括正确率、用时等。
在该部分,我主要用的是jsp和servlet来将前端与后端进行对接。我主要写了两个servlet方法。AlgorithmServlet、UploadTitleServlet和UserServlet。通过jsp页面将参数传递给servlet方法,servlet获取jsp的相关参数,调用方法将产生的相关内容再返回给jsp页面,在前台展示。
1.确定页面使用的语言
通过在jsp页面中获取用户选择的语言,将相关参数传递给AlgorithmServlet,将语言参数保存在session中。在每个页面中都进行判断session中语言的类型。根据语言的类型,来显示不同的内容。
servlet中存取语言类型 代码:
1 String language = request.getParameter("language");
2 HttpSession session=request.getSession();
3 session.setAttribute("language",language);
jsp中判断部分代码:
1 <c:if test="${language==1}"> 2 <input type="submit" value="返回页面" style="width: 100px;height:45px"> 3 </c:if> 4 <c:if test="${language==2}"> 5 <input type="submit" value="Return" style="width: 100px;height:45px"> 6 </c:if>
2.生成运算式
将运算式需要的参数在页面填写,通过form表单将填入的参数传到servlet中,通过servlet调用产生运算式的方法,将产生的运算式写入txt文件中,用户可进行下载。为了保证同时多人访问网页生成的文本文件冲突,因此,我用一个随机函数,生成一串字符作为写入文件的文件名。如果输入的参数不符合要求,则重新返回jsp页面,提示用户重新输入参数。
随机产生文件名的代码:
String fileName = UUID.randomUUID() + "result.txt";
3.上传文件
首先,通过jsp页面将上传的文件传入servlet中,servlet将该文件保存在程序中,然后通过方法将该文件中的每一行读取出来,存入List中,再将list传到jsp页面,进行题目的展示。
4.判断题目对错
首先将用户回答的原题跟答案传到servlet页面,通过调用方法将该题目的正确答案算出,然后将正确答案跟用户回答的答案进行比较,如果正确,正确的数量加一。如果错误,将错误的题号记录下来。
当用户将题目全部答完,将用户回答的全部题目及答案,还有用户回答对几道题,答错的题号有哪些,用时等信息传给result.jsp页面,通过该页面将信息显示给用户。
5.判断登录用户名是否正确,密码是否正确,不正确时会返回前台给出提示。
后台代码:
1 private void LoginCheck(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 String studentNumber = request.getParameter("studentNumber"); 3 String password = request.getParameter("password"); 4 UserDao userdao = new UserDaoImpl(); 5 User user1= userdao.SelectUserBystudentName(studentNumber); 6 HttpSession session=request.getSession(); 7 RequestDispatcher rd = null; 8 if (user1!= null) { 9 String username = user1.getUsername(); 10 session.setAttribute("username",username); 11 session.setAttribute("studentNumber",studentNumber); 12 if (user1.getPassword().equals(password)) { 13 rd = request.getRequestDispatcher(WebContents.WELCOME); 14 rd.forward(request, response); 15 } else { 16 rd = request.getRequestDispatcher(WebContents.LOGIN); 17 request.setAttribute("msg1", "密码错误,请重新输入!"); 18 request.setAttribute("msg2", "The password is wrong. Please retype it!"); 19 rd.forward(request, response); 20 } 21 } else { 22 rd = request.getRequestDispatcher(WebContents.LOGIN); 23 request.setAttribute("msg1", "该用户不存在,请重新输入用户信息!"); 24 request.setAttribute("msg2", "The user does not exist, please reenter the information!"); 25 rd.forward(request, response); 26 } 27 }
6.判断注册用户时,学号是否已存在(学号唯一),不符合要求则返回前台,给出提示。
后台代码
1 private void Register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 2 RequestDispatcher rd = null; 3 UserDao userdao = new UserDaoImpl(); 4 if (userdao.SelectUserBystudentName(request.getParameter("studentNumber")) != null) { 5 request.setAttribute("msg1", "用户名已经存在,请重新注册!!!"); 6 request.setAttribute("msg2", "The user name already exists, please reregister.!!!"); 7 rd = request.getRequestDispatcher(WebContents.REGISTER); 8 rd.forward(request, response); 9 } else { 10 User user = new User(); 11 user.setUsername(request.getParameter("username")); 12 user.setStudentNumber(request.getParameter("studentNumber")); 13 user.setPassword(request.getParameter("password")); 14 System.out.println(user); 15 if (user != null) 16 if (!user.getPassword().equals("")) { 17 userdao = new UserDaoImpl(); 18 userdao.AddUser(user); 19 request.setAttribute("msg1", "注册成功,请登录!!!"); 20 request.setAttribute("msg2", "Registration is successful, please login.!!!"); 21 rd = request.getRequestDispatcher(WebContents.LOGIN); 22 rd.forward(request, response); 23 } else { 24 rd = request.getRequestDispatcher(WebContents.REGISTER); 25 request.setAttribute("msg1", "输入信息不完全,请重新输入!!!"); 26 request.setAttribute("msg2", "The input information is incomplete,please reenter the information.!!!"); 27 rd.forward(request, response); 28 } 29 else { 30 rd = request.getRequestDispatcher(WebContents.REGISTER); 31 request.setAttribute("msg1", "输入信息不完全,请重新输入!!!"); 32 request.setAttribute("msg2", "The input information is incomplete,please reenter the information.!!!"); 33 rd.forward(request, response); 34 } 35 }
7.展示登录用户做题的历史记录。
后台代码:
1 private void ListUserScore(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException { 2 List<UserScore> list = new ArrayList<UserScore>(); 3 RequestDispatcher rd = null; 4 HttpSession session=request.getSession(); 5 UserScoreDao userScoreDao =new UserScoreDaoImpl(); 6 String sNo = (String) session.getAttribute("studentNumber"); 7 list = userScoreDao.InquiryBystudentNumber(sNo); 8 request.setAttribute("list",list); 9 rd = request.getRequestDispatcher(WebContents.SNO); 10 rd.forward(request,response); 11 }
具体页面展示:
1.index.jsp(确定页面的语言)
2.login.jsp(用户登录)
若输入错误,将提示:
3.register.jsp(用户注册)
若不符合要求,进行提示:
4.welcome.jsp ( 选择功能)
5.Algo.jsp(生成题目)
&nb 以上是关于结对项目的主要内容,如果未能解决你的问题,请参考以下文章