这个作业属于哪个课程 | 2020春S班 |
---|---|
这个作业要求在哪里 | 结对第二次作业——某次疫情统计可视化的实现 |
结对学号 | 221701203、221701214 |
这个作业的目标 | 创建疫情地图和省份具体情况网站 |
作业正文 | 结对第二次作业——某次疫情统计可视化的实现 |
其他参考文献 | java爬取丁香园、全国疫情统计可视化地图、新冠肺炎api |
Github仓库地址和代码规范
1. GitHub仓库:
2. 代码规范:
成品展示
首页的历史数据
全国累计的一些数据,包括更新时间、累计确诊、疑似病例、治愈病例、死亡病例,都是从丁香园爬取获得。
新增确诊趋势地图
一个中国疫情地图,颜色深浅表示严重程度,鼠标移动到省份上会高亮,并显示该省的现有确诊人数、死亡人数等信息,也都是从丁香园爬取获得。
累计确诊趋势地图
全国的累计确诊趋势地图,移动到福建上,发现福建累计确诊296人。
地图中的省份详细信息
这是现有确诊趋势地图,移到福建查看相关信息。
省份地图
- 选择湖北点击之后,跳转至详情页,可以看到该省各个城市的严重程度,鼠标移动到城市上会高亮,并显示该市的确诊人数,可以看到截止3月16日武汉市的疫情还是很严重的。
- 点击福建后看见福建每个市都已经没有确诊人数,让人欣慰。
省份疫情趋势折线图
省份的详情页可以查看爬到的数据(以湖北为例),可以看到湖北的新增确诊趋势最近几日是一直在下降的,累计治愈人数有上升,累计确诊人数变化幅度不大。同时上方可以看到湖北的现有确诊,累计确诊等数据。
结对讨论过程描述
设计实现过程
设计过程
看到题目之后,由于自身知识的欠缺,我们决定先从简单的前端静态页面入手,构建出网站的大概框架,由于局限于自身的代码技术能力想要选择纯前端实现,而后,由于队友的互相鼓励和与同学间的交流决定尝试一下使用前后端分离的技术构建网站,就逐步学习了Servlet、spring系列的技术,努力完成了此次结对任务。
功能结构图
关键代码
首页main.html的ajax
用于向后端InfoServlet类传递数据,获得数据data后通过js修改首页第一部分的累计确诊人数(id:one)等数据。
$.ajax({
url: "InfoServlet?method=crawl0",
async: true,
type: "POST",
data: {
},
success: function (data) {
var json = JSON.parse(data);//data为接收的后台返回的数据
//alert(json);
// var id1 = json[0].provinceName;
//alert(id1);
var c=document.createElement("a");
c.text=json[2];
var three=document.getElementById("three");
three.appendChild(c);
var b=document.createElement("a");
b.text=json[1];
var two=document.getElementById("two");
two.appendChild(b);
var d=document.createElement("a");
d.text= json[3];
var four=document.getElementById("four");
four.appendChild(d)
var date=document.createElement("a");
date.text=json[4];
var left=document.getElementById("left");
left.appendChild(date)
var a=document.createElement("a");
a.text=json[0];
var one=document.getElementById("one");
one.appendChild(a);
},
error : function() {
alert("请求失败");
},
})
渲染地图的ajax部分
与上方代码大同小异。
$.ajax({
url : "InfoServlet?method=crawl",
async : true,
type : "POST",
data : {
"time" : time
},
success : function(data) {
var json = eval("(" + data + ")");//data为接收的后台返回的数据;
//alert(json.length);
var id1 = json[0].provinceName;
//alert(id1);
dt = data;
mydata1 = [];
for (var i = 0; i < json.length; i++) {
var d = {
};
d["name"] = json[i].provinceShortName;
d["value"] = json[i].currentConfirmedCount;
d["yisi_num"] = json[i].suspectedCount;
d["cured_num"] = json[i].curedCount;
d["dead_num"] = json[i].deadCount;
mydata1.push(d);
console.log(json[i]);
}
var optionMap = {
tooltip : {
formatter : function(params) {
return params['data'].name + '<br/>' + '确诊人数 : '
+ params['data'].value + '<br/>' + '死亡人数 : '
+ params['data'].dead_num + '<br/>' + '治愈人数 : '
+ params['data'].cured_num + '<br/>'+ '疑似患者人数 : '
+ params['data'].yisi_num;
}//数据格式化
},
//左侧小导航图标
visualMap : {
min: 0,
max: 300,
left: 'left',
top: 'bottom',
text: ['高','低'],//取值范围的文字
inRange: {
color: ['#fff5ee', '#dd0515']//取值范围的颜色
},
show:true//图注
},
geo: {
map: 'china',
roam: false,//不开启缩放和平移
zoom:1.23,//视角缩放比例
label: {
normal: {
show: true,
fontSize:'10',
color: 'rgba(0,0,0,0.7)'
}
},
itemStyle: {
normal:{
borderColor: 'rgba(0, 0, 0, 0.2)'
},
emphasis:{
areaColor: '#F3B329',//鼠标选择区域颜色
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
},
//配置属性
series : [
{
name: '确诊人数',
type: 'map',
geoIndex: 0,
data:mydata1
}
]
};
//初始化echarts实例
var myChart = echarts.init(document.getElementById('content1'));
//使用制定的配置项和数据显示图表
myChart.setOption(optionMap);
myChart.on('click', function (params) {
window.location.href="/Servlet/DetailInformation.html?name="+params.name+"";
});
},
error : function() {
alert("请求失败");
},
dataType : "json"
});
后端InfoServlet类
用于处理前端ajax传递的url参数,根据method的不同调用不同的方法来为前端提供数据。
public class InfoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
int[][] number = new int[31][6];
public InfoServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String method = request.getParameter("method");
if(method.equals("tu")) {
try {
tu(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
else if(method.equals("crawl")) {
try {
crawl(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
else if(method.equals("crawl0")) {
try {
crawl0(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
else if(method.equals("crawl2")) {
try {
crawl2(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}else if(method.equals("d")) {
try {
d(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
//response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @param request
* @param response
* @throws Exception
*/
private void tu(HttpServletRequest request, HttpServletResponse response)throws Exception {
String time = request.getParameter("time");
String[] args = {"list","-log","D:\eclipse\workspace\Servlet\log\","-out","D:\output.txt","-date"
,time};
number = InfectStatistic2.main(args);
for(int i = 0;i < 31;i++)
{
number[i][5] = number[i][0] + number[i][2] +number[i][3];
}
Gson gson = new Gson();
String json = gson.toJson(number);
System.out.println(json);
response.getWriter().write(json);
}
private void crawl(HttpServletRequest request, HttpServletResponse response)throws Exception{
String list = WuhanService.getAreaStat();
Gson gson = new Gson();
String json = gson.toJson(list);
System.out.println(json);
response.getWriter().write(json);
}
private void crawl0(HttpServletRequest request, HttpServletResponse response)throws Exception{
String[] list = WuhanService.getStatisticsService();
Gson gson = new Gson();
String json = gson.toJson(list);
System.out.println(json);
response.getWriter().write(json);
}
private void crawl2(HttpServletRequest request, HttpServletResponse response)throws Exception{
String list = WuhanService.getAllHistoryDataService();
Gson gson = new Gson();
String json = gson.toJson(list);
System.out.println(json);
response.getWriter().write(json);
}
private void d(HttpServletRequest request, HttpServletResponse response)throws SQLException, ServletException, IOException {
String name = request.getParameter("name");
//System.out.println(name);
String list = ApiRequest.result(name);
//Gson gson = new Gson();
//String json = gson.toJson(list);
System.out.println(list);
response.getWriter().write(list);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
WuhanService类
用于获取丁香园的累计确诊人数、疑似病例、治愈人数、死亡人数等数据。
/**
* 获取丁香医生的总共确诊病例、疑似病例、治愈人数、死亡人数等数据
* @return
*/
public static String[] getStatisticsService(){
String url="https://ncov.dxy.cn/ncovh5/view/pneumonia";
//模拟请求
HttpPojo httpPojo = new HttpPojo();
httpPojo.setHttpHost("ncov.dxy.cn");
httpPojo.setHttpAccept("*/*");
httpPojo.setHttpConnection("keep-alive");
httpPojo.setHttpUserAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
httpPojo.setHttpReferer("https://ncov.dxy.cn");
httpPojo.setHttpOrigin("https://ncov.dxy.cn");
Map paramObj = new HashMap();
String htmlResult = httpSendGet(url, paramObj, httpPojo); //整个html页面
//System.out.println(htmlResult);
//正则获取数据
//因为html的数据格式看着就像json格式,所以我们正则获取json:{"id":1,"createTime":1579537899000,"modifyTime":1580571956000,"infectSource":"野生动物,可能为中华菊头蝠","passWay":"经呼吸道飞沫传播,亦可通过接触传播","imgUrl":"https://img1.dxycdn.com/2020/0201/450/3394153392393266839-135.png","dailyPic":"https://img1.dxycdn.com/2020/0201/693/3394145745204021706-135.png","summary":"","deleted":false,"countRemark":"","confirmedCount":11901,"suspectedCount":17988,"curedCount":275,"deadCount":259,"virus":"新型冠状病毒 2019-nCoV","remark1":"易感人群: 人群普遍易感。老年人及有基础疾病者感染后病情较重,儿童及婴幼儿也有发病","remark2":"潜伏期: 一般为 3~7 天,最长不超过 14 天,潜伏期内存在传染性","remark3":"","remark4":"","remark5":"","generalRemark":"疑似病例数来自国家卫健委数据,目前为全国数据,未分省市自治区等","abroadRemark":""}
String reg= "window.getStatisticsService = (.*?)\}(?=catch)";
Pattern totalPattern = Pattern.compile(reg);
Matcher totalMatcher = totalPattern.matcher(htmlResult);
String result="";
String[] result1 = new String[5];
if (totalMatcher.find()){
result = totalMatcher.group(1);
System.out.println(result);
JSONObject jsonObject = JSONObject.parseObject(result);
result1[0] = jsonObject.getString("confirmedCount");
result1[1] = jsonObject.getString("suspectedCount");
result1[2] = jsonObject.getString("curedCount");
result1[3] = jsonObject.getString("deadCount");
result1[4] = getTimeFormat(jsonObject.getString("modifyTime"));
//System.out.println("confirmedCount:"+confirmedCount);
}
System.out.println(result1);
return result1;
}
心路历程与收获
心路历程
- 陈朝帏:在项目一开始的时候对spring的技术有点陌生,于是在队友编写前端时努力学习了解了spring框架,掌握了前后端的连接技术和爬虫数据的应用,在与队友的合作中终于完成了此次的作业。
- 郑小华:由于此次的作业限时一周,并且自身对于许多技术的不了解,导致刚看到题目时是有点绝望的。之后呢,当决定从简单之处开始入手后,队友也紧跟其后开始尝试新的技术,通力合作后发现这个项目其实是可以完成的,除了过程十分艰辛之外,其实在项目结束之后心里更多的是一丝学到新技术的喜悦。
评价队友
- 陈朝帏:郑小华同学是一个很好的队友,努力参与团队工作,项目安排十分合理,希望有机会继续合作!
- 郑小华:陈朝帏同学是一个积极向上的大好青年,努力克服困难学习技术,是一个不可多得的队友!希望下次有机会一起组队!
阅读《构建之法》收获
- 代码规范是结对作业的基础,只有先设计好了代码规范,才不会将过多时间浪费在读懂杂乱无章的代码上,结对合作的效率才能提高。
- 软件团队和软件开发流程有各种形式,适用于不同的人员和需求,我们要根据自己团队成员的特点和项目的特性选择适合自己的软件团队模式。
- TSP原则:
- 使用妥善定义的流程,流程中的每一步都是可以重复、可以衡量结果的。
- 团队的各个成员对团队的目标、角色、产品都有统一的理解。
- 尽量使用成熟的技术和做法。
- 尽量多地收集数据(也包括对团队不利的数据),并用数据来帮助团队做出理性的决定。
- 制定切合实际的计划和承诺,团队计划要由负责具体执行的角色来制定(而不是从上级而来)。
- 增强团队的自我管理能力
- 专注于提高质量,争取在软件生命周期的早期发现问题。最有效提高质量的办法是做全面而细致的设计工作(而不是在后期匆忙修复问题)。