这个作业属于哪个课程 | |
---|---|
这个作业要求在哪里 | |
结对学号 | |
这个作业的目标 | |
作业正文 | |
其他参考文献 |
一、Github 仓库地址和代码规范链接
- Github仓库地址:https://github.com/theguiltyperson/InfectStatisticWeb/tree/hmx
- 代码规范链接:https://github.com/theguiltyperson/InfectStatisticWeb/blob/master/codestyle.md
二、成品演示
-
地图上方提供日历,可以选取不同日期查看截止该日全国疫情情况
-
统计数据在地图上方,只显示到助教提供的静态文件最后一个日期
相同感染人数区间的省份可以通过左下方鼠标停留或点击
-
全国疫情折线图在地图下方,可选择显示或隐藏确诊,疑似,治愈,死亡四条折线
折线上的点显示当前日期的疫情数据
-
地图上点击不同省份会跳转到该省份疫情数据的折线图
三、结对讨论过程描述
- 作业发布当天晚上,由于技术不足无法实现实时数据更新,我们决定用javeEE课上学的JSP框架和数据库完成本次作业
四、描述设计实现过程
221701429-前端
-
作业题目有提示用echarts设计图表,就跟着学了echarts的教程,下载了文件,
在前端用jsp的方式实现页面,在页面中加入script,添加图表,设置图表的类型和参数,就能够显示出来了。
数据部分则是通过Servlet的http请求获取的,把数据库中的表的数据实例化成Province后,通过req.setAttribute的方式传递参数。
在地图上设置了点击事件,将params加到url上传递给Servlet判断,点击后跳转到具体省份的疫情的功能就实现了。
221701438-后端
-
与前端交流后,确定我的主要任务是对log文件夹下的日志进行处理,再将日志中数据写入数据库,完善疫情数据的读取和存储。
结合之前所学,我将每个省份的疫情情况封装在Province类,把助教提供的静态日志内容读取出来,存储在ArrayList<Province>
再用正则匹配将每个省的疫情数据提取并写入数据库,然后完善数据库的存取。
五、关键代码
- Jsp页面通过http请求获得Servlet传的数据,用div的方式显示出来,在css中更改样式使得四块横向排版。
<div id="virusSummary">
<%
int totalip = (int) request.getAttribute("totalip");
int totalsp = (int) request.getAttribute("totalsp");
int totalcure = (int) request.getAttribute("totalcure");
int totaldead = (int) request.getAttribute("totaldead");
%>
<div id="ip">
<div class="name">确诊</div>
<div class="data"><%=totalip%></div>
</div>
<div id="sp">
<div class="name">疑似</div>
<div class="data"><%=totalsp%></div>
</div>
<div id="cure">
<div class="name">治愈</div>
<div class="data"><%=totalcure%></div>
</div>
<div id="dead">
<div class="name">死亡</div>
<div class="data"><%=totaldead%></div>
</div>
</div>
- 这是用echarts实现疫情地图的script,tooltip改变数据提示框的输出格式,visualMap改变确诊人数区间对应的颜色提示,series里data部分填入http请求得到的确诊人数数据,然后显示到地图上。再添加一个function点击事件,点击省份后跳转到该省份的疫情折线图的页面。
<div id="chinaMap"></div>
<script type="text/javascript">
var myChart = echarts.init(document.getElementById('chinaMap'));
myChart.setOption({
// 数据提示框
tooltip: {
trigger: 'item', // item放到数据区域触发
formatter: '地区:{b}<br/>确诊:{c}' // 提示数据格式br表示换行,地图 : {a}(系列名称),{b}(区域名称),{c}(合并数值), {d}(无)
},
// 工具栏
/*toolbox: {
show: true,
orient: 'horizontal',
left: 'right',
feature: {
dataView: {readOnly: false},
restore: {},
saveAsImage: {}
}
},*/
// 使用透明度来区分疫情严重情况
visualMap: {
type: 'piecewise',
pieces: [
{gt: 1500, color: 'darkred'},
{gt: 1000, lte: 1500, color: 'red', colorAlpha: 1},
{gt: 500, lte: 1000, color: 'red', colorAlpha: 0.8},
{gt: 300, lte: 500, color: 'red', colorAlpha: 0.6},
{gt: 100, lte: 300, color: 'red', colorAlpha: 0.4},
{gt: 50, lte: 100, color: 'red', colorAlpha: 0.3},
{gt: 0, lte: 50, color: 'red', colorAlpha: 0.2},
{lte: 0, color: 'white'}
],
},
// 具体数据
series: [
{
name: '各省确诊病例', // 系列名称
type: 'map', // 系列类型,地图
map: 'china', // 要使用的地图,即上面注册的地图名称
//roam: true, // 开启鼠标缩放和平移漫游
label: { // 图形上的文本标签,地图默认显示数据名
show: true,
formatter: '{b}', // b是数据名,c是数据值
fontSize: 12
},
data:[
<%
int Ip;
for(int i = 0; i < ProvinceName.provinceSize; i++){
//ip = 0;
Ip = (int) request.getAttribute(ProvinceName.provinceName[i] + "Ip");
%>
{name: "<%=ProvinceName.provinceName[i]%>", value: "<%=Ip%>"},
<%}%>
]
}
]
});
//点击省份后跳转到具体疫情的页面
myChart.on("click",function (params) {
window.location.href = "Servlet?flag=2&name="+params.name;
},true)
</script>
- 该部分显示的是全国四种人数的折线图,用echarts定制的折线图样式,将获取的日期作为xAxis的数据、四种人数作为每个点的值,实现折线图。点击省份进入具体页面的折线图与之类似。
<div id="lineChart" style=" 800px;height:400px; position: center; background-color: #ffffff; padding-top: 40px"></div>
<script type="text/javascript">
var name = "全国";
// 基于准备好的dom,初始化echarts实例
var Chart = echarts.init(document.getElementById('lineChart'),'infographic');
Chart.setOption({
//设置标题
title: {
text: name + '疫情趋势'
},
//数据提示框
tooltip: {
trigger: 'axis',
},
legend: {
data: ['确诊','疑似','治愈','死亡']
},
xAxis: {
data:[<%
List<Province> country = (List<Province>) request.getAttribute("country");
String date;
int ip,totalIp = 0;
int sp,totalSp = 0;
int cure,totalCure = 0;
int dead,totalDead = 0;
for(Province province : country){
date = province.getDate();
%>
"<%=date%>",
<%}%>]
},
yAxis: {},
series: [
{
name: '确诊',
type: 'line',
data:[<%
for(Province province : country){
ip = province.getIp();
totalIp += ip;
%>
<%=totalIp%>,
<%}%>]
},
{
name: '疑似',
type: 'line',
data:[<%
for(Province province : country){
sp = province.getSp();
totalSp += sp;
%>
<%=totalSp%>,
<%}%>]
},
{
name: '治愈',
type: 'line',
data:[<%
for(Province province : country){
cure = province.getCure();
totalCure += cure;
%>
<%=totalCure%>,
<%}%>]
},
{
name: '死亡',
type: 'line',
data:[<%
for(Province province : country){
dead = province.getDead();
totalDead += dead;
%>
<%=totalDead%>,
<%}%>]
}
]
},true)
</script>
- Servlet控制前后端数据交互,调用对象类实例化,将参数通过http请求发送给下一个页面,通过url附带参数的形式,在Servlet中获取参数并判断选择进入的页面。
String flag = req.getParameter("flag");
ProvinceDAO provinceDAO =new ProvinceDAOImpl();
//flag=2时跳转到第二个页面
if(flag != null && flag.equals("2")){
String name = req.getParameter("name");
provinceDAO =new ProvinceDAOImpl();
List<Province> local = provinceDAO.list(name,true);//获取当地每天数据
int ip = 0,sp = 0,cure = 0,dead = 0;
//累加当地每天的数据
for (Province province : local) {
ip += province.getIp();
sp += province.getSp();
cure += province.getCure();
dead += province.getDead();
}
req.setAttribute("name",name);
req.setAttribute("totalip",ip);
req.setAttribute("totalsp",sp);
req.setAttribute("totalcure",cure);
req.setAttribute("totaldead",dead);
req.setAttribute("local",local);
req.getRequestDispatcher("concreteInfectStatistic.jsp").forward(req,resp);
}
//否则跳转到第一个页面
else{
provinceDAO =new ProvinceDAOImpl();
List<Province> country = provinceDAO.list("全国",true);//获取全国每天数据
//List<Province> all = provinceDAO.list();//获取各省份每天的数据
int ip = 0,sp = 0,cure = 0,dead = 0;
//累加全国每天的数据
for (Province province : country) {
ip += province.getIp();
sp += province.getSp();
cure += province.getCure();
dead += province.getDead();
}
String name;
int eachIp;
//查找每个省份的每天的确诊数据累加到一个数值上
for(int i = 0; i < ProvinceName.provinceSize; i++) {
name = ProvinceName.provinceName[i];
eachIp = 0;
List<Province> each = provinceDAO.list(name, true);//按省份名获取省份每天数据
for(Province province : each){
eachIp += province.getIp();
}
req.setAttribute(name+"Ip",eachIp);
}
req.setAttribute("totalip",ip);
req.setAttribute("totalsp",sp);
req.setAttribute("totalcure",cure);
req.setAttribute("totaldead",dead);
req.setAttribute("country",country);
req.getRequestDispatcher("chinaMap.jsp").forward(req,resp);
}
- 读取目录下指定日期前的所有日志内容
public static String[] readFile(String path,String date) throws ParseException, IOException {
List allFilePath = getFileName(path,date);
String[] allContent = new String[allFilePath.size()];
for (int i = 0; i < allFilePath.size(); i++){
File file = new File(String.valueOf(allFilePath.get(i)));
StringBuilder result = new StringBuilder();
// 构造一个BufferedReader类来读取文件
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
String s;
// 使用readLine方法,一次读一行,并忽略注释行
while ((s = br.readLine()) != null && !s.startsWith("//")) {
result.append(System.lineSeparator() + s);
}
br.close();
allContent[i] = result.toString();
}
return allContent;
}
- 将正则匹配处理完的数据填入数据库
public static void connectMysql() throws IOException, ParseException {
for (int i=0; i<date.length; i++){
String[] allContent = readFile("src/infectstatistic/log",date[i]);
ArrayList<Province> province = RegularMatch.match(allContent);
ListAdd(province, date[i]);
}
}
六、《构建之法阅读心得》、心路历程和收获及对队友的评价
阅读心得
- 构建之法第四章提到两人合作开发,我和队友采用的是前后端分离的,按照作业要求使用Git分支,建立一条dev分支,让队友和自己在dev分支上开发,开发结束后再合并到main分支。第一次接触这样的结对编程,感到新颖的同时也很陌生,相信在以后的实践中对这种合作开发会有更多经验。
- 第五章讲述软件团队模式和开发流程,至于团队模式和团队的开发模式的关系,我个人的理解是一群人在一起做软件开发,总是要一些方式方法。而这里团队模式就是这一群人的定性,团队的开发模式则是这群人使用的方法的定性。
心路历程
221701429
- 刚开始以为实现地图会很难,但是知道了echarts之后发现也没有那么难实现,
就是设置图表格式和传入数据的事情,折线图也是一个意思。收获也是挺多的,
第一次写前端页面,一直设置不好,没办法做出自己想要的样子,甚是苦恼,
但时间问题也只能作罢,美名其曰“精简”。
这次结对作业锻炼了我们的合作开发能力,对技术上的也好、配合上的也好,
都有很大的提升,对GitHub的使用也更熟练了一些,总的来说是一件好事。
成长总是要经历一些挫折的,这也是我的感受。
221701438
- 第一次看到这次作业感觉非常难,毕竟自己很少接触前后端分离的开发模式,
与队友讨论完也认清自己的任务,代码虽然不多,但是小BUG还是很多,
因为自己能力不足,很多时候还是在查文档和看大佬代码中学习。
本次结对作业采用了全新的结对开发模式,刚上手不是很熟悉,
在查找很多资料后逐渐掌握,这也算学到一种新的技能。
对队友的评价
221701429
- 他是个靠谱的队友,能一起合作是我的荣幸,他的部分我完全不用担心,
都能做好,对前端的部分也能提出一些建议,是个有实力有配合的队友。
221701438
- 我的队友代码规范,对本次作业的看法很多很棒,能给后端很清晰的开发思路。