寒假作业(2/2)——疫情统计

问题 内容
这个作业属于哪个课程 这个作业属于哪个课程
这个作业要求在哪里 寒假作业(2/2)——疫情统计
这个作业的目标 学习使用Github,Git等工具,学会对项目的开发进行分析
作业正文 作业2
其他参考文献

1.Github仓库地址

我的Github仓库地址:https://github.com/takeyouhomeaa/InfectStatistic-main

2.PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 60 70
Estimate 估计这个任务需要多少时间 1970 2025
Development 开发 1130 1135
Analysis 需求分析 (包括学习新技术) 60 75
Design Spec 生成设计文档 60 55
Design Review 设计复审 30 35
Coding Standard 代码规范 (为目前的开发制定合适的规范) 30 20
Design 具体设计 120 130
Coding 具体编码 800 830
Code Review 代码复审 30 40
Test 测试(自我测试,修改代码,提交修改) 150 130
Reporting 报告 240 230
Test Report 测试报告 60 40
Size Measurement 计算工作量 30 20
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 300 350
合计   1910 1955
#3.解题思路描述及其资料查找 * 思路 > 首先,通过浏览作业要求,可以得知本次作业要通过命令行来传递参数。所以,要对传递的命令行参数进行解析,得到每个参数代表的意义。 > 其次,本次程序是通过日志中得到数据,所以要提取日志相关的信息。 > 然后,通过所传递的参数把提取到的日志信息组合。 > 最后输出文件 > ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200214093852QQ%E5%9B%BE%E7%89%8720200214173840.png) * 资料查找 查找Github、Git工具的使用方法的相关资料、阿里的代码规范 #4.设计实现过程 > 1. 提供一个类将相应的指令及其参数存取起来,方便调用。 > 2. 提供一个方法用于处理所传送的命令 > ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200214100652QQ%E5%9B%BE%E7%89%8720200214180632.png) > 3.提供一个方法用于处理日志信息并输出 > ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200214102517QQ%E5%9B%BE%E7%89%8720200214182447.png) > 4.提供一个方法用于处理日志文件 > ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200214103635QQ%E5%9B%BE%E7%89%8720200214183605.png) > 5.提供一个方法用于组合处理后的日志信息 > ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200214104244QQ%E5%9B%BE%E7%89%8720200214184228.png) #5.代码说明 ``` ListCommand类 参数: Map> listMap //用于存放分析后的命令行的参数。key:命令行参数 value: 对应参数的值.比如:key:-type value: sp dead List command //用于存放list的命令的命令行参数 ``` ``` InfectStatistic类 参数: ListCommand listCommand; List commands; //存放命令。比如:list Map> province //用于存放每个省份对应的状态和人数 String[] provinces = {"全国", "安徽", "北京", "重庆", "福建", "甘肃", "广东", "广西", "贵州", "海南", "河北" , "河南", "黑龙江", "湖北", "湖南", "吉林", "江苏", "江西", "辽宁", "内蒙古", "宁夏" , "青海", "山东", "山西", "陕西", "上海", "四川", "天津", "西藏", "新疆", "云南", "浙江"}; //存放省份信息,按下标提取 List result; //存放组合后的结果 List files; //存放日志存放文件夹下所有的文件名 ``` ``` /** 初始化province集合 flag为-1的省份信息不会被输出,0则能够输出 **/ for (int i = 0; i < 32; i++) { province.put(provinces[i], new LinkedHashMap<>()); Map map = province.get(provinces[i]); map.put("感染患者", 0); map.put("疑似患者", 0); map.put("治愈", 0); map.put("死亡", 0); map.put("flag", -1); } province.get("全国").put("flag", 0);

方法
/**
String[] commands 存有输入的命令
String command 存放命令行参数
List params 命令行参数对应的值
1.判断第一个参数是否是list
2.遍历数组,判断数组数组的元素是否是存储在ListCommand.command的命令行参数
3.如果是,把该元素赋值给command,不是存于params中
4.command值改变前,以及循环次数到数组的长度时,把command ,params以键值对的方式存与listCommand.listMap中
5.
**/
public void commandAnalyze(String[] commands) throws CommandErrorException {
if (!InfectStatistic.commands.contains(commands[0])) {
throw new CommandErrorException();
}
if ("list".equals(commands[0])) {
String command = "";
List params = new ArrayList<>();
int i;
for (i = 1; i <= commands.length; i++) {
if (i == commands.length) {
if (params.isEmpty()) {
throw new CommandErrorException();
}
listCommand.listMap.put(command, params);
break;
}
if (commands[i].charAt(0) == '-' && !ListCommand.command.contains(commands[i])) {
throw new CommandErrorException();
}
if (!commands[i].equals(command) && !"".equals(command) && ListCommand.command.contains(commands[i])) {
if (params.isEmpty()) {
throw new CommandErrorException();
}
listCommand.listMap.put(command, params);
params = new ArrayList<>();
}
if (ListCommand.command.contains(commands[i])) {
command = commands[i];
} else {
params.add(commands[i]);
}
}
}
}

