这个作业属于哪个课程 | 2020春s班 |
---|---|
这个作业要求在哪里 | 结对第二次作业——某次疫情统计可视化的实现 |
结对学号 | 041702303、221701238 |
这个作业的目标 | 1、结合寒假第二次作业的成果,使用web技术实现原型设计中的部分功能 2、使用github进行合作开发 3、学习《构建之法》第四章至第五章的内容。 |
作业正文 | 1、本博客正文 2、github项目代码 |
其他参考文献 | 1、《码出高效_阿里巴巴Java开发手册》 2、《构建之法》 |
1、Github项目地址和代码规范链接
Github项目主仓库
代码规范链接
2、成品展示
2.1 基本功能实现
1、进入主页,显示当前最新的全国疫情数据以及相应的显示现有确诊人数的疫情地图,鼠标移到每个省份会显示高亮和该省份的具体信息的悬浮块。
2、选择指定的日期,点击“确认”后即可显示该日期的全国疫情数据以及相应的疫情地图。
3、点击“现有确诊”,显示现有确诊人数的疫情地图;点击“累计确诊”,则显示累计确诊人数的疫情地图。
4、点击地图具体信息悬浮块中的详情,即可跳转到对应省份的详情疫情信息的界面,包含了最新疫情数据以及相关数据的折线图(默认显示新增确诊趋势图)。
5、选择指定的日期,点击“确认”后即可显示该日期的该省份疫情数据以及以及相关数据的折线图(默认显示新增确诊趋势图)。
6、点击“新增确诊趋势”,显示新增确诊趋势的折线图;点击“累计确诊趋势”,显示累计确诊趋势的折线图;点击“累计治愈/死亡”,显示累计治愈/死亡的折线图。
2.2 拓展功能实现
1、点击“热点新闻”,即可使用热点新闻功能,查看最新最热门的疫情新闻。
2、点击“疫情科普”,即可使用疫情科普功能,学习新冠病毒的相关知识,防患于未然。
3、点击“口罩预约”,即可使用口罩预约功能,填写相关信息预约口罩,信息无误则提示预约成功。
备注:由于技术和其他问题,拓展功能并没有完全能够实现。希望在今后的学习中能够得以完善(*^▽^*)。
3、结对过程
3.1 总体流程
- 明确分工,一个人主要负责前端界面设计,一个人主要负责后端开发,并做好时间规划
- 分别学习相关的知识和技术,并加以应用
- 通过视频和文字交流探讨项目的开发
- 实现过程发现开发过程中的困难,思考讨论寻找解决方案
- 逐步合作完成博客内容,总结过程
3.2 结对照片
3.3 部分聊天记录截图
4、设计实现过程
4.1 设计工具和技术
- 开发工具:Eclipse,Intellij IDEA,Firefox浏览器。
- 使用技术:JSP,Servlet,Css,Javascript,JQuery,Echarts,Sqlite,Ajax。
4.2 项目分解与实现
- 项目结构设计:使用JavaEE框架,即使用JSP+Servlet+JavaBean制作动态网页。
- 疫情数据:一开始想使用爬虫在网页上抓取数据,但感觉难度有点大便放弃了这个想法,转而使用Sqlite数据库,并从相关文件中读取数据保存到数据库中。
- 疫情地图及省份疫情趋势折线图:使用Echarts制作,并嵌入到指定JSP中。
- 疫情数据按日期查询:使用Ajax技术,输入日期确认后,后台获取响应的json后取出数据并设定相应参数的值,使网页可以快速显示该日期的具体疫情数据以及相应Echarts图像。
4.3 功能结构图
5、关键代码说明
1、ProvinceServlet:处理首页的疫情数据和疫情地图的请求,默认发送最新一天的数据。通过接收首页表单中填写的日期信息,从数据库中读取该日期及前一天的所有数据并发送回首页和疫情地图。
public class ProvinceServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
ProvinceDAO provinceDAO = new ProvinceDAOImpl();
String year = request.getParameter("year");
String month = request.getParameter("month");
String day = request.getParameter("day");
String type = request.getParameter("type");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Map<String, Object> map = new HashMap<String, Object>();
List<String> provinceName = new ArrayList<String>();
List<Integer> provinceValue = new ArrayList<Integer>();
List<Integer> nation = new ArrayList<Integer>();
String dateString = "";
String yesterdayString = "";
//判断日期合法
if (year != null && month != null && day != null && type != null) {
if (!year.equals("") && !month.equals("") && !day.equals("")) {
if (year.compareTo("2020") == 0
&& ((Integer.parseInt(month) == 2 && Integer.parseInt(day) > 0 && Integer.parseInt(day) < 3)
|| (Integer.parseInt(month) == 1 && Integer.parseInt(day) > 18
&& Integer.parseInt(day) < 32))) {
dateString = year + "-" + month + "-" + day;
} else {
dateString = "2020-02-02";
}
} else {
dateString = "2020-02-02";
}
try {
yesterdayString = DateUtil.getYesterday(dateString);
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
//写入日期前一天数据
if (format.parse(yesterdayString).getTime() < format.parse("2020-01-19").getTime()) {
nation.add(0);
nation.add(0);
nation.add(0);
nation.add(0);
nation.add(0);
nation.add(0);
} else {
Date yesterday = new Date(format.parse(yesterdayString).getTime());
Province p = provinceDAO.get("全国", yesterday);
nation.add(p.getNowIp());
nation.add(p.getNowSp());
nation.add(p.getAllIp());
nation.add(p.getAllSp());
nation.add(p.getAllCure());
nation.add(p.getAlldead());
}
Province data[] = provinceDAO.getListByDate(new Date(format.parse(dateString).getTime()));
for (Province p : data) {
if (!p.getName().equals("全国")) {
provinceName.add(p.getName());
if (type != null && type.equals("now")) {
provinceValue.add(p.getNowIp());
} else {
provinceValue.add(p.getAllIp());
}
} else {
//写入当天日期数据
nation.add(p.getNowIp());
nation.add(p.getNowSp());
nation.add(p.getAllIp());
nation.add(p.getAllSp());
nation.add(p.getAllCure());
nation.add(p.getAlldead());
map.put("全国", nation);
}
}
//写入map
map.put("省名", provinceName);
map.put("值", provinceValue);
//转换成接送发送
JSONObject json = JSONObject.parseObject(JSON.toJSONString(map));
out.write(json.toString());
out.flush();
out.close();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
2、MoreServlet:处理省份详情界面的疫情数据和疫情地图的请求,默认发送最新一天的数据。通过接收首页表单中填写的日期信息,从数据库中读取该日期及前一天的所有数据并发送回首页和疫情趋势折线图。
public class MoreServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
ProvinceDAO provinceDAO = new ProvinceDAOImpl();
String year = request.getParameter("year");
String month = request.getParameter("month");
String day = request.getParameter("day");
String type = request.getParameter("type");
String name = request.getParameter("name");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Map<String, Object> map = new HashMap<String, Object>();
List<Integer> province = new ArrayList<Integer>();
List<Integer> allIpData = new ArrayList<Integer>();
List<Integer> newIpData = new ArrayList<Integer>();
List<Integer> allCureData = new ArrayList<Integer>();
List<Integer> allDeadData = new ArrayList<Integer>();
List<String> dates = new ArrayList<String>();
String dateString = "";
String yesterdayString = "";
//检测数据合法
if (year != null && month != null && day != null && type != null && name != null) {
if (!year.equals("") && !month.equals("") && !day.equals("")) {
if (year.compareTo("2020") == 0
&& ((Integer.parseInt(month) == 2 && Integer.parseInt(day) > 0 && Integer.parseInt(day) < 3)
|| (Integer.parseInt(month) == 1 && Integer.parseInt(day) > 18
&& Integer.parseInt(day) < 32))) {
dateString = year + "-" + month + "-" + day;
}
else {
dateString = "2020-02-02";
}
} else {
dateString = "2020-02-02";
}
try {
yesterdayString = DateUtil.getYesterday(dateString);
Date today = new Date(format.parse(dateString).getTime());
Province data[] = provinceDAO.getListByName(name);
Province p = provinceDAO.get(name, new Date(format.parse(dateString).getTime()));
//写入当天日期疫情数据
province.add(p.getNowIp());
province.add(p.getNowSp());
province.add(p.getAllIp());
province.add(p.getAllSp());
province.add(p.getAllCure());
province.add(p.getAlldead());
//写入前一天疫情数据
if (format.parse(yesterdayString).getTime() < format.parse("2020-01-19").getTime()) {
province.add(0);
province.add(0);
province.add(0);
province.add(0);
province.add(0);
province.add(0);
} else {
p = provinceDAO.get(name, new Date(format.parse(yesterdayString).getTime()));
province.add(p.getNowIp());
province.add(p.getNowSp());
province.add(p.getAllIp());
province.add(p.getAllSp());
province.add(p.getAllCure());
province.add(p.getAlldead());
}
String tempday = "2020-01-19";
//提取小于当天的对象
for (Province p1 : data) {
if (p1.getDate().getTime() <= today.getTime()) {
//将未含有数据的对象数据(0)写入
if (format.format(p1.getDate()).compareTo(tempday) > 0) {
while (format.format(p1.getDate()).compareTo(tempday) > 0) {
dates.add(tempday);
newIpData.add(0);
allCureData.add(0);
allDeadData.add(0);
allIpData.add(0);
tempday = DateUtil.getNextday(tempday);
}
tempday = "2020-12-31";
}
//按照类型写入数据
if (type.equals("newIp")) {
yesterdayString = DateUtil.getYesterday(format.format(p1.getDate()));
//写入新增--累计的差值
if (format.parse(yesterdayString).getTime() < format.parse("2020-01-19").getTime()) {
newIpData.add(p1.getAllIp());
} else {
p = provinceDAO.get(name, new Date(format.parse(yesterdayString).getTime()));
newIpData.add(p1.getAllIp() - p.getAllIp());
}
} else if (type.equals("allIp")) {
allIpData.add(p1.getAllIp());
} else {
allCureData.add(p1.getAllCure());
allDeadData.add(p1.getAlldead());
}
//写入日期
dates.add(format.format(p1.getDate()));
}
}
//存入map
map.put("data", province);
map.put("allCure", allCureData);
map.put("allDead", allDeadData);
map.put("allIp", allIpData);
map.put("newIp", newIpData);
map.put("date", dates);
//转换成json发送
JSONObject json = JSONObject.parseObject(JSON.toJSONString(map));
out.write(json.toString());
out.flush();
out.close();
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
> 3、nationStatistic.jsp中的getData函数:发送请求到ProvinceServlet并获取指定日期的全国疫情数据,并返回在首页中显示详细数据
function getData() {
$.ajax({
type : "get",
async : true, //异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行)
url : "test", //请求发送到ProvinceServlet处
data : {
year : $("#year").val(),
month : $("#month").val(),
day : $("#day").val(),
type : type
},
dataType : "json", //返回数据形式为json
success : function(result) {
//解析json
var nationData = result["全国"];
var provinceName = result["省名"];
var provinceValue = result["值"];
var provinceData = new Array();
for (var i = 0; i < provinceName.length; i++) {
var row = new Object();
row.name = provinceName[i];
row.value = provinceValue[i];
provinceData.push(row);
}
//设置数据区域
$(".dataNum1").text(nationData[6]);
$(".dataNumYesterday1").text(
showSign(nationData[6] - nationData[0]));
$(".dataNum2").text(nationData[7]);
$(".dataNumYesterday2").text(
showSign(nationData[7] - nationData[1]));
$(".dataNum4").text(nationData[8]);
$(".dataNumYesterday4").text(
showSign(nationData[8] - nationData[2]));
$(".dataNum5").text(nationData[10]);
$(".dataNumYesterday5").text(
showSign(nationData[10] - nationData[4]));
$(".dataNum6").text(nationData[11]);
$(".dataNumYesterday6").text(
showSign(nationData[11] - nationData[5]));
myChart.setOption(fillData(provinceData), true);
}
})
}
> 4、trend.jsp中的getNewIpData函数:发送请求到MoreServlet并获取指定日期的省份新增确诊人数数据,并返回到省份详情页面中设置新增确诊趋势的折线图。
function getNewIpData() {
$.ajax({ //使用JQuery内置的Ajax方法
type : "get", //post请求方式
async : true, //异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行)
url : "MoreServlet",
data : {
name : name,
type : type,
year : $("#year").val(),
month : $("#month").val(),
day : $("#day").val()
},
dataType : "json", //返回数据形式为json
success : function(result) {
//document.write("123");
//请求成功时执行该函数内容,result即为服务器返回的json对象
if (result != null) {
//解析json
newIp = result["newIp"];
dates = result["date"];
data = result["data"];
$(".dataNum1").text(data[0]);
$(".dataNumYesterday1").text(showSign(data[0] - data[6]));
$(".dataNum2").text(data[2]);
$(".dataNumYesterday2").text(showSign(data[2] - data[8]));
$(".dataNum3").text(data[4]);
$(".dataNumYesterday3").text(showSign(data[4] - data[10]));
$(".dataNum4").text(data[5]);
$(".dataNumYesterday4").text(showSign(data[5] - data[11]));
...
}
},
})
}
}
6、总结与感想
6.1 阅读心得
软件都是在相互合作中完成的,在合作中,首先应先制定好统一的代码标准,在开发过程中需要互相审查对方的代码以便发现问题。团队开发按照一定的软件开发流程的体系可以让工作更加简单明了,提高项目完成度。
6.2 工作感想
周同学:在本次项目中我又学习到了新的知识,也更加感受到了结对合作的魅力。在完成项目后我感到非常开心。希望在接下来的团队作业中能够持续发光发亮。
陈同学:这次作业是为了完成第一次作业原型的部分功能,刚开始原型是做成app形式,但是由于时间以及作业要求,决定与队友做成web,主要用jsp以及servlet完成的(刚学只会这个),前期困难点在于数据的获取(爬虫),在尝试查阅资料后果断选择了内嵌数据库,使用sqlite还算勉强可以上手,接着是地图和趋势图的完成,经过学习学会和利用echarts+jsp+JavaScript+jQuery实现Ajax动态请求数据响应用户。这次作业主要还是进行结对的练习,所以内容也相对团队项目要求简单,在经过几天的学习,体会到了合作编程的要求和需求,同时自己在echarts图表和jsp、servlet有了更深入的了解掌握,有了此次经验相信在以后的团队合作能够更加熟练。
6.3 队友评价
周同学:陈同学学习能力、编程能力强,易于沟通交流,是一个非常棒的队友!他的后端开发给予我极大的帮助,也让本次作业能够更好地完成。
陈同学:队友是个比较会钻研的同学,在结对作业中对我还是帮助很多的,相对于我而言,队友的前端布局设计给了这次作业很大的帮助,同时队友还是很认真的完成作业,这是比较令人开心的,总之队友是个好学生以后也会是个好员工或者好队友。