142
社区成员




这个作业属于哪个课程 | 2022软工实践-W班 |
---|---|
这个作业要求在哪里 | 软件工程实践第二次作业——个人实战 |
这个作业的目标 | 完成对冬奥会的赛事数据的收集,并实现一个能够对国家排名及奖牌个数统计的控制台程序。 |
其他参考文献 |
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 40 |
• Estimate | • 估计这个任务需要多少时间 | 30 | 40 |
Development | • 开发 | 600 | 850 |
• Analysis | • 需求分析 (包括学习新技术) | 120 | 360 |
• Design Spec | • 生成设计文档 | 10 | 20 |
• Design Review | • 设计复审 | 10 | 20 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 15 | 20 |
• Design | • 具体设计 | 30 | 40 |
• Coding | • 具体编码 | 280 | 360 |
• Code Review | • 代码复审 | 35 | 120 |
• Test | • 测试(自我测试,修改代码,提交修改) | 120 | 200 |
Reporting | 报告 | 70 | 120 |
• Test Repor | • 测试报告 | 60 | 130 |
• Size Measurement | • 计算工作量 | 10 | 15 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 10 | 20 |
合计 | 1420 | 2035 |
发起http请求数据的JSON格式接口进行获取。
步骤:发送请求,请求后台的JS文件或某些接口来返回数据。
查看调试工具的控制台,看是否有日志输出。
通过浏览器审查元素可以看到里面包含了文章表体以及链接地址,知道了这些就可以利用API接口来帮我们完成解析了,截图如下
发送get请求获取后台数据,其中,将返回回来的字符串解析成json对象用到了google的Gson.jar包,用到了其中JsonParser的parse方法。代码截图如下
参考资料:
java发起http请求获取返回的Json对象
2018年俄罗斯世界杯之Java数据爬虫(一)
java发送http的get、post请求
用到java.io.BufferedReader和java.io.BufferedWriter类来读写文件。
输出排行榜到txt:Show_Total();{接受输入的文件名,读取对应json文件后,然后写入output.txt}
输出每日日赛程到txt:Show_Day();{接受输入的文件名,读取对应json文件后,然后写入output.txt}
接口设计
Lib.java:主要处理输入指令是否正确,判断日期和处理字符串数据等。具体有 :
outFile():接收input文件名输出output文件
cleanOutput():写文件时先将原内容清空
isRightDay():判断日期是否合法
isRightFirst():判断指令是否合法
checkPathSpaces():处理绝对路径可能存在空格的情况
cleanLine():去除输出txt末尾换行字符
TotalData.java:输出总榜功能。具体有 :
/**
* 存排行榜数据到指定的txt文件
*
* @param filename txt文件名
*/
public static void Show_Total(String filename, Map<String,String> map)
DayData.java:输出赛程功能。具体有 :
/**
* 存某日赛程数据到指定的txt文件
*
* @param s 日期
* @param filename txt文件名
*/
public static void Show_Day(String s, String filename, Map<String,String> map)
OlympicSearch.java:程序入口,读取命令行参数,为OlympicDataSet类提供命令行参数
流程图:
/**
* 存某日赛程数据到指定的txt文件
*
* @param s 日期
* @param filename txt文件名
*/
public static void showDay(String s, String filename, Map<String, String> map) {
try {
File f = new File(filename);
OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "utf-8");
BufferedWriter bw = new BufferedWriter(write);
//判断map对象是否缓存,若有直接读map中的数据。没有就读json文件并存到map。
if (!map.containsKey(s)) {
StringBuffer stringBuffer = new StringBuffer();
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(new FileReader("src/data/schedule/" + s + ".json"));
JsonArray jsonObject2 = jsonObject.get("matchList").getAsJsonArray();
//stringBuffer循环追加字符串
for (int i = 0; i < jsonObject2.size(); i++) {
JsonObject jsonObject1 = jsonObject2.get(i).getAsJsonObject();
stringBuffer.append("time:" + jsonObject1.get("startdatecn").getAsString().substring(11, 16) + "\n");
stringBuffer.append("sport:" + jsonObject1.get("itemcodename").getAsString() + "\n");
if (jsonObject1.get("homename").getAsString().equals("")) {
stringBuffer.append("name:" + jsonObject1.get("title").getAsString() + "\n");
} else {
stringBuffer.append("name:" + jsonObject1.get("title").getAsString() + " " + jsonObject1.get("homename").getAsString() + "VS" + jsonObject1.get("awayname").getAsString() + "\n");
}
stringBuffer.append("venue:" + jsonObject1.get("venuename").getAsString() + "\n");
stringBuffer.append("-----" + "\n");
}
//写入文件和存到map
bw.write(stringBuffer.toString());
map.put(s, stringBuffer.toString());
bw.close();
} else {
bw.write(map.get(s));
bw.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 存排行榜数据到指定的txt文件
*
* @param filename txt文件名
*/
public static void showTotal(String filename, Map<String, String> map) {
try {
File f = new File(filename);
OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "utf-8");
BufferedWriter bw = new BufferedWriter(write);
if (!map.containsKey("total")) {
StringBuffer stringBuffer = new StringBuffer();
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(new FileReader("src/data/total.json"));
JsonArray jsonObject2 = jsonObject.get("medalsList").getAsJsonArray();
for (int i = 0; i < jsonObject2.size(); i++) {
JsonObject jsonObject1 = jsonObject2.get(i).getAsJsonObject();
bw.append("rank" + jsonObject1.get("rank").getAsInt() + ":" + jsonObject1.get("countryid").getAsString() + "\n");
bw.append("gold:" + jsonObject1.get("gold").getAsInt() + "\n");
bw.append("silver:" + jsonObject1.get("silver").getAsInt() + "\n");
bw.append("bronze:" + jsonObject1.get("bronze").getAsInt() + "\n");
bw.append("total:" + jsonObject1.get("count").getAsInt() + "\n");
bw.append("-----" + "\n");
bw.write(stringBuffer.toString());
map.put("total", stringBuffer.toString());
}
bw.close();
} else {
bw.write(map.get("total"));
bw.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 判断日期是否合法
*
* @param s
* @return
*/
public static boolean isRightDay(String s) {
if (s.length() != 4) {
return false;
} else {
String s1 = s.substring(0, 1);
String s2 = s.substring(1, 4);
if (s1.equals("0")) {
if (Integer.valueOf(s2) >= 202 && Integer.valueOf(s2) <= 220) {
return true;
} else {
return false;
}
} else {
return false;
}
}
}
/**
* 判断指令是否合法
*
* @param s
* @param filename 输出文件名
* @return
*/
public static boolean isRightFirst(String s, String filename) {
String[] str = s.split("\\s+");
//取第一个单词判断是否是正确指令
if (str[0].equals("total") || str[0].equals("schedule")) {
if (str[0].equals("total")) {
return true; //是正确total指令
} else if (isRightDay(str[1])) {
return true; //是正确schedule指令
} else { //是正确schedule指令,但日期不正确,写入N/A
try {
File f = new File(filename);
if (!f.exists()) {
f.createNewFile();
}
OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "utf-8");
BufferedWriter bw = new BufferedWriter(write);
bw.write("N/A" + "\n");
bw.write("-----" + "\n");
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
} else { //不是正确指令,写入Error
try {
File f = new File(filename);
if (!f.exists()) {
f.createNewFile();
}
OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "utf-8");
BufferedWriter bw = new BufferedWriter(write);
bw.write("Error" + "\n");
bw.write("-----" + "\n");
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
/**
* 处理input文件输出output文件
*
* @param in 输入文件名
* @param ou 输出文件名
*/
public static void outFile(String in, String ou, Map<String, String> map) {
try {
String s;
LineNumberReader br = new LineNumberReader(new FileReader(in));
//按行读取input.txt
for (s = br.readLine(); s != null; s = br.readLine()) {
s=s.trim();
//若空白行跳过
if ("".equals(s)) {
s = br.readLine();
}
if (isRightFirst(s, ou)) { //判断指令正确与否
if (s.equals("total")) {
TotalData.showTotal(ou, map); //执行总榜写入
} else {
String[] str = s.split("\\s+");
DayData.showDay(str[1], ou, map); //执行赛程写入
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
执行循环5000次
用下方计算程序运行耗时时间
long startTime = System.currentTimeMillis(); //获取开始时间
long endTime = System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间:" + (endTime - startTime) + "ms"); //输出程序运行时间
改进措施:用Map<String, String> map 来缓存已经写入的字符串,下次再写入时就不用再读json文件。
改进前截图:
改进后截图:
public void testMain() throws IOException {
long startTime = System.currentTimeMillis(); //获取开始时间
OlympicSearch.main(new String[]{"test/input.txt", "test/output.txt"});
String s1, s2;
s1 = Files.readString(Path.of("test/output.txt"));
s2 = Files.readString(Path.of("test/2.txt"));
assertEquals(s2, s1);
long endTime = System.currentTimeMillis(); //获取结束时间
System.out.println("程序运行时间:" + (endTime - startTime) + "ms"); //输出程序运行时间
}
public void testShowTotal() throws IOException {
TotalData.showTotal("test/Total1.txt", new HashMap<>());
String s1, s2;
LineNumberReader br1 = new LineNumberReader(new FileReader("test/Total1.txt"));
LineNumberReader br2 = new LineNumberReader(new FileReader("test/1.txt"));
for (s1 = br1.readLine(), s2 = br2.readLine(); s1 != null && s2 != null; s1 = br1.readLine(), s2 = br2.readLine()) {
assertEquals(s1, s2);
}
}
覆盖率:
catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
1.边查边写,效率很慢,列出若干问题,再去学习相关技术,会更快一点。
2.加深对Java的IO的掌握和流操作的基本规律:明确数据源和数据汇,目的是明确使用输入流还是输出流。明确操作的数据是否是纯文本数据。是否需要进行字节流和字符流的转换。是否需要使用缓存。
3.性能优化 用JProfiler做性能分析 ,用空间换时间的策略 ,来提高程序的运行速度