结对第二次作业
这个作业属于哪个课程 | 2020软件工程w班 |
---|---|
这个作业要求在哪里 | 作业要求 |
这个作业的目标 | 针对原型设计实现疫情统计网页 |
结对学号 | |
作业正文 | .... |
其他参考文献 | 《构建之法》 |
一、仓库链接和代码规范链接
二、成品展示
-
全国疫情数据展示可以显示当前日期下累计确诊、现有确诊、累计死亡等实时数据,并且可以通过选择日期展示不同日期的数据
-
全国疫情通过地图展示,地图上不同数据通过不同的颜色显示,其中鼠标放置在具体省份展示人数详情,点击该省份可以跳转到具体省份的位置,分为现有确诊地图和累计确诊地图,点击上方按钮选择查看不同数据信息
-
省份疫情展示:上方显示该省份名称,还有具体日期下该省份的累计确诊、累计疑似、累计死亡等数据,与全国数据显示大致相同,可以通过选择日期选择具体日期。
-
省份疫情数据展示:通过折线图显示具体数据变化趋势,以便更加明显的观察数据走向,其中鼠标定位折线图具体位置可以显示数据,通过上方按钮可以选择查看累计确诊趋势和累计疑似趋势以及累计治愈/死亡趋势。
-
下面为具体演示
- 输入日期格式演示
- 全国页面地图演示
- 点击省份跳转演示
- 省份数据及折现图演示
三、结对过程
-
开始主要讨论一些分工,最后决定前端后端分开,前端用jsp+js+css后端用servlet+java+数据库,其中遇到很多奇奇怪怪的问题,最后解决之后都超级开心
-
大概讨论出一些思路 就开始分工做自己的事情
-
这里遇到一些问题 最后浪费不少时间才解决 收获很多
-
这里是一些前后端的沟通问题
四、设计实现过程
-
后端:
-
后端主要用servlet为控制器,pojo+DAO为逻辑层的javaEE的模式设计,页面显示由前端jsp显示。本来打算用纯前端完成本次作业,但在js读取文件这个模块上遇到了问题,临时改用javaEE的模式。在设计具体的代码前,因为不会爬虫且中途换成了javaEE实现,我先思考了数据库表的存储结构。最后采用省份名为表名的结构,这个决定让我后面的整个代码出现了部分冗余和麻烦,主要原因是在设计完基本的模块准备访问数据库的时候才发现我的mysql版本不支持把表名作为参数传入sql语句里,这个部分的错误花了很多时间来弥补。
-
设计的第一步肯定是先把后端各个模块dao pojo 设计好,在设计实现取数据时还增加了getdefaultdata这个方法,这也是在后面写代码的过程中发现的,第一次载入index.jsp时没办法获得数据,就在jsp的body标签了写了判断参数是否为空的代码块,为空就访问servlet调用getdefaultdata并转发。点击全国地图上的省份跳转到具体省份页面时的处理也类似。这也是整个过程中碰到的比较大的问题
-
然后就是选择具体时间这个功能,设计了dateServlet专门处理用户在两个页面输入提交的日期,调用getxxxxdata(string)方法将用户输入的日期传入,处理请求并转发。
-
-
前端:
-
前端我们使用html+css+jsp实现具体界面设计,由于能力有限没有使用框架等来实现,用单纯的html和css做出具体页面
-
主要分为两个具体视图:全国疫情视图和省份疫情视图
-
JavaScript实现地图显示和折现图,具体使用echart设置,在地图和折现切换中使用jquery来实现显示和隐藏
-
<script type="text/javascript" src="./js/jquery-3.4.1.js"></script> <script type="text/javascript"> $(document).ready(function(){ $("div#u39").hide(); $("#现有确诊").click(function(){ $("div#u39").hide(); $("div#u38").show(); }); $("#累计确诊").click(function(){ $("div#u38").hide(); $("div#u39").show(); }); }); </script>
-
五、功能结构图
六、代码说明
1、后端:
-
pojo 省份对象 封装了ip sp 等数据 及对应的set get方法
-
package pojo; public class Province { private int ip; private int ipcount; private int sp; private int spcount; private int cure; private int curecount; private int dead; private int deadcount; public int getip() { return ip; } public void setip(int ip) { this.ip = ip; } public int getipcount() { return ipcount; } public void setipcount(int ipcount) { this.ipcount = ipcount; } public int getsp() { return sp; } public void setsp(int sp) { this.sp = sp; } public int getspcount() { return spcount; } public void setspcount(int spcount) { this.spcount = spcount; } public int getcure() { return cure; } public void setcure(int cure) { this.cure = cure; } public int getcurecount() { return curecount; } public void setcurecount(int curecount) { this.curecount = curecount; } public int getdead() { return dead; } public void setdead(int dead) { this.dead = dead; } public int getdeadcount() { return deadcount; } public void setdeadcount(int deadcount) { this.deadcount = deadcount; } }
-
DAO 接口 default方法日期默认为2020.02.02(主要用于第一次进入jsp网页时)
-
package dao; import pojo.Province; public interface ProvinceDAO { Province getDefaultPceData(); Province getPceData(String date); Province getDefaultNationData(); Province getNationData(String date); }
-
DAO 实现
-
全国页面默认日期 返回pojo对象
-
public Province getDefaultNationData() { String sql = "select * from 全国 where date = '2020.02.02'"; Province pce = new Province(); ResultSet rs = null; try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql);) { rs = ps.executeQuery(); while(rs.next()) { int ipnum = rs.getInt("ipcount"); int spnum = rs.getInt("spcount"); int curenum = rs.getInt("curecount"); int deadnum = rs.getInt("deadcount"); pce.setipcount(ipnum); pce.setspcount(spnum); pce.setcurecount(curenum); pce.setdeadcount(deadnum); } } catch (SQLException e) { e.printStackTrace(); } return pce; }
-
全国页面 日期为参数 返回pojo对象
-
@Override public Province getNationData(String date) { // TODO Auto-generated method stub String udate = date; String sql = "select * from 全国 where date = ?"; Province pce = new Province(); ResultSet rs = null; try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql);) { ps.setString(1, udate); rs = ps.executeQuery(); while(rs.next()) { int ipnum = rs.getInt("ipcount"); int spnum = rs.getInt("spcount"); int curenum = rs.getInt("curecount"); int deadnum = rs.getInt("deadcount"); pce.setipcount(ipnum); pce.setspcount(spnum); pce.setcurecount(curenum); pce.setdeadcount(deadnum); } } catch (SQLException e) { e.printStackTrace(); } return pce; }
-
省份实现类似
-
dateServlet 处理两个页面的选择具体日期请求 并带值返回
-
package dao; import pojo.Province; import util.DBUtil; import java.sql.*; public class ProvinceDAOImpl implements ProvinceDAO{ @Override public Province getDefaultNationData() { String sql = "select * from 全国 where date = '2020.02.02'"; Province pce = new Province(); ResultSet rs = null; try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql);) { rs = ps.executeQuery(); while(rs.next()) { int ipnum = rs.getInt("ipcount"); int spnum = rs.getInt("spcount"); int curenum = rs.getInt("curecount"); int deadnum = rs.getInt("deadcount"); pce.setipcount(ipnum); pce.setspcount(spnum); pce.setcurecount(curenum); pce.setdeadcount(deadnum); } } catch (SQLException e) { e.printStackTrace(); } return pce; } @Override public Province getNationData(String date) { // TODO Auto-generated method stub String udate = date; String sql = "select * from 全国 where date = ?"; Province pce = new Province(); ResultSet rs = null; try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql);) { ps.setString(1, udate); rs = ps.executeQuery(); while(rs.next()) { int ipnum = rs.getInt("ipcount"); int spnum = rs.getInt("spcount"); int curenum = rs.getInt("curecount"); int deadnum = rs.getInt("deadcount"); pce.setipcount(ipnum); pce.setspcount(spnum); pce.setcurecount(curenum); pce.setdeadcount(deadnum); } } catch (SQLException e) { e.printStackTrace(); } return pce; } @Override public Province getDefaultPceData() { // TODO Auto-generated method stub String sql = "select * from 湖北 where date = '2020.02.02'"; Province pce = new Province(); ResultSet rs = null; try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql);) { rs = ps.executeQuery(); while(rs.next()) { int ipnum = rs.getInt("ipcount"); int spnum = rs.getInt("spcount"); int curenum = rs.getInt("curecount"); int deadnum = rs.getInt("deadcount"); pce.setipcount(ipnum); pce.setspcount(spnum); pce.setcurecount(curenum); pce.setdeadcount(deadnum); } } catch (SQLException e) { e.printStackTrace(); } return pce; } @Override public Province getPceData( String date) { // TODO Auto-generated method stub String udate = date; String sql = "select * from 湖北 where date = ?"; Province pce = new Province(); ResultSet rs = null; try (Connection c = DBUtil.getConnection(); PreparedStatement ps = c.prepareStatement(sql);) { ps.setString(1, udate); rs = ps.executeQuery(); while(rs.next()) { int ipnum = rs.getInt("ipcount"); int spnum = rs.getInt("spcount"); int curenum = rs.getInt("curecount"); int deadnum = rs.getInt("deadcount"); pce.setipcount(ipnum); pce.setspcount(spnum); pce.setcurecount(curenum); pce.setdeadcount(deadnum); } } catch (SQLException e) { e.printStackTrace(); } return pce; } }
-
nationServlet 处理全国页面(index.jsp)的第一次加载的请求,并带数据返回
-
package servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import dao.ProvinceDAO; import dao.ProvinceDAOImpl; import pojo.Province; /** * Servlet implementation class provinServlet */ @WebServlet("/nationServlet") public class nationServlet extends HttpServlet { private ProvinceDAO provinceDAO = new ProvinceDAOImpl(); private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public nationServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub Province nation = getDefaultNationData(); request.setAttribute("nation", nation); request.setAttribute("nationdate", "2020.02.02"); request.getRequestDispatcher("index.jsp").forward(request,response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub doGet(request, response); } private Province getDefaultNationData() { Province pce = provinceDAO.getDefaultNationData(); return pce; } }
-
省份servlet同
-
数据库工具类 封装访问数据库的代码
-
package util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DBUtil { static String ip = "127.0.0.1"; static int port = 3306; static String database = "疫情统计"; static String encoding = "UTF-8"; static String loginName = "root"; static String password = "wjl6588993"; static boolean isuseSSL= false; static String Timezone= "GMT%2B8"; static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { String url = String.format("jdbc:mysql://%s:%d/%s?useSSL=%b&serverTimezone=%s&characterEncoding=%s", ip, port, database,isuseSSL,Timezone, encoding); return DriverManager.getConnection(url, loginName, password); } /* 关闭连接的方法 */ public static void close(ResultSet rs, Statement stmt, Connection conn) { try { if (rs != null) rs.close(); } catch (Exception ex) { ex.printStackTrace(); } try { if (stmt != null) stmt.close(); } catch (Exception ex) { ex.printStackTrace(); } try { if (conn != null) conn.close(); } catch (Exception ex) { ex.printStackTrace(); } } public static void main(String[] args) throws SQLException { System.out.println(getConnection()); } }
2、前端:
-
对封面的主要设计
-
<!--封面--> <div class="cover" id="map_clock"> <div class="cover_img"> <img id="header_img" class="img " src="image/u0.png" width="100%"> <h1>科学防护 共渡难关</h1> <h2>肺炎疫情实时动态播报</h2> </div> </div> <form class="form_date" action="date.jsp" method="POST" > 日期: <input type="text" name="user_date" placeholder="输入格式:xxxx.xx.xx" /> </form> <div class="cover_cards"> <div class="cover_data_china noNewsScroll"> <div class="cover_confirm"> <h4>累计确诊</h4> <div class="number">-</div> </div> <div class="cover_dead"> <h4>累计死亡</h4> <div class="number">-</div> </div> <div class="cover_heal"> <h4>累计治愈</h4> <div class="number">-</div> </div> <div class="cover_today_confirm"> <h4>现有确诊</h4> <div class="number">22534</div> </div> <div class="cover_severe"> <h4>现有重症</h4> <div class="number">11234</div> </div> <div class="cover_suspect"> <h4>现有疑似</h4> <div class="number">-</div> </div> <div class="cover_time"> <h5>截止日期:</h5> </div> </div> </div>
- 设计疫情地图
<div class="map_block mb"> <div class="wrap" style="height: 700px;"> <div class="map_controls"> <button id="现有确诊" type="button">现有确诊</button> <button id="累计确诊" type="button">累计确诊</button> <div id="u38" style="width: 500px;height: 500px; text-align: center; margin: auto;"></div> <div id="u39" style="width: 500px;height: 500px; text-align: center; margin: auto;"></div> </div> </div> </div>
-
具体地图实现和折现实现的js代码部分
-
series: [{ name: '确诊', type: 'map', mapType: 'china', roam: false, label: { normal: { show: true //省份名称 }, emphasis: { show: false } }, itemStyle:{ normal:{ borderColor: 'rgba(0, 0, 0, 0.2)' }, emphasis:{ areaColor: '#f30d1d', shadowOffsetX: 0, shadowOffsetY: 0, shadowBlur: 20, borderWidth: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } }, data:mydata //数据 }] };
-
省份点击跳转
china_chart.setOption(option); china_chart.on('click', function (param) { var selected = param.name; if (selected) { switch(selected){ case '北京': location.href = "index_province.html"; break; ... default: break; } } }); function randomData() { return Math.round(Math.random()*500); }
-
-
折现图实现代码
-
xAxis: { type: 'category', data: ['1.27', '1.29', '1.31', '2.2', '2.4', '2.6', '2.8', '2.10', '2.12', '2.14', '2.16', '2.18'], // x轴数据 name: '日期', // x轴名称 // x轴名称样式 nameTextStyle: { fontWeight: 600, fontSize: 18 } }, yAxis: { type: 'value', name: '人数', // y轴名称 // y轴名称样式 nameTextStyle: { fontWeight: 600, fontSize: 18 } },
七、收获和心路历程
221701303:
首先阅读《构建之法》了解到更多在日常中没有注意到的细节和一些代码规范,其中更多的是完成一项项目中最重要的思想,在本次结对中,更多的考验了同伴之间的配合和协调,有很多自己不懂的东西恰好伙伴懂,更好的配合,一起完成这项任务,在其中学会了很多,搭建服务器、前端制作更加了解细节,了解到了更加深入的知识,虽然学会了搭建服务器但是最终由于没有实现云数据库,我的云服务器没有起到他的作用(害....)不过还是很开心完成这项任务的同时学到更多的知识。
221701326:
-
阅读《构建之法》收获很多,从更专业系统的层面了解了代码规范,和完成项目中的思想方法,对我的认知和具体的实践写代码有很大的帮助。这次结对作业的分工让我对结对编程的好处有了更深刻的理解,具体来说,我在css和html部分比较薄弱,很多样式被我设计的不是很友好,队友正好i擅长这部分,我的困难也因此解决。
-
本来打算用纯前端完成本次作业,临时改用javaEE的模式。采用省份名为表名的结构,这个决定让我后面的整个代码出现了部分冗余和麻烦,主要原因是在设计完基本的模块准备访问数据库的时候才发现我的mysql版本不支持把表名作为参数传入sql语句里,这个部分的错误花了很多时间来弥补。这也让我知道前期的准备过程要在现在的程度上更加的充分和细致。才能减少不必要的损失。
八、评价队友
队友超级给力!!!! --------221701303
我的css部分比较弱队友正好擅长于此,这让队友在我心中形象更加高大上,在彼此沟通上也很认真,遇到问题也非常认真百度或者请教他人,最后解决 221701326