688
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | <2023年福大-软件工程实践-W班社区> |
|---|---|
| 这个作业要求在哪里 | <软件工程实践第二次作业——个人实战> |
| 这个作业的目标 | <完成对澳大利亚网球公开赛相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序> |
| 其他参考文献 | 《构建之法》 |
https://gitcode.net/m0_52688898/project-java
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 20 | 20 |
| • Estimate | • 估计这个任务需要多少时间 | 20 | 20 |
| Development | 开发 | 800 | 850 |
| • Analysis | • 需求分析 (包括学习新技术) | 60 | 70 |
| • Design Spec | • 生成设计文档 | 20 | 30 |
| • Design Review | • 设计复审 | 20 | 20 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
| • Design | • 具体设计 | 30 | 40 |
| • Coding | • 具体编码 | 200 | 300 |
| • Code Review | • 代码复审 | 30 | 40 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 100 | 120 |
| Reporting | 报告 | 100 | 80 |
| • Test Repor | • 测试报告 | 50 | 50 |
| • Size Measurement | • 计算工作量 | 10 | 10 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 50 |
| 合计 | 1540 | 1730 |
经过对第二次作业的反复查看, 大致定下了项目开发的整体流程, 确定编写语言、开发环境、第三方库(fastjson)
第二次作业简单来讲是让我们使用编程语言对JSON文件进行读写操作, 从文件中获取所需的信息, 并将其输出, 所以数据文件的获取是第一步工作
①进入澳大利亚网球公开赛官网(https://ausopen.com/)
②打开开发者模式, 载入页面时可以看到从服务器请求的JSON文件,分别搜索players与results即可找到相应的文件
③预览文件, 复制文件内容到相应json文件中即可完成爬取
④重复以上几个步骤, 将所需的数据都下载下来
使用fastjson第三方库, 快速遍历解析文件
通过解析players.json文件, 从“players”数组 中获取 "full_name"、“gender”、“nationality” 等属性的值
通过结果信息文件, 从matches中读出 "actual_start_time"
从"teams"中读取status为"WInner"的队伍的"team_id", 从"score" 中读取分数
然后再根据"team_id"从teams中找到相应的"team", 再从中读取player的uuid
再去players中找到相应的选手, 这一部分功能的实现是整个程序的难点

主要包含了 AOSearch类与Lib类
其中AOSearch类负责实现对命令行参数的解析与异常处理分析,并读取"input.txt文件中的内容", 对指令正确与否进行判断, 同时将正确的指令交予Lib中的方法进行处理
Lib中主要由 "doResult" 和 "doPlayers" 两个静态方法, 分别用于处理 result指令 与 players指令
主函数代码
public static void main(String[] args) {
if (args.length != 2) {
throw new IllegalArgumentException("命令行参数需包含输入文件与输出文件且数量为2");
}
FileReader fr = null;
BufferedReader br = null;
try {
Lib.setOutPutFile(args[1]);
Lib.createEmptyFile();
File f = new File(args[0]);
try {
fr = new FileReader(f);
} catch (FileNotFoundException e) {
System.out.println("输入文件未找到: " + e.getMessage());
System.exit(0);
}
br = new BufferedReader(fr);
String line = null;
try {
while ((line = br.readLine()) != null) {
line = line.trim();
if (!line.equals("")) {
String[] params = line.split(" "); // 将一行的指令分解成多个参数分析
if (params.length > 2) { // 指令参数数量错误
if (params[0].equals("result")) {
Lib.writeToFile("N/A\n-----\n");
} else {
Lib.writeToFile("Error\n-----\n");
}
} else if (params.length == 2) {
if (!params[0].equals("result")) {
Lib.writeToFile("Error\n-----\n");
} else if (!Arrays.asList(Lib.DATE).contains(params[1])) {
Lib.writeToFile("N/A\n-----\n");
} else { // 处理 result 指令
Lib.doResult(params[1]);
}
} else if (params.length == 1) {
if (params[0].equals("result")) {
Lib.writeToFile("N/A\n-----\n");
} else if (!params[0].equals("players")) {
Lib.writeToFile("Error\n-----\n");
} else { // 处理 players 指令
Lib.doPlayers();
}
}
}
}
} catch (IOException e) {
System.out.println("IO读写错误:" + e.getMessage());
}
} finally {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
处理指令的两个方法
// 处理 result指令
public static void doResult(String date) throws IOException{
if(maps.containsKey(date)){
writeToFile(maps.get(date));
return;
}
String json = getJson(PATH+ date +".json");
JSONObject jo = JSONObject.parseObject(json);
JSONArray matches = JSONArray.parseArray(jo.getString("matches"));
JSONArray teamArr = JSONArray.parseArray(jo.getString("teams"));
JSONArray players = JSONArray.parseArray(jo.getString("players"));
StringBuilder matchInfo = new StringBuilder();
for (Object m : matches) {
JSONObject match = (JSONObject) m;
// 判断是否有弃赛
JSONObject match_status = JSONObject.parseObject(match.getString("match_status"));
if (match_status.getString("abbr").equals("W/O")){
matchInfo.append("W/O\n-----\n");
continue;
}
// 获取比赛时间
String time = match.getString("actual_start_time");
matchInfo.append("time:"+time+"\n");
// 获取参赛的两只队伍以及获胜的队伍
JSONArray teams = JSONArray.parseArray(match.getString("teams"));
JSONObject team1 = teams.getJSONObject(0);
JSONObject team2 = teams.getJSONObject(1);
JSONObject winTeam = team1.getString("status") != null ? team1 : team2;
String team_id = winTeam.getString("team_id");
// 根据team_id 查找获胜的队伍
JSONObject winnerTeam = findWinnerTeam(teamArr, team_id);
if (winnerTeam != null) {
// System.out.println(winnerTeam.getString("players"));
JSONArray winners = findWinner(players, winnerTeam.getString("players"));
// 获取获胜选手名
matchInfo.append("winTeam:");
for (int i = 0;i < winners.size(); i++){
JSONObject winPlaer = winners.getJSONObject(i);
matchInfo.append(winPlaer.getString("short_name"));
if (i < winners.size() - 1)
matchInfo.append(" & ");
}
matchInfo.append("\n");
}
// 获取比赛分数
JSONArray scores1 = JSONArray.parseArray(team1.getString("score"));
JSONArray scores2 = JSONArray.parseArray(team2.getString("score"));
matchInfo.append("score:");
for (int i = 0; i < scores1.size(); i++) {
JSONObject score1 = scores1.getJSONObject(i);
JSONObject score2 = scores2.getJSONObject(i);
matchInfo.append(score1.getString("game") + ":" + score2.getString("game"));
if (i < scores1.size() - 1) {
matchInfo.append(" | ");
}
}
matchInfo.append("\n-----\n");
}
maps.put(date,matchInfo.toString());
writeToFile(matchInfo.toString());
}
// 处理 players指令
public static void doPlayers() throws IOException{
if(maps.containsKey("players")){
writeToFile(maps.get("players"));
return;
}
String json = getJson(PATH+"players.json");
JSONObject jo = JSONObject.parseObject(json);
JSONArray players = JSONArray.parseArray(jo.getString("players"));
StringBuilder playerInfo = new StringBuilder();
for (Object p : players) {
JSONObject player = (JSONObject) p;
String full_name = player.getString("full_name");
String gender = player.getString("gender").equals("M") ? "male" : "female";
String nationality = player.getJSONObject("nationality").getString("name");
playerInfo.append("full_name:" + full_name + "\n");
playerInfo.append("gender:" + gender + "\n");
playerInfo.append("nationality:" + nationality + "\n-----\n");
}
maps.put("players",playerInfo.toString());
writeToFile(playerInfo.toString());
}
- 对连续的字符串拼接采用了 StringBuilder 来加速字符串的拼接
- 对先前已经处理过的指令,对其输出结果进行缓存处理,下次遇到相同指令时可以直接读出
- 尽量减少了对程序的IO次数, 增加了程序的可读性
设置了11个输入案例测试测试

覆盖率测试

参数数目不匹配的异常处理
由于用户可以自定义输入参数, 需要对输入参数进行严格的检查处理,程序中使用了try-catch进行代码检查处理,
对于非players或result开头的指令, 将输入 Error, 而result后参数不符合要求的指令, 将输入 N/A
IO异常处理
由于程序中多次涉及文件的IO操作, 容易引发IOException, 故程序对文件的读写.关闭都做了捕获处理
本次软工作业, 整体难道上来说难度不会太高, 尤其是在拥有第三方库帮助解析的情况下, 代码开发得到了事半功倍, 但由于有些日子没有书写Java代码, 对IO类的驾驭不够熟练, 从本次的项目开发中, 重新回忆起了过往学习的知识点。并且对于单元测试与异常处理已经PSP表格制造有了一定的初步了解
考虑执行几万行有效指几十万行指令的情况下,程序的实现是否依然能有效执行?在这个前提下谈谈你的优化~