北京市政百姓信件分析实战——五、开发JavaWeb+ECharts完成信件数据图表展示过程
ECharts简介
ECharts,纯Javascript图表库,基于Canvas,底层依赖ZRender,商业产品常用图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。创新的拖拽重计算、数据视图、值域漫游等特性大大增强了用户体验,赋予了用户对数据进行挖掘、整合的能力。可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等)。图表类型支持折线图(区域图)、柱状图(条状图)、散点图(气泡图)、K线图、饼图(环形图)、雷达图(填充雷达图)、和弦图、力导向布局图、地图,同时支持任意维度的堆积和多图表混合展现。
需求描述
需求1:将每年的信件数量用折线图进行展现,可以展现信件的数量随着时间的变化趋势。
需求2:把信件类型的投诉和咨询这两种类型,用饼图进行数据展示,从而达到让观者能从中熟悉某个类型的数量与整个数据组间所存在的比例关系的目的。
需求3:分析各个政府部门对信件的回答数量,用柱状图展示,可以达到展现数据并将数据进行比较的目的。
框架搭建
1.框架结构
2.框架说明
框架解释说明:
(1)src目录下的五个包和一个文件是项目的后台部分,用于实现页面中对数据的操作请求
(2)WebContent下命名为1的目录存放的是用于完成可视化数据展示的jsp页面,basic目录下存放编写页面公共部分的jsp文件,js目录下为实现jsp页面所用到的js文件,WEB-INF中的lib下为项目引入的所需要的jar包和为servlet定制url的web.xml文件,其余部分主要是实现jsp页面的样式文件。
后台工作原理说明:
(1)客户端向后台发送请求。即在jsp页面加载数据部分,设置需要调用的servlet文件名称和调用的方法参数给后台,目的是告诉后台要调用哪个servlet文件和这个文件中的哪个方法。
(2)web.xml文件里面设置了各个servlet文件的路径,所以客户端发送过来的请求会通过web.xml,提交到相应的如图(框架结构图)my.servlet目录下的servlet类,并接收传过来的参数,
(3)当成功提交到这个servlet类时,再通过参数值确定使用servlet哪个方法,然会通过如图(框架结构图)my.manager目录下相应的类里面的方法,将获取的数据的值返回。
(4)my.manager中的方法在获取数据时,需要图中(框架结构图)my.dao目录下相应的类里面的方法去操作数据库,因为dao层与db层结合可以直接操作数据库,获取数据库中的数据。
工作原理如图所示:
实验步骤
1.切换到/data目录,创建edu5文件夹。
cd /data
mkdir /data/edu5
2.再切换到/data/edu5目录下,下载实验所需的文件
cd /data/edu5
wget http://192.168.1.100:60000/allfiles/second/edu5/edu5out.sql
wget http://192.168.1.100:60000/allfiles/second/edu5/echarts.tar.gz
3.解压echarts.tar.gz包到当前目录
tar zxvf echarts.tar.gz
4.查看MySQL服务是否已经启动
sudo service mysql status
5.启动MySQL服务(数据库密码为:zhangyu)(如果MySQL服务已经启动可略过此步)
sudo service mysql start
6.启动MySQL(密码:strongs)
mysql -u root -p
7.创建并使用edu5out数据库
create database edu5out;
use edu5out;
8.将/data/edu5目录下的edu5out.sql脚本导入到mysql的edu5out库中
source /data/edu5/edu5out.sql;
9.查看一下edu5out库下的所有表
show tables;
10.打开Eclipse,导入echarts项目
单击File选择Import
11.选择General中的Existing Projects into Workspace
Select root directory出选择/data/edu5目录下的echarts项目
这样就将echarts项目导入进来了,目录结构如下:
在每个包下都包含First、Second、Third三个类,分别对应三个需求的功能实现
需求一:分析每年的信件数量,通过Echarts折线图展示出来。
12.首先,我们查看一下MySQL数据库中的lenumsql表
select * from lenumsql group by time desc;
包含两个字段time(年份)和num(数量),2005年和2017年统计的数量并不是全年,所以折线图演示的数据是2006年到2016年。
13.我们来执行echarts项目,查看一下效果
选择Window=>Show View=>Other
选择Server中的Servers后,点击OK
在Server处右键选择Add and Remove
将echarts项目添加到Configured中后,点击Finish
14.右键Server选择Start,开启Tomcat
15.Tomcat开启后,打开Firefox浏览器,输入下面网址
localhost:8080/echarts/1/ksh1.jsp
可以看到每年信件数量已经通过折线图展现出来了。
16.下面我们来看一下具体的代码:
在my.domain包下,First类的作用为:定义对象属性。具体代码如下:
package my.domain;
public class First {
private String time;
private int num;
public First() {
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public First(String time, int num) {
super();
this.time = time;
this.num = num;
}
@Override
public String toString() {
return "First [time=" + time + ", num=" + num + "]";
}
}
在my.dao包下,FirstDao.java类的作用为:调用sql语句对数据库的数据进行具体操作。具体代码如下:
package my.dao;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import my.domain.First;
import org.apache.log4j.Logger;
public class FirstDao {
public static Logger logger = Logger.getLogger(FirstDao.class);
public static List<First> getFirstList() {
String sql = "select time,num from lenumsql where time between 2006 and 2016 order by time asc";
Connection conn= null;
ResultSet set = null;
Statement stmt = null;
List<First> list = new ArrayList<First>();
try {
conn = DBHelper.connDB();
stmt = conn.createStatement();
set = stmt.executeQuery(sql);
while (set.next()) {
First bean = new First();
bean.setTime(set.getString("time"));
bean.setNum(set.getInt("num"));
list.add(bean);
}
} catch (Exception e) {
logger.error(e.getMessage());
} finally{
DBHelper.free(set, stmt, conn);
}
return list;
}
}
在my.manager包下,FirstManager.java类的作用为:用以调用FirstDao中的方法得到数据。具体代码如下:
package my.manager;
import java.util.List;
import my.dao.FirstDao;
import my.domain.First;
public class FirstManager {
public List<First> getFirstList() {
return FirstDao.getFirstList();
}
}
在my.servlet包下,FirstServlet.java类的作用为:将前面得到的数据传给jsp页面,响应客户端。具体代码如下:
package my.servlet;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import my.domain.First;
import my.manager.FirstManager;
import my.utils.BaseServlet;
import net.sf.json.JSONArray;
public class FirstServlet extends BaseServlet{
private static final long serialVersionUID = 1L;
public static Logger logger = Logger.getLogger(FirstServlet.class);
@Override
public void execute(HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setContentType("text/html;charset=utf-8");
String opt = request.getParameter("opt");
FirstManager scale= new FirstManager();
if (opt.equals("First")) {
List<First> list = new ArrayList<First>();
list = scale.getFirstList();
JSONArray jsonArray = JSONArray.fromObject(list);
//System.err.println(jsonArray);
PrintWriter out = response.getWriter();
out.print(jsonArray);
out.flush();
out.close();
}
}
}
main.properties文件的作用为,配置MySQL相关参数,涉及用户名、密码、数据库等。具体代码如下:
##MySQL Configuration
JDBC.DRIVER=com.mysql.jdbc.Driver
JDBC.URL=jdbc:MySql://localhost:3306/edu5out?
zeroDateTimeBehavior=convertToNull
MYSQLDB.USER=root
MYSQLDB.PASSWORD=strongs
web.xml的作用为:接受客户端的请求,然后响应给相应的servlet类,就好比一个信息中转站。主要代码为:
-<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>my.servlet.FirstServlet</servlet-class>
</servlet>
-<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/FirstServlet</url-pattern>
</servlet-mapping>
在WebContent/1/下面新建一个jsp页面,命名为ksh1,这个页面就是在浏览器上展现给客户的页面,在这个页面上接收后台数据,主要作用是实现数据的可视化展现。具体代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>每年信件数量</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<%@include file="../basic/cssjs.jsp" %>
<!-- 引入Jquery包 -->
<script type="text/javascript" src="../js/jquery-2.1.4.min.js"></script>
<!-- 引入Echarts3包 -->
<script type="text/javascript" src="../js/echarts.min.js"></script>
</head>
<body>
<%@include file="../basic/top.jsp" %>
<!-- content start -->
<div class="container-fluid">
<div class="row-fluid">
<div class="span3">
<!-- left navbar start -->
<%@include file="../basic/left.jsp" %>
<!-- left navbar end -->
</div>
<!-- right content start -->
<div class="span9">
<div class="session well">折线图适合用来展现某个项目的发展趋势,或展现并比较多个项目的发展趋势。</div>
<div class="session">
<div id="main" style="width: 100%;height:600px;"></div>
</div>
</div>
<!-- right content end -->
</div>
</div>
<!-- content end -->
</body>
</html>
<script type="text/javascript">
var data = [];
var markLineData = [];
for ( var i = 1; i < data.length; i++) {
markLineData.push([ {
xAxis : i - 1,
yAxis : data[i - 1],
value : (data[i] + data[i - 1]).toFixed(2)
}, {
xAxis : i,
yAxis : data[i]
} ]);
}
option = {
title : {
text : '每年信件数量',
subtext : '单位:条'
},
tooltip : {
trigger : 'axis'
},
toolbox: {
show : true,
feature : {
mark : {show: true},
dataView : {show: true, readOnly: false},
magicType : {show: true, type: ['bar']},
restore : {show: true},
saveAsImage : {show: true}
}
},
xAxis : {
name: '年份',
data : []
},
yAxis : {name: '数量',},
series : [ {
type : 'line',
data : data,
markPoint : {
data : [ {
type : 'max',
name : '最大值'
}, {
type : 'min',
name : '最小值'
} ]
},
markLine : {
smooth : true,
effect : {
show : true
},
distance : 10,
label : {
normal : {
position : 'middle'
}
},
symbol : [ 'none', 'none' ],
data : markLineData
}
} ]
};
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
var mapOnlyKey = [];
var mapKeyValue = [];
var mapOnlyValue = [];
var info = {
"opt" : "First"
};
$.post("../FirstServlet", info, function(data) {
mapOnlyKey.length = 0;
mapKeyValue.length = 0;
mapOnlyValue.length = 0;
for ( var i = 0; i < data.length; i++) {
mapOnlyKey.push(data[i].time);
mapKeyValue.push({
"value" : Math.round(data[i].num),
"name" : data[i].time
});
mapOnlyValue.push(data[i].num);
}
myChart.setOption({
legend : {
data : mapOnlyKey
},
xAxis : [ {
data : mapOnlyKey
} ],
series : [ {
name : '条',
data : mapKeyValue
} ]
});
}, 'json');
</script>
同理,需求二、需求三的原理和需求一相同,仍然使用以上框架,下面我们来实现剩下的两个需求。
需求二:分析信件是属于投诉和咨询的比例,通过Echarts饼图展示出来。
17.我们查看一下MySQL数据库中的typenum表
select * from typenum;
包含类型leixing(类型)和num(数量)两个字段。
18.打开浏览器,输入下面网址
localhost:8080/echarts/1/ksh2.jsp
可以看到投诉举报和咨询问答的数量和比例,通过饼状图清晰的展现出来了。
需求三:分析各个政府部门对信件的回答数量,通过Echarts柱状图展示出来。
19.我们查看一下MySQL数据库中的govnum表
select * from govnum;
包含govname(部门名称)和num(数量)两个字段。
20.打开浏览器,输入下面网址
localhost:8080/echarts/1/ksh3.jsp
可以看到部门名称以及对应的数量,通过柱状图清晰的展现出来了。
这样,实验就结束了,我们通过echarts完成了以上三个需求的数据展示。