/**
1.获取-log所带的值
2.判断命令是否带有-date参数,有则以date参数所带的值组合成绝对路径,否则以最新日期组合成绝对路径
3.通过-log 带的值获得日志所有日志的绝对路径
4.根据date所带的值或者最新日期,获得小于等于该日期的所有日志文件的绝对路径
5.遍历日志文件,对每个日志文件按行读取提取省份、状态、人数存储到province集合中
6.根据传递的命令行参数不同,组合存储信息
7.输出文件
**/
public void fileRead(String[] commands) throws IOException {
String input = listCommand.listMap.get("-log").get(0);
String tempString = "";
if (listCommand.listMap.containsKey("-date")) {
String date = listCommand.listMap.get("-date").get(0);
input += "\" + date + ".log.txt";
} else {
input += "\" + getTheLatestDate() + ".log.txt";
}
getFiles(listCommand.listMap.get("-log").get(0));
List loadFiles = getLoadFiles(input);
for (String fileName : loadFiles) {
BufferedReader reader = new BufferedReader(new FileReader(fileName));
while ((tempString = reader.readLine()) != null) {
stringProcessing(tempString);
}
reader.close();
}
updateCountry();
if (!listCommand.listMap.containsKey("-type") && !listCommand.listMap.containsKey("-province")) {
stringSynthesis(new ArrayList<>(), new ArrayList<>());
} else if (listCommand.listMap.containsKey("-type") && !listCommand.listMap.containsKey("-province")) {

        List<String> typeParams = listCommand.listMap.get("-type");
        stringSynthesis(typeParams, new ArrayList<>());
    } else if (!listCommand.listMap.containsKey("-type") && listCommand.listMap.containsKey("-province")) {
        List<String> provinceParams = listCommand.listMap.get("-province");
        stringSynthesis(new ArrayList<>(), provinceParams);
    } else {
        List<String> typeParams = listCommand.listMap.get("-type");
        List<String> provinceParams = listCommand.listMap.get("-province");
        stringSynthesis(typeParams, provinceParams);
    }
    logOutput();
    reset();
}

/**
1.把传递进来的日志的一行和对应正则表达式进行匹配
2.匹配成功获取该行中的省份、状态、人数,并把对应province集合中对应省份的flag值变为0
3.把province集合中对应省份的数据提取出来,根据日志现实意义进行数据更新
4.把更新后的数据存回province集合中
**/
public void stringProcessing(String ch) {
String pro = "";
String pro1 = "";
String state = "";
int temp = 0;
int num = 0;
String regex = "(\S+) 新增 (\S\S\S\S) (\d+)人";
String regex2 = "(\S+) (\S+) 流入 (\S+) (\d+)人";
String regex3 = "(\S+) (\S+) (\d+)人";
String regex4 = "(\S+) (\S+) 确诊感染 (\d+)人";
String regex5 = "(\S+) 排除 (\S+) (\d+)人";
if (ch.matches(regex)) {
pro = getPro(ch, 0);
num = getNum(ch);
state = getState(ch, 2);
Map<String, Integer> tempMap = province.get(pro);

        tempMap.put("flag", 0);
        temp = tempMap.get(state) + num;
        tempMap.put(state, temp);
    } else if (ch.matches(regex2)) {
        pro = getPro(ch, 0);
        pro1 = getPro(ch, 3);
        num = getNum(ch);
        state = getState(ch, 1);
        Map<String, Integer> tempMap = province.get(pro);

        tempMap.put("flag", 0);
        temp = tempMap.get(state) - num;
        tempMap.put(state, temp);

        tempMap = province.get(pro1);
        tempMap.put("flag", 0);
        temp = tempMap.get(state) + num;
        tempMap.put(state, temp);
    } else if (ch.matches(regex3)) {
        pro = getPro(ch, 0);
        state = getState(ch, 1);
        num = getNum(ch);
        Map<String, Integer> tempMap = province.get(pro);

        tempMap.put("flag", 0);
        temp = tempMap.get(state) + num;
        tempMap.put(state, temp);
        temp = tempMap.get("感染患者") - num;
        tempMap.put("感染患者", temp);
    } else if (ch.matches(regex4)) {
        pro = getPro(ch, 0);
        state = getState(ch, 1);
        num = getNum(ch);
        Map<String, Integer> tempMap = province.get(pro);

        tempMap.put("flag", 0);
        temp = tempMap.get(state) - num;
        tempMap.put(state, temp);
        temp = tempMap.get("感染患者") + num;
        tempMap.put("感染患者", temp);
    } else if (ch.matches(regex5)) {
        pro = getPro(ch, 0);
        state = getState(ch, 2);
        num = getNum(ch);
        Map<String, Integer> tempMap = province.get(pro);

        tempMap.put("flag", 0);
        temp = tempMap.get(state) - num;
        tempMap.put(state, temp);
    }
}

