122
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | 2302软件工程社区 |
|---|---|
| 这个作业要求在哪里 | 软件工程第二次作业--文件读取 |
| 这个作业的目标 | 完成文件读取小练习 |
| 其他参考文献 | 《阿里巴巴Java开发手册》、工程师的能力评估和发展、单元测试和回归测试 |
项目地址
因为提交时重新fork了一边,这里展示原项目的提交记录截图

| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 10 | 10 |
| • Estimate | • 估计这个任务需要多少时间 | 10 | 10 |
| Development | 开发 | 300 | 350 |
| • Analysis | • 需求分析 (包括学习新技术) | 20 | 10 |
| • Design Spec | • 生成设计文档 | 30 | 20 |
| • Design Review | • 设计复审 | 15 | 10 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 15 |
| • Design | • 具体设计 | 45 | 60 |
| • Coding | • 具体编码 | 90 | 120 |
| • Code Review | • 代码复审 | 40 | 50 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 60 | 100 |
| Reporting | 报告 | 90 | 90 |
| • Test Repor | • 测试报告 | 50 | 40 |
| • Size Measurement | • 计算工作量 | 10 | 20 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 30 | 30 |
| 合计 | 820 | 985 |
为了方便读取和处理JSON文件,我们用到了jackson 这一开源框架。Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。
获取的JSON文件中有的是对象类型,有的是数组类型,为了实现通用的json文件读取,我们使用Jackson中objectMapper.readTree方法,先将json文件读取为一个JsonNode对象,再进行后续的处理。
然后通过观察JSON文件的结构,找到我们需要提取的字段
数据说明
athletes:存储了关于跳水项目的运动员信息。
event:存储了项目名称与项目id的对照,通过项目名称可以找到对应的项目id。
results:文件夹下存储以项目id命名的各个项目的成绩。包括总分与每一次比赛的小分。

先根据input.text中的命令获取项目名称,然后在event.json中匹配相同的项目名称

通过项目ID找到results文件夹下对应的项目成绩文件,一层一层地提取我们需要的字段(FullName, Rank, Score等),获取对应的字段后,再按照格式进行输出即可。
.
├─datas // json数据文件
└─src
├─core // 核心功能目录
│ └─impl // 核心功能实现类
├─entity // 实体对象封装
└─util // 工具类
└─FileUtils // 文件读写工具类
核心功能接口主要包括:

