这个作业属于哪个课程 | <2023年福大-软件工程实践-W班> |
---|---|
这个作业要求在哪里 | <软件工程实践第二次作业——个人实战> |
这个作业的目标 | <完成对澳大利亚网球公开赛相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序> |
其他参考文献 | 邹欣老师的博客:单元测试和回归测试 邹欣老师的博客:源代码管理 |
文章目录
作业基本信息…
一、Gitcode项目地址
二、PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 40 |
• Estimate | • 估计这个任务需要多少时间 | 30 | 35 |
• Estimate | 开发 | 400 | 430 |
• Analysis | • 需求分析 (包括学习新技术) | 60 | 40 |
• Design Spec | • 生成设计文档 | 60 | 60 |
• Design Review | • 设计复审 | 30 | 20 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
• Design | • 具体设计 | 60 | 150 |
• Coding | • 具体编码 | 120 | 140 |
• Code Review | • 代码复审 | 120 | 100 |
• Test | • 测试(自我测试,修改代码,提交修改) | 120 | 180 |
Reporting | 报告 | 60 | 120 |
• Test Repor | • 测试报告 | 60 | 60 |
• Size Measurement | • 计算工作量 | 60 | 40 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 1260 | 1465 |
三、解题思路描述
1.获取数据
其中一部分数据:
选手数据(players.txt)
1月16日——1月22日赛事结果数据(0116.json、0117json……0122.json)
为教师下发的数据,直接从教师上传的压缩包下载
剩下的数据由自己爬取,爬取方式:
1.1打开赛事官网
1.2进入赛事结果专栏
点击result进入赛事结果专栏
1.3在该页面利用开发者工具进行读取
按F12进入开发者工具,若有自行修改过快捷方式,则自行打开,或从浏览器设置里面进入
点击网络——Fetch/XHR
在下方找到result,result为结果数据
然后在右侧点击相应,下方的代码即该天赛果数据对应的json文件,复制黏贴保存为.txt文件即可
2.查询所有选手信息
利用maven项目解析json数据,maven环境配置好后,利用JSONObject打开相对应的文件,从文件中用循环结构对选手表进行遍历,并逐个输出选手的姓名、性别、国籍。
3.查询某一天的赛果
由命令知道需要获取哪一天的赛果,利用JSONObject打开相对应的赛事结果文件,从文件中用循环结构对该天所有比赛进行遍历,每场比赛的实际比赛时间可以直接得到。json文件中胜利的队伍status为winner,对每一个status为winner的队伍id进行记录,再在该天中参赛队伍中进行查询,查询该天获胜队伍中的参赛队员名单,由此得到这天该场比赛的胜利队员姓名,若为团体比赛,则对两名选手都进行名字输出。具体比分则对每一小场双方的得分逐一输出即可。
4.复合查询
将上述两个功能进行复合使用,只要解决如何处理命令行的多行命令输入即可,我选择按行读取,每行再拆成每个单词,每一行作为一个新的命令,若命令复合要求则找到相对应的功能,若改行命令不符合要求,则输出Error或N/A。若能输出,则为追加输出,即后面的指令输出将会打印在后面。
四、接口设计和实现过程
由于本次作业要求有两个主要功能(1.查询所有选手信息,2.查询某一天的赛事结果)因此把这两个功能分开写,其中在写的过程中注意到输出文件output.txt需要用到追加写的方式,后来由重新封装了一个函数append(String path, String context),path为需要保存的文件路径名,context为需要追加到该文件的内容,若不存在这个文件,则会在目标路径新建该文件。两个功能的函数形参结构如:function(String path, String commond),path为输出文件output.txt需要保存的路径,commond为相应的指令,在main函数阶段先对指令commond进行初步分类,作为实参进入函数后再进一步判断指令的内容喝正确性。
五、关键代码展示
向文件追加内容
public static void append(String file, String conent) {
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(file, true)));
out.write(conent);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出所有选手
public static void output_players(String path, String commond) throws IOException {
//打开文件
if(commond.equals("players")){
File players_file = new File(AOSearch.players_path);
String content = FileUtils.readFileToString(players_file, "UTF-8");
JSONObject jsonObject = new JSONObject(content);
for (int i = 0; i < jsonObject.getJSONArray("players").length(); i++) {
append(path, "full_name:" + jsonObject.getJSONArray("players").getJSONObject(i).getString("full_name") + "\n");
if (jsonObject.getJSONArray("players").getJSONObject(i).getString("gender").equals("M"))
append(path, "gender:male" + "\n");
if (jsonObject.getJSONArray("players").getJSONObject(i).getString("gender").equals("F"))
append(path, "gender:female" + "\n");
append(path, "nationality:" + jsonObject.getJSONArray("players").getJSONObject(i).getJSONObject("nationality").getString("name") + "\n");
append(path, "-----" + "\n");
}
}else{
append(path, "Error\n-----\n");
}
}
输出某一天的赛事结果
public static void output_result(String path, String commond) throws IOException {
//path是目标存放文件,即output.txt
//commond是指令
String[] commondword = commond.split(" ");
if ((commondword[0].equals("result") && commondword[1].charAt(0) == '0' && Integer.parseInt(commondword[1].substring(1, 4)) >= 116 && Integer.parseInt(commondword[1].substring(1, 4)) <= 129) || (commondword[0].equals("result") && commondword[1].equals("Q1") && commondword[1].equals("Q2") && commondword[1].equals("Q3") && commondword[1].equals("Q4"))) {
String result_path = "D:\\data\\SchoolFile\\StudyFile\\《软件工程》\\code\\project-java\\222000103\\src\\data\\schedule\\" + commondword[1] + ".json";
File result_file = new File(result_path);
String content = FileUtils.readFileToString(result_file, "UTF-8");//获取该日期比赛的所有信息
JSONObject jsonObject = new JSONObject(content);
for (int i = 0; i < jsonObject.getJSONArray("matches").length(); i++) {
append(path, "time:" + jsonObject.getJSONArray("matches").getJSONObject(i).getString("actual_start_time") + "\n");
String winteamid = "";
if (jsonObject.getJSONArray("matches").getJSONObject(i).getJSONArray("teams").getJSONObject(0).has("status")) {
//记录获胜队伍的id号
winteamid = jsonObject.getJSONArray("matches").getJSONObject(i).getJSONArray("teams").getJSONObject(0).getString("team_id");
} else {
winteamid = jsonObject.getJSONArray("matches").getJSONObject(i).getJSONArray("teams").getJSONObject(1).getString("team_id");
}
for (int j = 0; j < jsonObject.getJSONArray("teams").length(); j++) {
//找到此次比赛该队伍参赛的人员
if (winteamid.equals(jsonObject.getJSONArray("teams").getJSONObject(j).getString("uuid"))) {
String winnerid1 = jsonObject.getJSONArray("teams").getJSONObject(j).getJSONArray("players").getString(0);//参赛队员的名字
String winnerid2 = "";
if (jsonObject.getJSONArray("teams").getJSONObject(j).getJSONArray("players").length() >= 2) {//说明为团体比赛
winnerid2 = jsonObject.getJSONArray("teams").getJSONObject(j).getJSONArray("players").getString(1);
}
File players_file = new File(AOSearch.players_path);
String content_players = FileUtils.readFileToString(players_file, "UTF-8");
JSONObject jsonObject_players = new JSONObject(content);
for (int co = 0; co < jsonObject_players.getJSONArray("players").length(); co++) {
if (winnerid1.equals(jsonObject_players.getJSONArray("players").getJSONObject(co).getString("uuid"))) {
append(path, "winner:" + jsonObject_players.getJSONArray("players").getJSONObject(co).getString("short_name"));
}
}
for (int co = 0; co < jsonObject_players.getJSONArray("players").length(); co++) {
if (winnerid2.equals(jsonObject_players.getJSONArray("players").getJSONObject(co).getString("uuid"))) {
append(path, " & " + jsonObject_players.getJSONArray("players").getJSONObject(co).getString("short_name"));
}
}
append(path, "\n");
}
}
int set_number = jsonObject.getJSONArray("matches").getJSONObject(i).getJSONArray("teams").getJSONObject(0).getJSONArray("score").length();
for (int tmp = 0; tmp < set_number; tmp++) {
append(path, jsonObject.getJSONArray("matches").getJSONObject(i).getJSONArray("teams").getJSONObject(0).getJSONArray("score").getJSONObject(tmp).getString("game") + ':');
append(path, jsonObject.getJSONArray("matches").getJSONObject(i).getJSONArray("teams").getJSONObject(1).getJSONArray("score").getJSONObject(tmp).getString("game") + " | ");
}
append(path, "\n-----\n");
}
} else if(commondword[0].equals("result")){
append(path, "N/A\n-----\n");
} else {
append(path, "Error\n-----\n");
}
}
六、性能改进
利用buffer输出流加快输出速度。
buffer加入了缓冲技术,将字符读取对象作为参数。
BufferedWriter类将一个常量值作为默认缓冲区的大小,它同时也可以通过构造函数来指定大小。
七、单元测试
八、异常处理
在有异常处理需求的函数添加throw IOexception,对输入输出异常进行抛出。
在功能函数中对指令数据进行分析,不符合要求的执行将进行错误报告。
九、心得体会
本次作业我明白了如何爬取数据的.json文件,并且知道了如何解析数据,编写程序利用这些数据。一开始不知道所谓的爬虫,以为是一个很难很深奥的东西,经过本次作业,对爬数据有了大概的了解,虽然只能算略知一二,但自己心中大概对这项技术有了一定了解和掌握。本次作业用java编写程序,与往常不同的是要用命令行进行输入,几乎没有利用此方式进行输入的我一开始觉得犯难,对main函数的形参使用也有点忘记,但很快就能想起来,本次作业也让我温习了以往的很多其他知识。包括但不限于异常处理、数据的严谨性判断等。另外作业要求要有严谨的编写代码习惯,这也使得我开始注意代码编写的合理性,变量名的合理性。
本次作业还要求进行性能改进和单元测试,这两个模块以前并没有接触过,因此在这也碰壁不少,需要一直求助同学或者查询论坛及相关资料。经验不足做了许多南辕北辙的事情。时间上就显得更加匆忙。在今后,我会争取提前学习有关知识,防止在开始项目时遇到棘手的事情。