/**
1.如果命令中带有-province,先把所有省份的flag值改为-1,把-province所带的省份对应的flag改为1
2.如果有带-type参数,则按照对应参数从province中取值
3.否则,全部输出;
**/
public void stringSynthesis(List typeParams, List countryParams) {
if (!countryParams.isEmpty()) {
for (int i = 0; i < 32; i++) {
province.get(provinces[i]).put("flag", -1);
}
for (String param : countryParams) {
province.get(param).put("flag", 0);
}
}
if (typeParams.isEmpty()) {
for (String key : province.keySet()) {
StringBuffer tempString = new StringBuffer();
Map<String, Integer> map = province.get(key);
if (map.get("flag") == -1) {
continue;
} else {
tempString.append(key + " ");
for (String ch : map.keySet()) {
if (!"flag".equals(ch)) {
tempString.append(ch);
tempString.append(map.get(ch) + "人 ");
}
}
result.add(tempString.toString().trim());
System.out.println(tempString.toString().trim());
}
}
} else {
for (String key : province.keySet()) {
StringBuffer tempString = new StringBuffer();
Map<String, Integer> map = province.get(key);
if (map.get("flag") == -1) {
continue;
} else {
tempString.append(key + " ");
for (String param : typeParams) {
if ("ip".equals(param)) {
tempString.append("感染患者");
tempString.append(map.get("感染患者") + "人 ");
} else if ("sp".equals(param)) {
tempString.append("疑似患者");
tempString.append(map.get("疑似患者") + "人 ");
} else if ("cure".equals(param)) {
tempString.append("治愈");
tempString.append(map.get("治愈") + "人 ");
} else if ("dead".equals(param)) {
tempString.append("死亡");
tempString.append(map.get("死亡") + "人 ");
}
}
result.add(tempString.toString().trim());
System.out.println(tempString.toString().trim());
}
}
}
result.add("// 该文档并非真实数据,仅供测试使用");
}

# 6.单元测试截图和描述
> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215142442QQ%E5%9B%BE%E7%89%8720200215222354.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215142555QQ%E5%9B%BE%E7%89%8720200215222542.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215142728QQ%E5%9B%BE%E7%89%8720200215222714.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144059QQ%E5%9B%BE%E7%89%8720200215224022.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144210QQ%E5%9B%BE%E7%89%8720200215223837.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144256QQ%E5%9B%BE%E7%89%8720200215223841.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144305QQ%E5%9B%BE%E7%89%8720200215223844.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144311QQ%E5%9B%BE%E7%89%8720200215223847.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144321QQ%E5%9B%BE%E7%89%8720200215223852.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144328QQ%E5%9B%BE%E7%89%8720200215223855.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144520QQ%E5%9B%BE%E7%89%8720200215223908.png)

> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215144524QQ%E5%9B%BE%E7%89%8720200215223913.png)

# 7.单元测试覆盖优化和性能测试
* 代码覆盖率分析
> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215145445QQ%E5%9B%BE%E7%89%8720200215225426.png)
> 覆盖率达到预期
* 性能分析
> ![图片](https://images.cnblogs.com/cnblogs_com/Ozgblog/1639679/o_200215160645QQ%E5%9B%BE%E7%89%8720200216000623.png)

# 8.代码规范
> 我的代码规范:https://github.com/takeyouhomeaa/InfectStatistic-main/blob/master/221701227/codestyle.md

# 9.心路历程与收获
1. 通过这次作业,了解了开发一个项目有许多流程,不仅仅是编程。
2. 学会了单元测试,也明白了单元测试的重要性。
3. 学习了GitHub、Git工具的使用
4. 发现许多不足,需要继续努力学习

# 10.技术相关的五个仓库
|  库  |  简介  |
|  ----  | ----  |
| Spring Framework  | Spring框架的源代码库 |
| spring-analysis  | Spring框架源码阅读 |
| SpringBoot-Learning  | SpringBoot基础教程 |
| JavaEETest  | Spring、SpringMVC、MyBatis、Spring Boot案例 |
| SpringMvcStepByStep  | SpringMVC基础教程 |
posted @ 2020-02-14 16:07  root11  阅读(185)  评论(2编辑  收藏  举报