685
社区成员
这个作业属于哪个课程 | 2023年福大-软件工程实践-W班 |
---|---|
这个作业要求在哪里 | 软件工程实践第二次作业——个人实战 |
这个作业的目标 | 1.完成代码编写并进行测试。2.撰写博客。 |
其他参考文献 | Java性能优化 ; Java Gson教程 ;Java文本逐行读取及效率对比 |
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 50 |
• Estimate | • 估计这个任务需要多少时间 | 30 | 50 |
Development | 开发 | 620 | 1000 |
• Analysis | • 需求分析 (包括学习新技术) | 80 | 120 |
• Design Spec | • 生成设计文档 | 40 | 60 |
• Design Review | • 设计复审 | 20 | 30 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
• Design | • 具体设计 | 60 | 120 |
• Coding | • 具体编码 | 300 | 500 |
• Code Review | • 代码复审 | 40 | 60 |
• Test | • 测试(自我测试,修改代码,提交修改) | 60 | 80 |
Reporting | 报告 | 60 | 90 |
• Test Repor | • 测试报告 | 20 | 30 |
• Size Measurement | • 计算工作量 | 15 | 30 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 25 | 30 |
合计 | 710 | 1140 |
一开始并不知道怎么爬取数据,后来经过百度了解到可以利用浏览器的开发者工具进行数据爬取。
首先,进入澳大利亚网球公开赛官网,找到schedule栏,选择要爬取的赛事日期,按F12打开浏览器开发者工具,选择“网络”,等待响应,点击schedule文件名,右边会出现json格式的数据。
然后双击schedule文件名,会出现新页面,点击“原始数据”,选择“美化输出”,就可以把数据按美化输出后的样式保存成json文件。
这次作业编码重点就是读json文件,将所需的数据输出。因为之前在学习Android时用过gson,所以我打算继续用第三方库gson来解析json文件。大概思路就是建player类,schedule类,然后用gson反序列化得到相应的对象,最后输出。但是没想到的是实际编码过程中发现json文件里数据是比较复杂的,就干脆用JsonObject和JsonArray一层一层获取所需的数据。
一是读输入的指令文件input.txt,打算按行读取每条指令,用String类的split函数对每条指令进行处理,然后判断指令的正确性,最后执行指令。
二是写结果文件output.txt,考虑到每条指令执行都有各自的结果,就先将结果存在一个字符串数组,最后一起写进output文件。
//主程序,包含main方法
public class AOSearch {...}
//Lib类,包含自定义函数
public class Lib {...}
//Player类,存放运动员相关信息
public class Player {...}
//Scores类,存放每个队的比赛成绩
public class Scores {...}
//Team类,存放每个队的信息
public class Team {...}
//Lib类,包含自定义函数
public class Lib {
//读指令文件input.txt
public static boolean readInputTxt(String file) throws IOException {...}
//判断每条指令的正确性
public static String isRightInstruction(String s) {...}
//判断result指令后日期是否正确
public static boolean isRightDate(String s) {...}
//执行指令
public void runInstruction() throws IOException {...}
//读取json文件
public String readJson(String s) throws IOException {...}
//获取运动员信息
public void getPlayers(String s) {...}
//获取赛事信息
public void getSchedule(String s) {...}
//获取胜利队伍的成员信息
public void getWinPlayers(JsonObject jsonObject,ArrayList<String> winteam,HashMap<String, ArrayList> Sites) {...}
//按格式输出时间及对应的比赛队伍成绩
public void showScheduleForm(ArrayList<Team> tm,ArrayList<String> time,ArrayList<String> winteam,HashMap<String, ArrayList> Sites) {...}
//获取要写入文件的结果
public ArrayList<String> getResults() {...}
//将结果写入文件
public void writeToFile(String file) throws IOException {...}
}
public class Player {
private String full_name; //全名
private String gender; //性别
private String nationality; //国籍
public Player(String s1,String s2,String s3){
full_name=s1;
gender=s2;
nationality=s3;
}
@Override
public String toString() {...}
...//及set、get方法
public class Scores {
private String set,game; //场次、得分
private boolean winner; //是否胜利
public Scores(String set,String game,boolean winner){
this.set=set;
this.game=game;
this.winner=winner;
}
...//及set、get方法
public class Team {
private String status=null; //状态
private String team_id; //队名id
private ArrayList<Scores> scoresArrayList; //成绩
public Team(){
scoresArrayList=new ArrayList<Scores>();
}
...//及set、get方法
1、我觉得本次作业关键点是对于赛事结果的获取,里面的细节点有这些:
//获取胜利队成员名字
public void getWinPlayers(JsonObject jsonObject,ArrayList<String> winteam,HashMap<String, ArrayList> Sites) {
//取获胜队的成员
JsonArray teamArray = jsonObject.getAsJsonArray("teams");
for (String s : winteam) {
for (JsonElement ta : teamArray) {
JsonObject jsonObject1 = ta.getAsJsonObject();
String uuid = jsonObject1.get("uuid").getAsString();
//判断是否是获胜队
if (uuid.equals(s)) {
//取出成员编号
JsonArray memberArray = jsonObject1.get("players").getAsJsonArray();
ArrayList<String> members = new ArrayList<String>();
for (JsonElement ma : memberArray) {
members.add(ma.getAsString());
}
Sites.put(uuid, members);
}
}
}
//在player数组找成员名字
JsonArray playerArray = jsonObject.getAsJsonArray("players");
ArrayList tmp;
//player
for (JsonElement pa : playerArray) {
JsonObject jsonObject1 = pa.getAsJsonObject();
String playeruuid = jsonObject1.get("uuid").getAsString();
for (String i : Sites.keySet()) {
tmp = Sites.get(i);
for (int j = 0; j < tmp.size(); j++) {
//找到名字就替换成员编号
if (tmp.get(j).equals(playeruuid)) {
tmp.set(j, jsonObject1.get("short_name").getAsString());
}
}
Sites.replace(i, tmp);
}
}
}
以上获取成员名字缩写思路就是:将获胜队伍id与该队伍成员id用HashMap的方式进行匹配,然后再取查询成员id对应得名字缩写,替换id,目的是为了队伍id与队伍成员名字缩写相匹配。
public void showScheduleForm(ArrayList<Team> tm,ArrayList<String> time,ArrayList<String> winteam,HashMap<String, ArrayList> Sites) {
int p = 0;
//先按时间顺序
StringBuilder sb;
for (int i = 0; i < time.size(); i++) {
sb = new StringBuilder();
if (time.get(i).equals("no")) {
sb.append("W/O\n-----\n");
} else {
sb.append("time:").append(time.get(i)).append("\nwinner:");
//找胜利队成员
int b = 0;
if (Sites.get(winteam.get(i)) != null) {
for (int m = 0; m < Sites.get(winteam.get(i)).size(); m++) {
sb.append(Sites.get(winteam.get(i)).get(m));
if (b != Sites.get(winteam.get(i)).size() - 1) {
sb.append(" & ");
b++;
}
}
sb.append("\nscore:");
int m = 0;
//按2个队伍一组,输出2队之间成绩
for (int j = 0; j < tm.get(p).getScore().size(); j++) {
sb.append(tm.get(p).getScore().get(j)).append(":").append(tm.get(p + 1).getScore().get(j));
if (m != tm.get(p).getScore().size() - 1) {
sb.append(" | ");
m++;
}
}
sb.append("\n-----\n");
p = p + 2;
}
results.add(sb.toString());
}
}
}
以上按格式输出赛事的思路就是:首先,已经提前把时间和获胜队伍id分别存储在字符串数组里,这样就可以输出格式前两行的time和winner,对于特殊情况“弃赛”就直接输出“W/O”;接下来,先前读取赛事时把所有队伍id也存储在字符串数组里,就是按两个队伍为一组,将成绩根据场次顺序输出来。这样一个时间段的比赛情况就按格式整理好了。
1、在循环输出赛事结果时,字符串连接时使用StringBuilder/StringBuffer的append方法代替字符串的“+”号连接,提高效率。
2、在循环遍历JsonArray时不要不断创建JsonObject对象引用,节省内存空间,如:
1、部分测试代码
@Test
void isRightInstructionTest() { //判断指令是否正确
assertEquals("players",Lib.isRightInstruction("players"));
assertEquals("Error",Lib.isRightInstruction("Player"));
assertEquals("N/A",Lib.isRightInstruction("result"));
assertEquals("Error",Lib.isRightInstruction("result0116"));
assertEquals("N/A",Lib.isRightInstruction("result 0133"));
assertEquals("N/A",Lib.isRightInstruction("result sss"));
assertEquals("N/A",Lib.isRightInstruction("result 117"));
assertEquals("0116",Lib.isRightInstruction(" result 0116"));
assertEquals("Q2",Lib.isRightInstruction("result Q2"));
assertEquals("Error",Lib.isRightInstruction("re"));
assertEquals("N/A",Lib.isRightInstruction(" result players"));
}
@Test
void getPlayerTest() throws IOException {
Lib lib1=new Lib();
lib1.getPlayers(lib1.readJson("players"));
assertNotNull(lib1.getResults());
}
2、单元测试覆盖率
1、命令行参数个数的错误
2、文件不存在
3、文件读写的异常
有所准备才能有所收获