结对第二次——某次疫情统计可视化的实现
这个作业属于哪个课程 | 软件工程 |
---|---|
这个作业要求在哪里 | 结对第二次作业——某次疫情统计可视化的实现 |
这个作业的目标 | 结合寒假第二次作业的成果实现原型设计中的部分功能,例如地图高亮不同颜色显示和曲线图的绘制 |
结对学号 | 221701103 221701141 |
作业正文 | .... |
其他参考文献 | ... |
一、地址&链接
Github:InfectStatisticWeb
codestyle:codestyle.md
二、展示成品
1.主要功能
- 鼠标移到省份上可高亮并显示数据信息,点击省份跳转到省份详情界面
-
数据随着选择日期变化
-
全国
-
省份
-
-
病例变化曲线图
-
全国
-
省份
-
2.其他界面
三、结对过程
1.开始讨论
刚拿到这个题目的第一反应是很懵的,因为刚从上次只用做原型的庆幸中走出来就遇到真正的难题——实现原型。我们开始都不知道如何下手,题目里所建议使用的所有工具我们基本都不会,只是惊叹于一串串难而专业的名词又感叹我们的菜。虽然专业技术不会,但是讨论的仪式感还是要有的。我们首先确定了任务阶段,撰写讨论了代码规范的事宜,还有使用的技术问题:
主要的分工是这样的:一个去做图表显示有关的东西,一个编写疫情数据统计的程序和界面
2.解决问题
先不说我们合力解决了什么技术上的问题,首先队友就解决了我的问题。因为一直使用命令行commit请求,之前虽然下载了github桌面版但还是没怎么用过(因为不会),这次为了合作仓库方便统一,就硬着头皮学了它,多亏队友的帮助,我基本是弄清楚了桌面版的使用,上图!
然后我就会了(再次感谢)
再说解决实际问题的话,因为我们的主攻方向不一样基本没有什么要一起解决的问题,不过最后合并代码的时候确实有点小插曲,但最后都有坎坷的解决,解决的方法无非是细心和百度,比如:
3.查找资料
资料基本都来源于网络的不知名热心网友
四、设计实现过程
1.疫情统计程序
我们这次直接使用的是助教提供的日志文档,所以可以沿用第二次作业的程序。根据我们的界面设计,需要现有现有确诊,现有疑似,累计确诊,累计死亡,累计治愈新增五个数据,并分为全国和各省的范围,还要计算增长变化量。
和上次作业不同的就是要分清累计和现有还有变化量的关系。刚开始因为没仔细思考序错将变化量当成现有量差点翻车。上次作业只考虑了现有的情况,所以这次添加了累计和变化量的情况。依我的理解累计确诊就是不减去死亡和治愈的人数,所以在统计函数里做了调整,删去了做相应减法的语句。变化量的统计就更简单了,只读入一个日期的log文件。
刚开始用的是控制台输入输出,方便调试,输入模式如下图,可以准确简单的获取想要的答案,输出的就是所需人数,后来为了获取数据方便就改成了命令行输入:
为了方便在地图里的数据显示,利用程序先输出了所需要的各省份现有和累计的确诊人数还有全国每天的现有和确诊人数。
2.图表
图表从内容上分为省份和全国两种,从类型上分为地图和曲线图两种。都是采用ECharts实现。
- 全国地图
引入了china.js和echarts.min.js两个文件。
数据来源为GetInfo类和log文件。
移动到具体省份时高亮并显示简要信息用 tooltip : {trigger: 'item'}。
点击跳转为函数myChart.on(具体见代码部分),经过servlet : toProvince处理后,转到具体省份界面。 - 全国曲线图
数据来源为GetInfo类和log文件。 - 省份曲线图
通过url携带信息获得省份名。
数据来源为GetInfo类和log文件。
使用BootStrap的选项卡作为容器。
ECharts自动将数据拟合成曲线图。
3.网页布局
网页布局都采用html+css+javascript技术,因为两人分工不同,所以刚开始的网页布局都是在单独的html文件下实现的,调试好了才一起合并。布局是照搬之前的原型图做的,有些相似的功能就只做了一种。实现方法就是各种div模块化拼接。因为时间比较赶所以也没有用什么花里胡哨的界面,加上确实能力有限,也没有用什么框架,全程手打。(泪目)
4.功能结构图
五、代码说明
- 选择具体的日期展现疫情数据
下拉选项(bootstrap)->界面展示(china.jsp)->处理选中动作(servlet:updateChinaInfo)->回到界面(china.jsp)
<!--选择日期 -->
<div class="btn-group">
<button class="btn btn-default">请选择日期</button> <button data-toggle="dropdown" class="btn btn-default dropdown-toggle"><span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="/InfectStatisticWeb/updateChinaInfo?flag=2020-02-02">2020-02-02</a></li>
<li><a href="/InfectStatisticWeb/updateChinaInfo?flag=2020-02-01">2020-02-01</a></li>
...
</ul>
</div>
<%--显示疫情数据信息 --%>
<table>
<tr>
<td><%="现有确诊" %></td><td><%="现有疑似" %></td><td><%="现有重症" %></td>
</tr>
<tr>
<td><%=request.getAttribute("info2") %></td><td><%=request.getAttribute("info3") %></td><td><%="---" %></td>
</tr>
<tr>
<td><%="昨日+"+request.getAttribute("info4") %></td><td><%="昨日+"+request.getAttribute("info5") %></td><td><%="昨日---" %></td>
</tr>
<tr>
<td><%="累计确诊" %></td><td><%="累计治愈" %></td><td><%="累计死亡" %></td>
</tr>
<tr>
<td><%=request.getAttribute("info6") %></td><td><%=request.getAttribute("info7") %></td><td><%=request.getAttribute("info8") %></td>
</tr>
<tr>
<td><%="昨日+"+request.getAttribute("info9") %></td><td><%="昨日+"+request.getAttribute("info10") %></td><td><%="昨日+"+request.getAttribute("info11") %></td>
</tr>
</table>
//在servlet中处理选中日期的动作
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
String flag=request.getParameter("flag");//时间
String[] args={flag,"1","2","ip"};
try {
GetInfo temp=new GetInfo();
request.setAttribute("info",temp.getInfo(args));
args[2]="2";args[3]="ip";
GetInfo temp1=new GetInfo();
request.setAttribute("info2",temp1.getInfo(args));
...
} catch (IOException e) {
e.printStackTrace();
}
request.getRequestDispatcher("china.jsp").forward(request, response);
}
- 显示中国地图图像
引入资源(echarts.min.js、china.js)->显示界面(china.jsp)
<%--显示疫情图像信息 --%>
<%--当前现有确诊病例数图像信息 --%>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="china1" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('china1'));
// 指定图表的配置项和数据
var option = {
title : {
text: '',
subtext: '当前现有确诊病例数,排除治愈、死亡。',
x:'center'
},
tooltip : {//提示框组件。
trigger: 'item'
},
visualMap: {
type: 'piecewise',
pieces: [
{min: 1500,color: '#6D000E'},
{min: 900, max: 1500,color: '#A30014'},
{min: 310, max: 1000,color: '#B8741A'},
{min: 200, max: 300,color: '#F59A23'},
{min: 1, max: 200,color: '#FACD91'},
{max: 0,color: '#F2F2F2'}
//label: '';
]
},
series: [
{
name: '确诊病例',
type: 'map',
mapType: 'china',
label: {
show: true,
color: '#000000',
fontSize:10
},
data: [
{name: '北京',value: 5},
...
]
}
]
};
myChart.setOption(option);
//处理点击跳转至具体省份
myChart.on('click', function (params) {
var dataIndex = params.name;
window.localStorage.setItem("selectedProvince", params.name);
window.open("toProvince?prov="+dataIndex+"");
});
</script>
- 点击省份跳转至具体省份界面
地图显示(china.jsp/ECharts)->跳转函数(myChart.on('click', function (params))->界面切换处理(servlet:toProvince)->跳转至省份界面(province.jsp))
//处理点击跳转至具体省份
myChart.on('click', function (params) {
var dataIndex = params.name;
window.localStorage.setItem("selectedProvince", params.name);
window.open("toProvince?prov="+dataIndex+"");
});
//界面切换处理
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
String sp=request.getParameter("prov");
request.setAttribute("provinceInfo", sp);
String[] args={"2020-02-02","2",sp,"2","ip"};
try {
GetInfo temp=new GetInfo();
request.setAttribute("infop1",temp.getInfo(args));
args[3]="3";args[4]="ip";
GetInfo temp1=new GetInfo();
request.setAttribute("infop2",temp1.getInfo(args));
...
} catch (IOException e) {
e.printStackTrace();
}
request.getRequestDispatcher("province.jsp").forward(request, response);
}
//具体省份界面数据
<table>
<tr>
<td><%="现有确诊" %></td><td><%="累计确诊" %></td><td><%="累计治愈" %></td><td><%="累计死亡" %></td>
</tr>
<tr>
<td><%=request.getAttribute("infop1") %></td><td><%=request.getAttribute("infop2") %></td>
<td><%=request.getAttribute("infop3") %></td><td><%=request.getAttribute("infop4") %></td>
</tr>
<tr>
<td><%="昨日+"+request.getAttribute("infop5") %></td><td><%="昨日+"+request.getAttribute("infop6") %></td>
<td><%="昨日+"+request.getAttribute("infop7") %></td><td><%="昨日+"+request.getAttribute("infop8") %></td>
</tr>
</table>
- 具体省份信息曲线图
界面显示(province.jsp:EChart)->数据来源(import pojo.GetInfo)
ps:涉及到数据来源的都是使用了GetInfo类,只在此详列。
ps+:该jsp用了很多java的内容,有点破坏了MVC模式。但如果不这样,又要用到很多全局变量,难以两全。
//新增确诊病例折线图(其他图就不一一列举了)
<script type="text/javascript">
var province = window.localStorage.getItem("selectedProvince");
//document.write(window.localStorage.getItem("selectedProvince"));
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('line1'));
// 指定图表的配置项和数据
var option = {
title: {
text: province+" 新增确诊趋势",
subtext: '单位:例'
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1.19', '1.20', '1.21', '1.22', '1.23', '1.24', '1.25', '1.26', '1.27', '1.28'
, '1.29', '1.30', '1.31', '2.1', '2.2']
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value}'
},
axisPointer: {
snap: true
}
},
series: [
{
name: '新增确诊',
type: 'line',
smooth: true,
data: [<%GetInfo temp1=new GetInfo();
String pro=(String)request.getAttribute("provinceInfo");
String[] args1={"2020-01-19","2",pro,"4","ip"};%>
<%=temp1.getInfo(args1) %>,
...
]
}
]
};
myChart.setOption(option);
</script>
//仅列出getInfo方法,其余方法和第二次作业类似。
public int getInfo(String[] args) throws IOException {
//System.out.print("输入查找日期、数据范围(全国数据输入1,省份数据输入2)、省份名(若前一项选择2则需输入)、");
//System.out.println("数据类型(现存变化量输入1,现有输入2,累计输入3,累计变化量输入4)、感染信息(ip,sp,cure,dead)");
String province="";
int isAll=1;//输出全国数据
String date=args[0];
String type="";
int boundary=Integer.parseInt(args[1]);
if(boundary==2) {
province=args[2];
isAll=0;
}
if(isAll==1) {//是全国
timeLimits=Integer.parseInt(args[2]);
type=args[3];//获得需要的感染类型
}
else {
timeLimits=Integer.parseInt(args[3]);
type=args[4];//获得需要的感染类型
}
CalData dailyData=new CalData(date, boundary, province,timeLimits);
return getData(type,dailyData);
}
六、心路历程与收获
衡:
真的难哭我了
这次作业就是让我反思让我怀疑人生。我不知道自己大学三年在干什么,我学过什么,扩展过什么。回顾前三年,玩也没玩好学也没学好。每学期需要打代码的课程对我来说都比较艰辛。刚开始的代码作业还是能跟得上的,到后面代码越来越长,知识面越来越广,所需技术越来越难,我就开始掉队了。我确实只是拘泥于课本中所学到的编程知识,以为足够(说实话我也不怎么愿意去拓展),课外的知识总觉得无从下手,就算开始前的准备工作,例如环境配置,各种包的引入什么的就已经击垮我了。
这次的作业直击我的软肋,全是课外拓展我没见过的技术框架。好嘛,我投降。不要说让我利用这些陌生繁琐的代码开发个什么东西,单单是看懂我就已经费事了。非要说的话,心路历程就是自我怀疑逐渐崩溃又趋于平稳的过程。为什么最后平稳了呢,是因为我心态已经佛了(死猪不怕开水烫?)还有靠着我的神仙队友,请带我飞。
我在这个作业里能做的就是提供数据获取的代码还有简单到不能再简单的网页布局。做这些边角工作打打下手还蛮适合我的。
要说收获的话,打代码速度变快了,打代码思维清晰了,页面布局速度变快了。
马:
快乐齐天,我已成仙
原来就想着这次作业不会就是上次的原型实现吧。结果,呵。
刚开始确实无从下手,选个开发技术都犹豫半天。难呐,都不熟。思来想去,还是用J2EE吧,起码刚学的,还记得。确定开发技术后,就开始补J2EE的知识了。说实话,我离老师教的进度都差不少。后面学了一天多,才跟上老师的进度,可以做项目。
中间编码的过程确实不堪回首。干啥啥不行,百度第一名。学J2EE理论知识,学JS忘掉的知识,学ECharts画图,找china.js等资源。这可能是我学习新知识最勤奋的一次了,以往都是将就着用自己的旧知识。慢慢的,我居然变得快乐了。不会的东西很多,所以学到的东西也很多,然后就觉得自己还行,起码能学会,哈哈。尤其是通过队友的协作,处理了一个困扰我半天的bug的时候,真的是很舒畅。
七、评价队友
衡:
夸
一个好队友真的太重要了。如果给我一个人布置这个作业我直接原地去世。不像前几次作业的题目,之前我看题目是看个三四遍就基本有个思路了,起码知道怎么做了,这个题我看一遍就知道是要我干什么了,但是我不会。之前是题目要求写的繁琐,这次是题目本身繁琐。所以队友的解题思路救了我。大概分配了下任务,明确了我要干什么,嗯靠谱!
队友还教我使用桌面版github,我真的要感谢加赞扬。之前我不是没学过桌面版的使用,是网上的教程真的看不懂,一个简简单单的功能非要写半天还不在点子上,所以我就放弃了,反正命令行也是一样的。队友简要的介绍每个常用功能的位置还有使用注意事项,通俗易懂,方便快捷的github体验。
队友最大的优点就是没有嫌我菜(也有可能是不好意思说)。我本来是要帮着分担一点jsp文件的编写,熬夜硬肝还是一直报错,而且javaee诡异就在于它的报错冗长难懂,加上这学期才开这门课,我是心有余力不足。所以得知了我的情况,队友毅然决然揽下了数据与图表混合的部分,真是救人于水火之中。
经过这两次的结对作业我深刻体会到了队友的重要性。队友可以帮助我不会的部分,提高了我原来的作业品质。而且遇到问题还能有人一起讨论,有的时候一句话就可以点醒查几天网上资料还什么也不明白的我。
马:
赞
有了队友,肯定做事会容易些。不过没想到的是,原来以为队友是无所不能的学霸,结果在网页制作上和我一样都是小白。印象最深刻的是,我们在选择开发技术的时候犹豫不决。明明两个人只会php还有刚学习的javaee,还犹豫半天。选哪个简单呢,emmm。
我还是比较喜欢这次结对作业的,特别队友是个女生,给了我无形的压力。要是队友是舍友,我可能就:做什么,做个锤子!衡也是比较认真的一个人,我有时候这边涉及到她的代码的东西,就交给她做了,然后她也没说啥,做的很好。
总之,给队友一个赞,奥利给!
八、PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 16 |
Estimate | 估计这个任务需要多少时间 | 20 | 16 |
Development | 开发 | 1740 | 2265 |
Analysis | 需求分析 (包括学习新技术) | 240 | 600 |
Design Spec | 生成设计文档 | 60 | 45 |
Design Review | 设计复审 | 30 | 25 |
Coding Standard | 代码规范 | 30 | 50 |
Design | 具体设计 | 180 | 120 |
Coding | 具体编码 | 900 | 1200 |
Code Review | 代码复审 | 180 | 90 |
Test | 测试(自我测试,修改原型,优化) | 120 | 135 |
Reporting | 报告 | 140 | 135 |
Test Report | 测试报告 | 60 | 45 |
Size Measurement | 计算工作量 | 20 | 10 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 80 |
合计 | 1900 | 2416 |