121
社区成员




这个作业属于哪个课程 | 2302软件工程社区 |
---|---|
这个作业要求在哪里 | 软件工程第二次作业--文件读取 |
这个作业的目标 | 完成文件读取小练习 |
其他参考文献 | 《构建之法》、《阿里巴巴Java开发手册》、工程师的能力评估和发展、单元测试和回归测试 |
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 10 |
• Estimate | • 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | 300 | 400 |
• Analysis | • 需求分析 (包括学习新技术) | 20 | 10 |
• Design Spec | • 生成设计文档 | 30 | 20 |
• Design Review | • 设计复审 | 15 | 10 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 15 | 10 |
• Design | • 具体设计 | 45 | 60 |
• Coding | • 具体编码 | 90 | 120 |
• Code Review | • 代码复审 | 25 | 50 |
• Test | • 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | 90 | 90 |
• Test Repor | • 测试报告 | 50 | 40 |
• Size Measurement | • 计算工作量 | 10 | 20 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 400 | 500 |
从题目中提供的网站,打开开发者工具初步判断对应的请求,并获取url地址已经接口参数等进行分析,后续在程序中使用网络请求获取数据(预计同时也会提供一种允许通过读取本地数据(example中的data)实现)
运动员数据相对简单,直接可以找到对应的api
从这个请求对应的请求头中可以找到我们需要的url,即
https://api.worldaquatics.com/fina/competitions/3337/athletes?gender=&countryId=
,分析可,这是一个GET请求,带有gender、countryId等params,params参数可以为空
比赛数据涉及到多个api请求,我们首先在请求中找到比赛项目以及对应的id,我们可以轻易的找到获取这些信息的api接口:
https://api.worldaquatics.com/fina/competitions/3337/events
接着我们进一步找到具体比赛项目的详细得分情况,api:
https://api.worldaquatics.com/fina/events/${id}
,其中id
就是刚刚从请求中得到的id
网络请求使用hutool的网络请求包进行(这也是java开发用的较多的开源工具之一了)
使用hutool的json库对请求返回的json数据进行解析,同时需要编写JavaBean来对Json数据做一些简单的映射,便于后续开发和维护使用。
为提高系统性能,使用hutool的缓存组之间本地缓存,加速读取热点数据的过程,避免网络请求或文件流读取成为系统应用瓶颈。
(不用redis是嫌麻烦了,而且怕待会助教整起来又没环境什么的)
.
├─assets
└─src
├─core // 核心功能接口设计
│ └─impl // 核心功能实现类
├─datas // 本地缓存数据
├─entity // 实体对象封装
└─util // 工具类
/**
* 核心算法接口定义
*
* @author 天狗
* @version 1.0
* @date 2024/2/19 11:25
*/
public interface Algorithms {
/**
* 获取所有选手信息
* @return 选手信息列表
*/
List<Player> getAllPlayers();
/**
* 获取指定项目的决赛结果
* @param event 项目
* @return 比赛结果列表
*/
List<Result> getResults(String event);
/**
* 获取指定项目的详细结果
* @param event 项目
* @return 比赛结果列表
*/
List<Result> getDetailResults(String event);
}
/**
* 基于hutool的Http请求工具类
*
* @author 天狗
* @version 1.0
* @date 2024/2/18 16:12
*/
public class HttpRequestUtil {
/**
* 发送get请求
* @param url 请求地址
* @param queryParams 请求参数
* @return 返回json对象
* @throws IOException IO异常
*/
public static JSONObject getObj(String url, Map<String, Object> queryParams) throws IOException {
return HttpRequestUtil.getObj(url, queryParams, new HashMap<String, String>(1));
}
/**
* 携带自定义请求头发送get请求
* @param url 请求地址
* @param queryParams 请求参数
* @param headers 请求头
* @return 返回json对象
* @throws IOException IO异常
*/
public static JSONObject getObj(String url, Map<String, Object> queryParams, Map<String, String> headers) throws IOException {
String body = HttpRequestUtil.get(url, queryParams, headers);
return JSONUtil.parseObj(body);
}
/**
* 发送get请求
* @param url 请求地址
* @param queryParams 请求参数
* @return 返回json数组
* @throws IOException IO异常
*/
public static JSONArray getArr(String url, Map<String, Object> queryParams) throws IOException {
return HttpRequestUtil.getArr(url, queryParams, new HashMap<String, String>(1));
}
/**
* 携带自定义请求头发送get请求
* @param url 请求地址
* @param queryParams 请求参数
* @param headers 请求头
* @return
*/
public static JSONArray getArr(String url, Map<String, Object> queryParams, Map<String, String> headers) {
String body = HttpRequestUtil.get(url, queryParams, headers);
return JSONUtil.parseArray(body);
}
/**
* 发送get请求
* @param url 请求地址
* @param queryParams 请求参数
* @param headers 请求头
* @return 返回json字符串
*/
private static String get(String url, Map<String, Object> queryParams, Map<String, String> headers) {
return HttpRequest.get(url).form(queryParams).addHeaders(headers).execute().body();
}
/**
* 发送post请求
* @param url 请求地址
* @param json 请求体
* @param headers 请求头
* @return 返回json对象
*/
public static JSONObject post(String url, String json, Map<String, String> headers) {
String body = HttpRequest.post(url).body(json).addHeaders(headers).execute().body();
return JSONUtil.parseObj(body);
}
}
代码量较多,这边只展示一部分
/**
* 处理结果数据
* @param resultData 结果数据
* @param key key
* @param mergeMap 合并结果
* @param phase 阶段
*/
private void processResultData(JSONObject resultData, String key, Map<String, Result> mergeMap, String phase) {
if (resultData != null) {
for (Object o : resultData.getJSONArray(key)) {
JSONObject player = (JSONObject) o;
Result result = new Result();
String fullName = player.getStr("FullName");
String rank = player.getStr("Rank");
ArrayList<String> scoreList = new ArrayList<>();
for (Object dive : player.getJSONArray("Dives")) {
JSONObject diveObj = (JSONObject) dive;
scoreList.add(diveObj.getStr("DivePoints"));
}
Result mapResult = mergeMap.get(fullName);
if (mapResult != null) {
BeanUtil.copyProperties(mapResult, result);
}
result.setFullName(fullName);
switch (phase) {
case "Final":
result.setFinalRank(rank);
result.setFinalScore(scoreList);
break;
case "SemiFinal":
result.setSemiFinalRank(rank);
result.setSemiFinalScore(scoreList);
break;
case "Preliminary":
result.setPreliminaryRank(rank);
result.setPreliminaryScore(scoreList);
break;
default:
break;
}
mergeMap.put(fullName, result);
}
}
}
/**
* 执行读入的命令命令
* @param command 命令
* @throws IOException IO异常
*/
private static String doCommand(String command) {
Algorithms algorithms = new AlgorithmsImpl();
if ("players".equals(command)) {
List<Player> players = algorithms.getAllPlayers();
return toResultString(players);
} else if (Pattern.matches("result .* detail$", command)) {
String event = command.replaceFirst("result ", "").replaceFirst(" detail", "");
List<Result> results = algorithms.getDetailResults(event);
return toDetailResultString(results);
} else if (Pattern.matches("result .*",command)) {
String event = command.replaceFirst("result ", "");
List<Result> results = algorithms.getResults(event);
return toResultString(results);
} else {
return "ERROR\n-----\n";
}
}
增加了一个缓存工具类,基于Hutool提供的LFU最少使用率策略,使用单例模式,保证全局实例唯一性
/**
* 缓存工具类
* 用于缓存一些数据
* 使用单例模式
*
* @author 天狗
* @version 1.0
* @date 2024/2/20 14:55
*/
public class CacheSingleton {
private static volatile Cache<String, Object> instance;
public static Cache<String, Object> getInstance() {
if (instance == null) {
synchronized (CacheSingleton.class) {
if (instance == null) {
instance = CacheUtil.newLRUCache(100);
}
}
}
return instance;
}
public static void put(String key, Object value) {
getInstance().put(key, value);
}
public static Object get(String key) {
return getInstance().get(key);
}
}
对核心模块进行单元测试,测试覆盖率要求达到75%以上
对入口函数进行测试,覆盖率同样符合要求
原本想搞全局异常捕获的,但是这种相对原生的项目还是有点无从下手
当Http请求失败时,会捕获异常,并从本地读取json数据进行输出。(数据来源于题目example中提供的datas)
会在控制台中进行提示
在这个作业中,我学会了如何从互联网上获取数据,然后用程序来分析和处理这些数据。最难的部分是理解如何正确地使用API来获取数据,并且搞清楚如何从复杂的JSON格式中提取我们需要的信息。另外,学会了如何从文件中读取数据,处理它们,然后将结果保存回文件。这个作业让我更熟练地掌握了API调用、JSON处理和文件操作,也让我更有信心能够在未来的项目中应对类似的挑战。通过这次经历,我觉得自己的编程能力得到了提升,也更了解了软件工程这个领域的实际应用。