executeCommand函数对命名列表进行逐行处理(包括异常命令的处理)players时候,调用getAllPlayersInfo方法,得到并且返回所有运动员信息getEventResult方法,并且传入项目名称event,得到并返回对应项目的比赛结果其中,在得到结果后,将结果信息封装成一个对象,然后通过返回一个对象列表,再进行后续的格式化、输出等操作,相比于直接返回结果字符串,灵活性更强,复用性更高,符合模块化设计原则,提高了代码的可读性和可维护性。
public class DWASearch {
public static void main(String[] args) {
// 校验、读取命令行参数
String inputFile;
String outputFile;
// 校验命令行参数
if (args.length != 2) {
System.out.println("参数错误,需要包含input和output文件名");
} else {
inputFile = args[0];
outputFile = args[1];
try {
// 读取命令
List<String> commandList = FileUtils.readCommandList(inputFile);
// 处理命令
int count = 0;
for (String command : commandList) {
System.out.println("execute: " + command);
String result = impl.executeCommand(command);
// 第一条命令覆盖原文件内容,后续的命令缀加
try (Writer writer = new FileWriter(outputFile,count!=0)) {
writer.write(result);
count++;
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
}
代码量较大,以获取运动员信息为例
/**
* 获取所有运动员信息
* @return 运动员信息列表
*/
public static List<Player> getAllPlayersInfo() {
List<Player> players = new ArrayList<>();
try {
JsonNode playersInfo = FileUtils.readObjectFromJson("E:\\课内学习\\软件工程实践\\作业材料\\作业二\\newCode\\project-java\\222100222\\datas\\athletes.json");
Iterator<JsonNode> iterator = playersInfo.elements();
while (iterator.hasNext()) {
// 遍历国家
JsonNode countryInfo = iterator.next();
if (countryInfo.isObject()) {
// 从对象中读取需要的字段
String countryName = countryInfo.get("CountryName").asText();
JsonNode participations = countryInfo.get("Participations");
// 遍历该国家的运动员
Iterator<JsonNode> playerIterator = participations.elements();
while (playerIterator.hasNext()) {
// 提取字段
JsonNode playerInfo = playerIterator.next();
String firstName = playerInfo.get("PreferredFirstName").asText();
String lastName = playerInfo.get("PreferredLastName").asText();
String fullName = lastName + ' ' + firstName;
String gender = playerInfo.get("Gender").asText();
gender = gender.equals("0") ? "Male" : "Female";
// 创建并且添加Player对象到List
players.add(new Player(fullName,gender,countryName));
}
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
return players;
}
本题的大致流程就是读json数据并且解析,这也是性能开销较大的地方,于是很自然的可以想到将已经读取、解析过的文件缓存起来,这样再次执行相同命令或者用到相同的数据时,不需要再进行json文件的读取与解析,而是直接从缓存中获取,由此提高性能。
代码大致如下:
public static List<Player> getAllPlayersInfo() {
// 读取缓存的运动员信息
if (!impl.playersInfo.isEmpty()) {
System.out.println("(read players info from cache)");
return impl.playersInfo;
}
// 正常读取、解析json文件
// ......
}

对核心模块进行单元测试,主要分为三个部分


通过较完备的测试用例对这三个核心模块进行测试,从而达到一个较高的覆盖率,保证测试的有效性
展示部分测试代码:
@Test
public void testGetFinalResult1() throws IOException {
String event = "women 1m springboard";
List<Result> resultList = impl.getEventResult(event);
String correctResult = "MULLER Jette 1 [51.60, 52.00, 51.75, 46.80, 46.80]\n" +
"ROLLINSON Amy 2 [46.00, 42.90, 50.70, 54.00, 46.80]\n" +
"SKRZEK Kaja 3 [50.40, 46.80, 48.30, 45.60, 48.75]\n" +
"BENT-ASHMEIL Desharne 4 [46.80, 50.70, 48.30, 43.20, 45.50]\n" +
"JASMIN Amelie-Laura 5 [50.40, 45.50, 43.70, 46.80, 43.75]\n" +
"BLAZOWSKA Aleksandra 6 [43.20, 44.85, 45.60, 53.30, 41.80]\n" +
"WILSON Aimee 7 [50.40, 44.85, 38.40, 44.20, 50.70]\n" +
"OH Sooyeon 8 [45.60, 36.80, 46.80, 46.80, 46.80]\n" +
"LEE Yejoo 9 [43.20, 41.40, 43.20, 41.60, 39.60]\n" +
"JELINKOVA Tereza 10 [46.80, 42.90, 41.40, 26.40, 38.50]\n" +
"SHARIA Tekle 11 [38.40, 41.60, 30.00, 30.45, 34.10]\n" +
"SANTIAGO Dominique 12 [42.00, 18.20, 35.70, 34.50, 32.55]\n";
String resultStr = "";
for (Result result : resultList) {
resultStr += result.getFullName() + " " + result.getFinalRank() + " " +result.getFinalScore() + "\n";
}
Assert.assertEquals(correctResult,resultStr);
}
@Test
public void testGetFinalResult4() throws IOException {
String event = "women 1000m springboard";
List<Result> resultList = impl.getEventResult(event);
Assert.assertEquals("[]",resultList.toString());
}
@Test
public void testExecuteCommand1(){
String command = "this is a test command";
String result;
String expectedStr = "Error\n-----\n";
try {
result = impl.executeCommand(command);
Assert.assertEquals(expectedStr,result);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Test
public void testExecuteCommand2(){
String command = "result test event";
String result;
String expectedStr = "N/A\n-----\n";
try {
result = impl.executeCommand(command);
Assert.assertEquals(expectedStr,result);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 校验命令行参数
if (args.length != 2) {
System.out.println("参数错误,需要包含input和output文件名");
}

捕获并且会在控制台中进行提示
在完成这项任务时,我掌握了如何从网络源获取数据,并通过编程手段对这些数据进行深入分析和处理。最具挑战性的部分在于理解如何精准地利用API接口提取数据,以及怎样从结构复杂的JSON数据中筛选和整理出我们需要的关键信息。同时,我也学会了如何有效地从文件中读取数据,对它们进行处理,然后将最终结果存回文件中。这项作业不仅锻炼了我的API调用技巧、JSON数据处理能力,还加深了我对文件操作的理解以及对项目规范的要求。这使我更有信心在未来的项目中面对类似的数据处理挑战。