122
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | 2302软件工程社区 |
|---|---|
| 这个作业要求在哪里 | 软件工程第二次作业--文件读取 |
| 这个作业的目标 | 完成对世界游泳锦标赛跳水项目相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序 |
| 其他参考文献 | 工程师的能力评估和发展、阿里巴巴Java开发手册 |
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 30 | 20 |
| • Estimate | • 估计这个任务需要多少时间 | 30 | 30 |
| Development | 开发 | 700 | 630 |
| • Analysis | • 需求分析(包括学习新技术) | 180 | 160 |
| • Design Spec | • 生成设计文档 | 60 | 60 |
| • Design Review | • 设计复审 | 50 | 50 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 40 | 30 |
| • Design | • 具体设计 | 100 | 100 |
| • Coding | • 具体编码 | 420 | 400 |
| • Code Review | • 代码复审 | 120 | 100 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 140 | 120 |
| Reporting | 报告 | 120 | 120 |
| • Test Repor | • 测试报告 | 70 | 60 |
| • Size Measurement | • 计算工作量 | 70 | 60 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 50 |
| 合计 | 2190 | 1990 |

打开世界游泳锦标赛官网,点开F12,再进入运动员界面,获取json数据


首先对json文件的结构进行分析
athletes.json
从athletes.json文件中,我们可以获得我们所需要的运动员信息
接着是event文件
获得Rank,FullName等信息
从赛事文件中,我们可以获得相关信息DivePoint,FullName,TotalPoint,Gender等
使用第三方库Gson对json文件进行解析,可以使用Map,List等方法存储对象信息,或者使用手动方法帮助解析并存储信息。
在使用Gson方法前,要设计一个json转String的方法getJsonString
1.读取input.txt:使用List将文件中的指令存储下来,交给控制器使用
2.识别并运行指令:控制器controller读取指令并识别,根据判断结果使用不同的操作函数
3.写入文件:不同的操作函数,使用StringBuilder将结果写入文件output.txt中
程序组织架构,程序由多个类组成,包括getAthletes()获得运动员信息,getResults()获得比赛信息,getEventDetail()获得比赛详细信息,使用接口设计,将这三个方法封装起来。outputPlayers()输出运动员信息,outputError()输出Error,outputNA()输出N/A,outputResult()输出比赛信息,outputEventDetail()输出比赛详细信息。
我的思路是,readInput()读取指令并保存在List中,控制器controller读取指令并判断,根据指令走向不同的分支,DataSourceIml()继承DataSource(),实现了获得信息的相关函数,通过DataSourceIml()获得信息后传给输出函数,最后写入output.txt中。
其中的关键在于解析Json获得数据,因此我使用第三方库Gson来帮助解析Json,手动导入Gson jar包,要想使用Gson的fromJso()方法将Json转化成对象,我需要写一个方法getJsonString()将Json文件转成字符串,将Json转成对象后,可以使用手动建类或者是使用List
•分析json文件,获取字符串
getJsonString函数:
• 参数:json文件的路径
• 返回:json字符串
• 调用关系:被getAthletes(),getResults(),getEventDetail()函数调用;
public String getJsonString(String fileName) {
try {
File fp = new File(fileName);
if (!fp.exists()) {
fp.createNewFile();
}
String str;
StringBuilder sb = new StringBuilder();
//创建一个文件输入流,再创建一个BufferedReader对象,用来从文件输入流中读取数据
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fp), "UTF-8"));
while ((str = reader.readLine()) != null) {
sb.append(str);
}
reader.close();
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
•Gson解析字符串,获得运动员信息
getAtletes函数:
• 参数:无
• 返回:字符串
public String getAthletes() {
//如果hashMap中已有运动员信息
if (sites.containsKey("players")) {
return sites.get("players");
}
//String S = getJsonString("D:\\File\\study\\codechina\\project-java\\222100235\\src\\data\\athletes.json");
Gson gson = new Gson();
List<AthletesData> athletesData = gson.fromJson(getJsonString(athletesPath), new TypeToken<List<AthletesData>>() {
}.getType());
StringBuilder sb = new StringBuilder();
if (athletesData != null) {
for (AthletesData athletesData1 : athletesData) {
String country = athletesData1.getCountryName();
List<Participation> participations = athletesData1.getParticipations();
for (Participation part : participations) {
String gender = part.getGender() == 0 ? "Male" : "Female";
String firstName = part.getPreferredFirstName();
String lastName = part.getPreferredLastName();
sb.append("Full Name:" + lastName + " " + firstName + "\n");
sb.append("Gender:" + gender + "\n");
sb.append("Country:" + country + "\n");
sb.append("-----" + "\n");
}
}
}
sites.put("players", sb.toString());
return sb.toString();
}
•Gson解析字符串,获得比赛信息
getResults函数:
• 参数:指令字符串
• 返回:字符串
public String getResults (String cmd) {
//如果hashMap中已有比赛信息
if (sites.containsKey(cmd)) {
return sites.get(cmd);
}
Gson gson = new Gson();
// ResultData resultData = gson.fromJson(getJsonString(cmdNames.get(cmd)), ResultData.class);
Map map = gson.fromJson(getJsonString(cmdNames.get(cmd)),Map.class);
StringBuilder sb = new StringBuilder();
List<Map> heat = (List<Map>)map.get("Heats");
for(Map m : heat){
List<Map> results = (List<Map>)m.get("Results");
for (Map r : results){
double rank = (double) r.get("Rank");
sb.append("Full Name:" + r.get("FullName") + "\n");
sb.append("Rank:" + (int)rank + "\n");
sb.append("Score:");
List<Map> dives = (List<Map>)r.get("Dives");
List<String> points = new ArrayList<>();
int index = 0;
for (Map d : dives){
index++;
points.add((String) d.get("DivePoints"));
}
for (int i = 0;i < index;i++){
if (i < index - 1){
sb.append(points.get(i) + " + ");
}else {
sb.append(points.get(i) + " = ");
}
}
sb.append(r.get("TotalPoints") + "\n");
sb.append("-----" + "\n");
}
}
sites.put(cmd, sb.toString());
return sb.toString();
}
首先是加快指令查找,使用HashMap存储指令与json文件路径的对应关系,方便快速查找。
接着使用HashMap记录指令与输出的关系,这样在有多个相同指令的情况下,避免程序重复执行,加快运行速度,减少频繁的文件读取次数。
另一个需要改进的地方是可以使用BufferdWriter包装FileWriter作输入流,提高运行速度。
1.HashMap记录指令与Json文件的对应关系
static HashMap<String,String> cmdNames = new HashMap<String,String>(){
{
put("result men 1m springboard",resultPath6);
put("result men 3m springboard",resultPath9);
put("result men 3m synchronised",resultPath7);
put("result men 10m platform",resultPath3);
put("result men 10m synchronised",resultPath5);
put("result women 1m springboard",resultPath4);
put("result women 3m springboard",resultPath2);
put("result women 3m synchronised",resultPath8);
put("result women 10m platform",resultPath1);
put("result women 10m synchronised",resultPath0);
put("result men 1m springboard detail",resultPath6);
put("result men 3m springboard detail",resultPath9);
put("result men 3m synchronised detail",resultPath7);
put("result men 10m platform detail",resultPath3);
put("result men 10m synchronised detail",resultPath5);
put("result women 1m springboard detail",resultPath4);
put("result women 3m springboard detail",resultPath2);
put("result women 3m synchronised detail",resultPath8);
put("result women 10m platform detail",resultPath1);
put("result women 10m synchronised detail",resultPath0);
}
};
- 使用HashMap记录指令与输出结果的对应关系
/*
使用hashmap存储运动员和比赛信息
"player = 运动员信息"
*/
HashMap<String, String> sites = new HashMap<>();
/*
使用hashmap存储运动员信息
帮助输出比赛详细信息
*/
HashMap<String , AthleteClass> events = new HashMap<>();
- 使用BufferdWriter包装FileWriter作输入流
//创建一个文件输入流,再创建一个BufferedReader对象,用来从文件输入流中读取数据
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fp), "UTF-8"));
异常处理主要使用try...catch以及throw方法进行处理
输出函数中的异常处理
//输出Error
public void outputError(String fileName){
try{
File fp = new File(fileName);
if (!fp.exists()){
fp.createNewFile();
}
......
}catch (IOException e){
e.printStackTrace();
}
}
通过throw方法抛出异常,使用catch捕捉异常并处理
//读取input.txt文件内容,保存下来,准备下一步处理
public List<String> readInput(String fileName){
try{
File fp = new File(fileName);
if (!fp.exists()){
throw new FileNotFoundException(fileName + "文件不存在");
}
......
} catch (FileNotFoundException exception){
System.out.println(exception);
} catch (IOException e){
e.printStackTrace();
}
return null;
}
使用JUint进行单元测试,首先下载JUint jar包,再手动导入。接着建立一个Test包,建立一个单元测试类进行测试。
测试时使用覆盖率运行测试类
@Test
public void main() {
//正确
DWASearch.main(new String[]{"D:\\File\\study\\codechina\\project-java\\222100235\\src\\input.txt",
"D:\\File\\study\\codechina\\project-java\\222100235\\src\\output.txt"});
}
@Test
public void test(){
//参数错误
DWASearch.main(new String[]{"D:\\File\\study\\codechina\\project-java\\222100235\\src\\input.txt"});
}
@Test
public void test1(){
//参数错误
DWASearch.main(new String[]{" ","D:\\File\\study\\codechina\\project-java\\222100235\\src\\input.txt"});
}
@Test
public void test2(){
//参数错误
DWASearch.main(new String[]{" "," "," "});
}
对参数错误的测试类测试结果如下:
由于参数错误,程序抛出并处理异常,输出“文件不存在”
对参数正确的测试类测试结果如下:
各种指令,包括输出运动员信息,比赛信息,比赛详细信息,Error,N/A
测试结果,由于新加入指令,HashMap中没有相应结果,因此覆盖的方法率高
多次运行后,覆盖的方法较少,覆盖率降低
因此,在第一次输入正确参数的情况下,测试通过,类的覆盖率达到百分百的同时也有较高的代码和方法覆盖率。
在本次实践过程中,我接触到了很多之前我不曾了解的知识,包括使用Gson解析Json文件,建立单元测试类,如何导入jar包等。在刚开始的过程中,完全不知道如何动手,来来回回参考了很多博客,查询了很多资料,学到了很多知识,好在最终完成了这个项目。在这次实践的过程中,我知道万事开头难,在开始动手编程前一定要对程序进行先一步的分析,了解要用到的知识,这样在编程的过程中才能游刃有余。接着,一定要根据PSP表格来对自己完成项目的每一步有一个时间上的规划,安排好时间,不然到后面就会很忙。