这个作业属于哪个课程 | 软件工程23春季学期社区 |
---|---|
这个作业要求在哪里 | <软件工程实践第二次作业—文件读取> |
这个作业的目标 | 收集<澳大利亚网球公开赛>的相关数据、实现一个能够对赛事数据进行统计的控制台程序 |
其他参考文献 | 《构建之法》、CSDN博客 |
Gitcode项目地址
PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
• Estimate | • 估计这个任务需要多少时间 | 20 | 30 |
Development | 开发 | 400 | 500 |
• Analysis | • 需求分析 (包括学习新技术) | 200 | 300 |
• Design Spec | • 生成设计文档 | 80 | 60 |
• Design Review | • 设计复审 | 30 | 30 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
• Design | • 具体设计 | 30 | 50 |
• Coding | • 具体编码 | 480 | 500 |
• Code Review | • 代码复审 | 60 | 50 |
• Test | • 测试(自我测试,修改代码,提交修改) | 100 | 90 |
Reporting | 报告 | 100 | 120 |
• Test Repor | • 测试报告 | 10 | 10 |
• Size Measurement | • 计算工作量 | 30 | 40 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 1600 | 1850 |
解题思路描述
数据处理
-
获取数据
题目要求从<澳大利亚网球公开赛>上获取数据,步骤是从浏览器右键选择底部的检查,再进去找到网络,输入players和result刷新后得到请求的url,截取得到的字符串保存得到相应的json数据。- 这边示例Q1数据的获取
*Q1数据
- 这边示例Q1数据的获取
- 分析数据
获取json数据之后对这部分数据进行分析,我使用的是阿里巴巴的fastjson,从网站上下载相应的jar包,并且建立依赖。
功能实现思路
-
json解析
-
players的输出
players指令的输出是作业的第一题,也是最简单的起手。首先我们需要观察players.json数据文件,观察通过键值直接获取player对象数组,再从这个数组中循环得到player对象,再根据键值输出相应需要输出的数据,并且关注输出格式。
-
result的输出
result的输出则包含了日期的比赛结果和Q1 Q2 Q3 Q4的比赛结果,但是都是大同小异的。这次的题目则难度大于上一个单单输出players,我们需要先从当日比赛的队伍中找到对应的胜利的队伍,并且根据胜利队伍的id从players.json里找到相应的队伍,再从队伍里的选手id匹配相应的选手,再输出相应的信息。
接口设计和实现过程
AOSearch 完成命令的读入,以及完成错误的输出
public static String readJsonFile(String fileName) 完成json数据的获取
public static String OutResult(String function) 传入命令,获取对应json文件,解析json数据,输出比赛结果
public static String OutPlayers() 解析json数据,输出选手信息
public static void writeTxt(String txtPath,String content) 输出数据到output.txt
public static List readStringFromtxt(String txtpath) 从input.Txt获取命令
关键代码展示
public static void OutPlayers(){ //输出选手信息
//String path = StyleUtil.class.getClassLoader().getResource("test.json").getPath();
String path = "222000125/src/Data/players.json";
String str = readJsonFile(path);
JSONObject jsonObj = JSON.parseObject(str);
JSONArray players = jsonObj.getJSONArray("players");
String infop="";
for (Object player : players) {
JSONObject play =(JSONObject)player;
// System.out.print("full_name:");
// System.out.println(play.getString("full_name"));
infop += "full_name:";
infop += play.getString("full_name");
infop += "\n";
// JSONObject play =(JSONObject)player;
// System.out.print("gender:");
// System.out.println(play.getString("gender"));
infop += "gender:";
infop += play.getString("gender").equals("M")?"male":"female";
infop += "\n";
JSONObject nationality = play.getJSONObject("nationality");
// System.out.print("nationality:");
// System.out.println(nationality.getString("name"));
infop += "nationality:";
infop += play.getString(nationality.getString("name"));
infop += "\n";
infop += "-----\n";
}
writeTxt("222000125/src/output.txt",infop);
}
public static void writeTxt(String txtPath,String content){ //输出相应的信息到output.Txt
FileOutputStream fileOutputStream = null;
File file = new File(txtPath);
try {
if(file.exists()){
//判断文件是否存在,如果不存在就新建一个txt
file.createNewFile();
}
fileOutputStream = new FileOutputStream(file,true);
fileOutputStream.write(content.getBytes());
fileOutputStream.flush();
fileOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void OutResult(String function){ //输出比赛信息
String path = "222000125/src/Data/";
String[] strs = function.split(" ");
strs[1] += ".json";
path += strs[1];//生成对应的日期的json文件地址 ,通过拼接形成对应的json文件地址
String str = readJsonFile(path);
JSONObject jsonObj = JSON.parseObject(str);
JSONArray matches = jsonObj.getJSONArray("matches"); //获得matches数组
String t1,t2,t3,t4,t5,t6; //用于存放比赛分值
String []arr = new String[2];
String infor="";
for (Object match : matches){
JSONObject matc = (JSONObject)match;
JSONObject match_status = matc.getJSONObject("match_status"); //得到对象
JSONArray team = matc.getJSONArray("teams"); //得到team数组
// JSONObject score =team.getJSONArray();
if(match_status.getString("abbr").equals("W/O")){ //弃赛判断
System.out.println("W/O");
infor += "W/O";
System.out.println("-----");
infor += "\n";
}
else{ //输出比赛时间
System.out.print("time:");
System.out.println(matc.getString("actual_start_time"));
infor += "time:";
infor += matc.getString("actual_start_time");
infor += "\n";
------------
if(tm1.containsKey("status")){ //说明第一个队伍对象是胜者
teamId = tm1.getString("team_id");
for(Object teamss :teams){
JSONObject teamsss = (JSONObject)teamss;
if(teamsss.getString("uuid").equals(teamId)){ //将获胜队伍与play表里的队伍uuid匹配
for (Object player : players) {
JSONObject play = (JSONObject) player;
//寻找相应的选手 并且强制先寻找第一个if语句也就是数组的第一个元素
if (playuidA.getString(0).equals(play.getString("uuid"))) {
System.out.print(play.getString("short_name")); //注意需要输出缩写
infor += play.getString("short_name");
n = 1;
}
else if(n==1 && playuidA.size()==2 && playuidA.getString(1).equals(play.getString("uuid"))){
System.out.print(" & ");
infor += " & ";
System.out.print((play.getString("short_name")));
infor += play.getString("short_name");
n = 100;
}
}
}
独到之处:这段代码运行时发现,选手输出顺序有时会混乱,双打前后部分。
所以在寻找选手时我使用了类似互斥锁思想的设计,让程序必须先查找获取的第一个选手,
再查找第二个选手。
下边是代码
int n = 100; //定义用于后边选手搜索顺寻的先后
for (Object player : players) {
JSONObject play = (JSONObject) player;
//寻找相应的选手 并且强制先寻找第一个if语句也就是数组的第一个元素
if (playuidA.getString(0).equals(play.getString("uuid"))) {
System.out.print(play.getString("short_name")); //注意需要输出缩写
infor += play.getString("short_name");
n = 1;
}
else if(n==1 && playuidA.size()==2 && playuidA.getString(1).equals(play.getString("uuid"))){
System.out.print(" & ");
infor += " & ";
System.out.print((play.getString("short_name")));
infor += play.getString("short_name");
n = 100;
}
}
性能改进
使用caffeine.jar,使用cache,对找到的数据进行缓存,下次若再需使用这个数据,则直接取用不用再解析json数据。这样代码运行的速度提高了很多。
运行一条
运行一千条
单元测试
提高覆盖率要尽可能覆盖到程序中不同的分支结构,Lib类中有一些处理流异常的指令无法覆盖到,所以Lib类的覆盖率会相对低一点
异常处理
- AOSearch.java(命令行参数异常处理)
if(parts.length==1) {
if (!parts[0].equals("players")&&!parts[0].equals("result")) {
info += "Error\n" + "-----\n";
Fun.writeTxt("output.txt", info);
// Fun.OutPlayers();
} else if(parts[0].equals("result")){
info+="N/A\n"+"-----\n";
Fun.writeTxt("output.txt",info);
} else {
if (cache.getIfPresent(comd) == null) { //如果缓存中没有这条指令则将其存入缓存
info = Fun.OutPlayers();
cache.put(comd, info);
} else info=cache.getIfPresent(comd);//如果缓存中存在这条指令则从缓存中获取
// info = Fun.OutPlayers();
Fun.writeTxt("output.txt",info);
}
}
// parts[0].equals("result")
else if (parts.length>=2) {
if(!parts[0].equals("result")){
info += "Error\n" + "-----\n";
Fun.writeTxt("output.txt", info);
}
else if (parts.length>2){
info+="N/A\n"+"-----\n";
Fun.writeTxt("output.txt",info);
}
else if (!Fun.judgeRight(parts[1])) {
info+="N/A\n"+"-----\n";
Fun.writeTxt("output.txt",info);
}
else if (Fun.judgeRight(parts[1])) {
if(cache.getIfPresent(comd) == null) {
info = Fun.OutResult(comd);
cache.put(comd, info);
}else info=cache.getIfPresent(comd);
// info = Fun.OutResult(comd);
Fun.writeTxt("output.txt",info);
- Fun.java(文件打开异常)
try {
File jsonFile = new File(fileName);
FileReader fileReader = new FileReader(jsonFile);
Reader reader = new InputStreamReader(new FileInputStream(jsonFile),"utf-8");
int ch = 0;
StringBuffer sb = new StringBuffer();
while ((ch = reader.read()) != -1) {
sb.append((char) ch);
}
fileReader.close();
reader.close();
jsonStr = sb.toString();
return jsonStr;
} catch (IOException e) {
e.printStackTrace();
return null;
}
心得体会
在刚开始拿到这个题目的时候,我确实是没有什么思路的,但是在一些已经开始写代码的同学的解释下,我清楚了这次作业的整个流程以及拥有了一个大概的思路。
这次作业的难度所在在于第一次真正的去这样像模像样的去完成一个功能,其中有着之前没有接触过的东西,在从零到一的路上,我学会了使用Java去解析复杂的json数据,自己从网络上爬取相应的json数据,学会了使用fastjson去解析数据,理清复杂的json数据内的取数据的流程。以及封装自己的代码,尝试着去优化自己的代码,进行单元测试,测试覆盖率。
总之在这次作业,我明白了自己拥有的技术栈的缺陷,以及理解需求能力和,自学能力的不足。在以后的学习中,我应该更注重编码的规范,技术栈的扩展,只有会的多自学能力才能慢慢提高。以后遇到这样的问题才能更加的得心应手。