这个作业属于哪个课程 | 福大20春软工S班 |
---|---|
这个作业要求在哪里 | 结对第二次作业——某次疫情统计可视化的实现 |
结对学号 | 221701113、221701128 |
这个作业的目标 | 1、实现疫情数据的可视化 2、学习github合作开发 |
作业正文 | 正文 |
其他参考文献 | 百度 CSDN博客 Echart教程 echarts实现中国地图数据展示 |
一、代码规范
1、代码规范
2、GitHub仓库
二、功能展示
1、地图页面
页面上方统计了感染患者,疑似患者,累计治愈和累计死亡四个数据,时间默认为日志文件中最晚的那天,时间可以供用户自由更改。
用户可以在下方看到感染患者与疑似患者全国的分布情况,并且根据各省人数使用不同颜色进行区分,方便用户直观的查看全国患者的分布情况,而当用户的鼠标移到对应的省份上时,会自动显示出该省份对应的省份名和患者人数,并且对应省份会高亮,而通过单击省份可以进入对应省份的详情页。
2、详情页面
详情页显示了对应省份的名称,并且带有感染患者,疑似患者,累计治愈和累计死亡四个数据以及相对于前一天的人数的增减,上方的日期与地图页对应,且同样支持用户的自行更改,而点击返回地图按键即可返回地图页。
在页面下方可以看到新增确诊趋势,新增疑似趋势,治愈趋势和死亡趋势四个折线图,对应四个数据在七天内的变化趋势,便于用户直观的感受疫情在各个地区的发展。
三、结对过程描述
在项目开端,经过简单的讨论就确定了分工。
经过一段时间的查询了解了GitHub仓库同步的方法。
中间出现了java类包丢失的情况,导致无法运行java类,最后重新建立项目,并对资源进行搬迁。
当前后端数据对接完成的时候还出现了无法读取文件的情况。
关于地图点击跳转的讨论
中间还遇到utf-8 bom文件读不到第一行数据的问题 转成utf-8即可
四、设计实现过程
本次采用Web实现疫情可视化,为此将其分为前端和后端,前端显示视图,后端进行数据运算和传递,在Eclipse上创建Dynamic Web Project,部署tomcat9.0服务器
- 前端
- 前端有两个页面,一个页面显示中国地图和全国的疫情数据,另一个页面则显示省份的疫情数据,并用折线图表示疫情人群的每日趋势
- 每个页面都可以选择具体的日期,选中后,就能显示那个日期对应的疫情数据
- 后端
- 后端有一个servlet,当做控制器,进行传递数据和跳转的中转站,还有两个类,用于统计log文件夹内的疫情统计数据,提供必要的接口
- 前端实现
- 将两个页面设置成JSP,并且运用前次作业的原型,来展现前端的HTML样式中国地图采用echarts的china.js来展现
- 中国地图采用echarts的china.js来展现,通过改变js配置参数,来实现颜色变化和省份数据显示
- 详情页的折线图同样通过echarts的折线图来实现,横坐标对应日期,纵坐标对应数据
- 日期选择通过input标签的date类型来实现,选择完日期后即可按提交按钮传参给后端
- 前端涉及的页面跳转,都会传递一个flag参数给servlet,用于告诉servlet页面需要的需求是什么,点击省份还会传递province来表示省份
- 加入index.jsp,当做web应用的启动入口,他会经过servlet显示中国地图页面
- 后端实现
- servlet接受参数selected(用户选择的时间),province(用户点击的省份),flag(判断要执行的操作和跳转的页面),并通过服务器读取根目录下log文件夹(存放统计文件)的路径
- InfectMap类继承以前做过的统计疫情数据的InfectStatistic类,来提供接口
- allStatistic (String date)方法返回一个保存某日所有省市和全国的疫情数据hashmap
- compare(String province,String date)方法返回某个城市某日疫情数据变化的arraylist
- latestDate()getDate()方法分别返回文件夹下统计的最新日期和最新七天的日期
五、代码说明
前后端信息交互控制器,通过接收的参数判断之后执行的操作,并于后端统计文件对接,获取统计文件
String flag = request.getParameter("flag"); //判断跳转信息
String selected = request.getParameter("selected"); //判断选择的日期
String province = request.getParameter("province"); //判断选择的省份
String abpath = getServletContext().getRealPath("/log/"); //获取web根目录下的路径
if(selected == null)
{
InfectMap infect = new InfectMap();
infect.path = abpath;
selected = infect.latestDate(); //获取最新日期
}
else
{
InfectMap infect = new InfectMap();
infect.path = abpath;
selected = infect.judgeDate(selected); //判断是否超出或早于统计的日期
}
request.setAttribute("date", selected);
if(flag != null && flag.equals("mapStat")) //跳转地图页面
{
InfectMap infect = new InfectMap();
infect.path = abpath;
ArrayList<String> increase = infect.compare("全国", selected);
request.setAttribute("increase", increase);
Map<String, String> stat = infect.allStatistic(selected);
request.setAttribute("stat", stat);
request.getRequestDispatcher("中国地图.jsp").forward(request, response);
}
else if(flag != null && flag.equals("increase")) //跳转详情页面
{
InfectMap infect = new InfectMap();
infect.path = abpath;
Map<String, String> stat = infect.allStatistic(selected);
request.setAttribute("stat", stat);
ArrayList<String> increase = infect.compare(province, selected);
request.setAttribute("increase", increase);
request.setAttribute("province", province);
ArrayList<String> allDate = infect.getDate();
request.setAttribute("allDate", allDate);
ArrayList<ArrayList<String>> allIncrease = new ArrayList<ArrayList<String>>();
for(int i = 0 ; i < allDate.size() ; i++)
{
ArrayList<String> dateIncrease = infect.compare(province, allDate.get(i));
allIncrease.add(dateIncrease);
}
request.setAttribute("allIncrease", allIncrease);
request.getRequestDispatcher("湖北详情页.jsp").forward(request, response);
}
}
reading()方法将会读取日志文件并将date日期的数据统计到哈希表statistic中,将日志中没涉及到的省份初始化置0,然后调用countryStatistic()统计全国总人数,再返回这个表
public static Map<String, String> allStatistic (String date)
/*
* 统计出所有省份的数据
*/
{
dateTime = date;
reading();
String allProvin[] = {"北京","天津","河北","辽宁","吉林","黑龙江","山东","江苏","上海","浙江","安徽","福建",
"江西","广东","广西","海南","河南","湖南","湖北","山西","内蒙古","宁夏","青海","陕西","甘肃",
"新疆","四川","贵州","云南","重庆","西藏","香港","澳门","台湾"};
for(int i = 0 ; i < allProvin.length ; i++)
{
if(!statistic.containsKey(allProvin[i] + "疑似患者")) //检查哈希表中是否已经存在该省份的数据了
{
initStatistic(allProvin[i]);
}
}
sortMap = sortHashkey();
countryStatic();
Map<String, String> sta = statistic;
return sta;
}
①conpare方法用于统计某个省在某一个日期的人数变化数据,judgeDate会在reading()中判定用户选择的日期是否早于最早日期,如果早于最早日期,那么变化直接为0,judgeDate设为true
②如果用户没选择日期,那么直接用文件中最新日期,否则就寻找日期对应的日志文件
③读取文件后,判定那个省份的新增、确诊、治愈、死亡,然后进行统计,放入动态数组后返回
public static ArrayList<String> compare(String province,String date) throws FileNotFoundException
/*
* 统计每个省份某个日期的变化趋势
*/
{
judgeDate= false;
dateTime = date;
reading();
ArrayList<String> array = new ArrayList<String> ();
for(int i = 0 ; i < 4 ; i ++)
{
array.add("0");
}
if(judgeDate) //true说明比统计文件的最早日期还早
return array;
if(date == null)
filename = fileArray[fileArray.length - 1];
else
for(int i = 0 ; i < fileArray.length ; i++)
{
if(fileArray[i] .getName().equals(date + ".log.txt" ))
{
filename = fileArray[i];
break;
}
}
Scanner sc = new Scanner(filename,"UTF-8");
fileContent = new ArrayList<String>();
while(sc.hasNext())
{
String str = sc.next();
if (str.equals("//"))
break;
else fileContent.add(str);
}
sc.close();
for(int i = 0; i < fileContent.size() - 2; i++)
{
if(fileContent.get(i + 1).equals("新增") && fileContent.get(i).equals(province)) //判别新增
{
String str = fileContent.get(i + 3);
str = str.substring(0 , str.length() - 1); //截取人数
if(fileContent.get(i + 2).equals("感染患者"))
{
int num = Integer.parseInt(array.get(0)) + Integer.parseInt(str);
array.set(0, String.valueOf(num));
}
else if(fileContent.get(i + 2).equals("疑似患者"))
{
array.set(1, str);
}
}
else if(fileContent.get(i + 2).equals("确诊感染") && fileContent.get(i).equals(province)) //判别为确诊感染或排除的情况
{
String str = fileContent.get(i + 3);
str = str.substring(0 , str.length() - 1); //截取人数
int num = Integer.parseInt(array.get(0)) + Integer.parseInt(str);
array.set(0, String.valueOf(num));
}
else if(fileContent.get(i + 1).equals("死亡")) //判别为死亡的情况
{
if(fileContent.get(i).equals(province))
{
String str = fileContent.get(i + 2);
str = str.substring(0 , str.length() - 1); //截取人数
array.set(3, str);
}
}
else if(fileContent.get(i + 1).equals("治愈")) //判别为治愈的情况
{
if(fileContent.get(i).equals(province))
{
String str = fileContent.get(i + 2);
str = str.substring(0 , str.length() - 1); //截取人数
array.set(2, str);
}
}
}
return array;
}
六、心路历程与收获
221701113:
经过这次作业可以说是从头到尾刷新了对于正常工程开发的认知,从之前完全无知的状态脱离了出来,并且更加深刻的理解了在多人合作当中,正确的代码规范和良好的沟通的重要性,在遇到的种种低级错误和基础缺失的问题上,我的队友耐心地为我讲解,使我收获认识了很多,十分的感谢,是一个难得的好队友
221701128:
此次作业需要用github进行合作开发,由于这次是我主导,所以关于github建立库,增加合作者,添加分支等功能都需要我去研究,我也很好地跟我的队友规范了修改代码和上传代码的事宜,分别开发前后端,让我们一开始更新文件不会冲突
之后我后端做完,开始一起着手前端的完善事宜,有可能出现同时修改了文件的情况,所以再修改某个文件前一定要先向对方确认,让对方把自己更新的内容上传了,我再获得最新文件并进行作业,这是团队开发需要注意的问题
因为是合作开发,前后端的对接就需要更多地沟通,知道接口如何使用,这样才能统筹好开发事宜
合作开发经常出现我这边可以运行,对方却无法运行的情况,这时候一定要耐心,好好调试,看看是哪一步出了问题,这样问题才能得以解决
总的来说,这次合作开发对我收获很大,我的队友基础偏弱,但是是个勤奋好学的人,我也因此很耐心的引导他,他也不负我的期待,很好地完成了任务,是一个可以依赖的队友