最近做的一个在线气象观测网站要实现一个需求:使用图表展示最近五天温湿度等气象要素的曲线变化

具体效果参考:http://www.weatherobserve.com/showInfoIndex.jsp

图示如下(2016-5-25日的数据):

下面就详述一下实现过程吧(注:相较于原网页我隐去了很多内容,本实现过程就只专注于Echarts图表实现)

一:

HTML页面部分,代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN">
<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- 在IE运行最新的渲染模式 -->
<meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 初始化移动浏览显示 -->
<meta name="Author" content="Dreamer-1."> <script type="text/javascript" src="js/jquery-1.12.3.min.js"></script>
<script type="text/javascript" src="js/echarts.common.min.js"></script> <title>- 观测数据 -</title>
</head> <body> <!-- 显示Echarts图表 -->
<div style="height:410px;min-height:100px;margin:0 auto;" id="main"></div> <script type="text/javascript"> // 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main')); // 指定图表的配置项和数据
var option = {
title: { //图表标题
text: '过去五天数据图表'
},
tooltip: {
trigger: 'axis', //坐标轴触发提示框,多用于柱状、折线图中
/*
控制提示框内容输出格式
formatter: '{b0}<br/><font color=#FF3333>&nbsp;●&nbsp;</font>{a0} : {c0} ℃ ' +
'<br/><font color=#53FF53>●&nbsp;</font>{a1} : {c1} % ' +
'<br/><font color=#68CFE8>&nbsp;●&nbsp;</font>{a3} : {c3} mm ' +
'<br/><font color=#FFDC35>&nbsp;●&nbsp;</font>{a4} : {c4} m/s ' +
'<br/><font color=#B15BFF>&nbsp;&nbsp;&nbsp;&nbsp;●&nbsp;</font>{a2} : {c2} hPa '
*/
},
dataZoom: [
{
type: 'slider', //支持鼠标滚轮缩放
start: 0, //默认数据初始缩放范围为10%到90%
end: 100
},
{
type: 'inside', //支持单独的滑动条缩放
start: 0, //默认数据初始缩放范围为10%到90%
end: 100
}
],
legend: { //图表上方的类别显示
show:true,
data:['温度(℃)','湿度(%)','雨量(mm)','风速(m/s)','压强(hPa)']
},
color:[
'#FF3333', //温度曲线颜色
'#53FF53', //湿度曲线颜色
'#B15BFF', //压强图颜色
'#68CFE8', //雨量图颜色
'#FFDC35' //风速曲线颜色
],
toolbox: { //工具栏显示
show: true,
feature: {
saveAsImage: {} //显示“另存为图片”工具
}
},
xAxis: { //X轴
type : 'category',
data : [] //先设置数据值为空,后面用Ajax获取动态数据填入
},
yAxis : [ //Y轴(这里我设置了两个Y轴,左右各一个)
{
//第一个(左边)Y轴,yAxisIndex为0
type : 'value',
name : '温度',
/* max: 120,
min: -40, */
axisLabel : {
formatter: '{value} ℃' //控制输出格式
}
},
{
//第二个(右边)Y轴,yAxisIndex为1
type : 'value',
name : '压强',
scale: true,
axisLabel : {
formatter: '{value} hPa'
}
} ],
series : [ //系列(内容)列表
{
name:'温度(℃)',
type:'line', //折线图表示(生成温度曲线)
symbol:'emptycircle', //设置折线图中表示每个坐标点的符号;emptycircle:空心圆;emptyrect:空心矩形;circle:实心圆;emptydiamond:菱形
data:[] //数据值通过Ajax动态获取
}, {
name:'湿度(%)',
type:'line',
symbol:'emptyrect',
data:[]
}, {
name:'压强(hPa)',
type:'line',
symbol:'circle', //标识符号为实心圆
yAxisIndex: 1, //与第二y轴有关
data:[]
}, {
name:'雨量(mm)',
type:'bar', //柱状图表示
//barMinHeight: 10, //柱条最小高度,可用于防止某数据项的值过小而影响交互
/* label: { //显示值
normal: {
show: true,
position: 'top'
}
}, */
data:[]
}, {
name:'风速(m/s)',
type:'line',
symbol:'emptydiamond',
data:[]
}
]
}; myChart.showLoading(); //数据加载完之前先显示一段简单的loading动画 var tems=[]; //温度数组(存放服务器返回的所有温度值)
var hums=[]; //湿度数组
var pas=[]; //压强数组
var rains=[]; //雨量数组
var win_sps=[]; //风速数组
var dates=[]; //时间数组 $.ajax({ //使用JQuery内置的Ajax方法
type : "post", //post请求方式
async : true, //异步请求(同步请求将会锁住浏览器,用户其他操作必须等待请求完成才可以执行)
url : "ShowInfoIndexServlet", //请求发送到ShowInfoIndexServlet处
data : {name:"A0001"}, //请求内包含一个key为name,value为A0001的参数;服务器接收到客户端请求时通过request.getParameter方法获取该参数值
dataType : "json", //返回数据形式为json
success : function(result) {
//请求成功时执行该函数内容,result即为服务器返回的json对象
if (result != null && result.length > 0) {
for(var i=0;i<result.length;i++){
tems.push(result[i].tem); //挨个取出温度、湿度、压强等值并填入前面声明的温度、湿度、压强等数组
hums.push(result[i].hum);
pas.push(result[i].pa);
rains.push(result[i].rain);
win_sps.push(result[i].win_sp);
dates.push(result[i].dateStr);
}
myChart.hideLoading(); //隐藏加载动画 myChart.setOption({ //载入数据
xAxis: {
data: dates //填入X轴数据
},
series: [ //填入系列(内容)数据
{
// 根据名字对应到相应的系列
name: '温度',
data: tems
},
{
name: '湿度',
data: hums
},
{
name: '压强',
data: pas
},
{
name: '雨量',
data: rains
},
{
name: '风速',
data: win_sps
}
]
}); }
else {
//返回的数据为空时显示提示信息
alert("图表请求数据为空,可能服务器暂未录入近五天的观测数据,您可以稍后再试!");
myChart.hideLoading();
} },
error : function(errorMsg) {
//请求失败时执行该函数
alert("图表请求数据失败,可能是服务器开小差了");
myChart.hideLoading();
}
}) myChart.setOption(option); //载入图表 </script> </body>
</html>

二:

Servlet部分,客户端请求提交到 ShowInfoIndex 处,先在 web.xml 里配置一下Servlet映射:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>BlogExample</display-name> <servlet>
<servlet-name>ShowInfoIndexServlet</servlet-name>
<servlet-class>EchartsExample.ShowInfoIndexServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ShowInfoIndexServlet</servlet-name>
<url-pattern>/ShowInfoIndexServlet</url-pattern>
</servlet-mapping> </web-app>

关于ShowInfoIndexServlet,简单说一下请求-响应中间的过程:

客户端发送图表请求给Servlet,Servlet接收到请求后先获取客户端请求查看的气象站名称,然后从数据库(SqlServer2005 Express版)中获取最近五天内该气象站所有的采集数据(装在List中),再用Gson工具将该List转换成Json对象返回给客户端,客户端接收到返回的Json对象后对其进行解析并将相应数据填入Echarts中,然后作显示;

其中Record.java是只对外提供get/set方法的用于封装数据的普通实体类,DBUtil.java是JDBC方式下专门提供Connection、Statement、ResultSet等的数据库工具类。

(原本的连接数据库并获取数据过程需经过业务逻辑层与数据访问层,较为复杂,这里隐去这两层,直接在Servlet内连接数据库并拿取数据)

Ps:墙裂建议使用PreparedStatement进行参数化查询,这样可以有效避免SQL注入!

ShowInfoIndexServlet代码如下:

其中用到了Google的Gson工具包(提供java-json对象间的转换,下载后放在 WRB-INF/lib 目录下即可)

下载地址:http://mvnrepository.com/artifact/com.google.code.gson/gson

package EchartsExample;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.google.gson.Gson; /**
* 响应观测记录展示页的Echarts图表数据请求(使用json格式返回客户端需要的数据)
* @author zhong
*
*/
public class ShowInfoIndexServlet extends HttpServlet { /**
*
*/
private static final long serialVersionUID = 1L; @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
} @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); //设定客户端提交给servlet的内容按UTF-8编码
response.setCharacterEncoding("UTF-8"); //设定servlet传回给客户端的内容按UTF-8编码
response.setContentType("text/html;charset=UTF-8"); //告知浏览器用UTF-8格式解析内容 String name = request.getParameter("name"); //获取台站名参数 //获取当天在内的五天以前的0点格式字符串(用于数据库查询)
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -4); //获取当天在内的五天以前的日期时间
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd 00:00:00"); //设定日期格式
String fiveDaysAgoStr = sdf1.format(cal.getTime()); //将五天前的日期时间按指定格式转换成字符串 //获取当前时间并将其转换成指定格式的字符串(用于数据库查询)
Date now = new Date();
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String nowStr = sdf2.format(now);
//System.out.println(nowStr); //======================================连接数据库操作============================================================================================
/*
* 连接数据库并获取五天内该名称的气象站的所有采集数据
*/
List<Record> records = new ArrayList<Record>(); //用一个ArrayList来盛装封装了各气象数据的对象 Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null; try {
conn = DBUtil.getConnection(); //获取与数据库的连接
String sql = "select * from alldata where data_taizhan_num = ? and data_date >= ? and data_date <= ? order by data_date asc"; //初始化SQL查询语句
pstmt = conn.prepareStatement(sql); //创建preparedStatement语句对象
pstmt.setString(1, name); //设定查询参数
pstmt.setString(2, fiveDaysAgoStr);
pstmt.setString(3, nowStr);
rs = pstmt.executeQuery(); //获取查询到的结果集
while (rs.next()) {
//封装Record对象
Record r = new Record();
r.setTaizhan_num(rs.getString(1));
r.setDate(rs.getTimestamp(2));
r.setTem(rs.getString(3));
r.setHum(rs.getString(4));
r.setPa(rs.getString(5));
r.setRain(rs.getString(6));
r.setWin_dir(rs.getString(7));
r.setWin_sp(rs.getString(8)); //将时间转换成给定格式便于echarts的X轴日期坐标显示
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(rs.getTimestamp(2));
r.setDateStr(str);
//System.out.println(r.getTem()+" | "+r.getHum()+" | "+r.getPa()+" | "+r.getRain()+" | "+r.getWin_dir()+" | "+r.getWin_sp());
records.add(r); //将封装好的Record对象放入列表容器中
} } catch (SQLException e) {
System.out.println("查询出错,操作未完成!");
e.printStackTrace();
} finally {
//查询结束后释放资源
DBUtil.close(rs);
DBUtil.close(pstmt);
DBUtil.close(conn);
}
//======================================连接数据库操作(完)============================================================================================ //将list中的对象转换为Json格式的数组
Gson gson = new Gson();
String json = gson.toJson(records); //System.out.println(json); //将json数据返回给客户端
response.setContentType("text/html; charset=utf-8");
response.getWriter().write(json);
} }

alldata表部分数据截图:

Record类代码如下:

package EchartsExample;

import java.sql.*;

/**
* 封装气象数据信息
* @author zhong
*
*/
public class Record { private String taizhan_num; //台站名
private String tem; //温度
private String hum; //湿度
private String pa; //压强
private String rain; //雨量
private String win_dir; //风向
private String win_sp; //风速
private String dateStr; //观测日期(用于Echarts显示格式)
private Timestamp date; //观测日期(原始格式) /**
* 获取观测日期(用于echarts图表展示);
* @return 观测日期值
*/
public String getDateStr() {
return dateStr;
} /**
* 设置观测日期(用于echarts图表展示);
* @param dateStr 待设置观测日期值
*/
public void setDateStr(String dateStr) {
this.dateStr = dateStr;
} /**
* 获取产生该观测记录的台站名称;
* @return 台站名称
*/
public String getTaizhan_num() {
return taizhan_num;
} /**
* 设置产生该观测记录的台站名称;
* @param taizhan_num 待设置台站名称
*/
public void setTaizhan_num(String taizhan_num) {
this.taizhan_num = taizhan_num;
} /**
* 获取温度;
* @return 温度值
*/
public String getTem() {
return tem;
} /**
* 设置温度;
* @param tem 待设置温度值
*/
public void setTem(String tem) {
this.tem = tem;
} /**
* 获取湿度;
* @return 湿度值
*/
public String getHum() {
return hum;
} /**
* 设置湿度;
* @param hum 待设置湿度值
*/
public void setHum(String hum) {
this.hum = hum;
} /**
* 获取压强;
* @return 压强值
*/
public String getPa() {
return pa;
} /**
* 设置压强;
* @param pa 待设置压强值
*/
public void setPa(String pa) {
this.pa = pa;
} /**
* 获取雨量;
* @return 雨量值
*/
public String getRain() {
return rain;
} /**
* 设置雨量;
* @param rain 待设置雨量值
*/
public void setRain(String rain) {
this.rain = rain;
} /**
* 获取风向;
* @return 风向值
*/
public String getWin_dir() {
return win_dir;
} /**
* 设置风向;
* @param win_dir 待设置风向值
*/
public void setWin_dir(String win_dir) {
this.win_dir = win_dir;
} /**
* 获取风速;
* @return 风速值
*/
public String getWin_sp() {
return win_sp;
} /**
* 设置风向;
* @param win_sp 待设置风向值
*/
public void setWin_sp(String win_sp) {
this.win_sp = win_sp;
} /**
* 获取观测日期;
* @return 观测日期
*/
public Timestamp getDate() {
return date;
} /**
* 设置观测日期;
* @param date 观测日期值
*/
public void setDate(Timestamp date) {
this.date = date;
} }

DBUitl类(数据库工具类)代码如下:

package EchartsExample;

import java.sql.*;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties; /**
* 数据库工具类(采用了tomcat jdbc pool)
* @author zhong
*
*/
public class DBUtil { private static DataSource ds; static {
//配置tomcat jdbc pool (连接池)
PoolProperties p = new PoolProperties();
p.setUrl("jdbc:sqlserver://localhost:1433; DatabaseName=weather"); //设置连接的url
p.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //载入数据库驱动
p.setUsername("sa"); //用于远程连接的用户名
p.setPassword("2003NianDeDiYiChangXue"); //密码
p.setJmxEnabled(true);
p.setTestWhileIdle(false);
p.setTestOnBorrow(true);
p.setValidationQuery("SELECT 1");
p.setTestOnReturn(false);
p.setValidationInterval(30000);
p.setTimeBetweenEvictionRunsMillis(30000);
p.setMaxActive(100);
p.setInitialSize(10);
p.setMaxWait(10000);
p.setRemoveAbandonedTimeout(60);
p.setMinEvictableIdleTimeMillis(30000);
p.setMinIdle(10);
p.setLogAbandoned(true);
p.setRemoveAbandoned(true);
p.setJdbcInterceptors(
"org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
ds = new DataSource();
ds.setPoolProperties(p);
} private DBUtil() {} /**
* 获取一个数据库连接(Connection);
* @return Database Connection
*/
public static Connection getConnection() {
Connection conn = null; try {
conn = ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
} return conn;
} /**
* 关闭传入的Connection;
* @param conn 待关闭的Connection
*/
public static void close(Connection conn) {
try {
if (conn != null) {
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* 关闭传入的Statement;
* @param stmt 待关闭的Statement
*/
public static void close(Statement stmt) {
try {
if (stmt != null) {
stmt.close();
stmt = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* 关闭传入的ResultSet;
* @param rs 待关闭的ResultSet
*/
public static void close(ResultSet rs) {
try {
if (rs != null) {
rs.close();
rs = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
} }

——————————————————————————我是小小分割线————————————————————————————————————

关于远程连接(包括使用Eclipse连接)SqlServer2005我再多嘴两句:

当确认连接的URL,驱动加载,用户名,密码都配置正确时,仍然抛出 java.lang.NullPointerException 的话,请打开开始菜单Microsoft SQL Server 2005软件目录下的SQL Server配置管理器:

①:启用SQL Server 2005网络配置 下的 SQLEXPRESS协议 内的 TCP/IP 协议,并右键TCP/IP协议选择属性,确保IP地址一栏最末的TCP端口为1433,具体见下图

②:启用 SQL Native Client配置 下的 客户端协议 内的 TCP/IP 协议,并右键查看TCP/IP 属性,确保端口为1433,具体见下图

③:重新启动 SQL Server 2005服务 下的 SQL Server服务,详情见下图

至此,应该就解决了java.lang.NullPointerException这个错误了。

————————————————————————我是小小分割线————————————————————————————————————

让我们再回到原来的Echarts图表显示过程上,你可以试着在后台打印看看转换出的Json字符串,关于Json的使用这里我不再多言解释,具体可参考简单易懂的官方教程:http://www.w3school.com.cn/json/

源码下载:http://files.cnblogs.com/files/Dreamer-1/BlogExample.rar

使用Echarts实现动态曲线图表的更多相关文章

  1. echarts入门,5分钟上手写ECharts的第一个图表

    1.新建一个echarts.html文件,为ECharts准备一个具备大小(宽高)的Dom. <!DOCTYPE html> <head> <meta charset=& ...

  2. Mschart应用之曲线图表spline

    本文主要是Mschart应用之曲线图表spline,实现6个模拟数据的图表,其中数据源X轴为当前系统时间,Y轴是由随机函数产生的不同范围的随机数. 首先是自定义一个数据表,然后产生的数据添加到该数据表 ...

  3. 百度echart如何动态生成图表

    百度echart如何动态生成图表 一.总结 一句话总结: clear hideloading setOption 主要是下面三行代码: myChart.clear(); //清空画布myChart.h ...

  4. vue和echarts 封装的 v-charts 图表组件

    https://v-charts.js.org/#/ 在使用 echarts 生成图表时,经常需要做繁琐的数据类型转化.修改复杂的配置项,v-charts 的出现正是为了解决这个痛点.基于 Vue2. ...

  5. [转载] MFC绘制动态曲线,用双缓冲绘图技术防闪烁

    转载的原文地址 先上效果图 随着时间的推移,曲线向右平移,同时X轴的时间坐标跟着更新. 一.如何绘制动态曲线 所谓动画,都是一帧一帧的图像连续呈现在用户面前形成的.所以如果你掌握了如何绘制静态曲线,那 ...

  6. ECharts学习总结(一):ECharts的第一个图表

    在进行echarts图表开发之前先要到echarts官网下载echarts的库文件,我下载的是echarts-2.2.7.然后把库文件放到工程文件web目录下.接下来进行第一个图表的显示步骤如下: 1 ...

  7. Highcharts 基本曲线图;Highcharts 带有数据标签曲线图表;Highcharts 异步加载数据曲线图表

    Highcharts 基本曲线图 实例 文件名:highcharts_line_basic.htm <html> <head> <meta charset="U ...

  8. echarts.js中的图表大小自适应

    echarts的图表,如果父级容器的height/width属性设置为百分比的形式,那么echarts就会warning,且不能正常的生成图表.所以div容器的高度宽度必须指定为px,这设计不知道是为 ...

  9. 【MFC】MFC绘制动态曲线,用双缓冲绘图技术防闪烁

    摘自:http://zhy1987819.blog.163.com/blog/static/841427882011614103454335/ MFC绘制动态曲线,用双缓冲绘图技术防闪烁   2011 ...

随机推荐

  1. 彻底解决低端安卓手机touchend事件不触发(考虑scroll)

    本次移动端开发时遇见了安卓4.2系统不能触发touchend的问题,有以下需求. 1. 横滑轮播图 2.下拉刷新页面内容 3.body滚动条不能失效 开始在轮播图touchmove事件中阻止了浏览器默 ...

  2. CQRS, Task Based UIs, Event Sourcing agh!

    原文地址:CQRS, Task Based UIs, Event Sourcing agh! Many people have been getting confused over what CQRS ...

  3. VMware Workstation 10.0 正式版官方简体中文下载(附序列号)

    虚拟机界数一数二的王者软件VMWare Workstation 今日推出了最新的VMware Workstation 10.0 版本.该版本最大的更新是加入了简体中文语言,这意味着未来神马汉化包.中文 ...

  4. Xamarin.Android之Splash的几种简单实现

    对现在的APP软件来说,基本上都会有一个Splash页面,类似大家常说的欢迎页面.启动界面之类的. 正常来说这个页面都会有一些相关的信息,比如一些理念,Logo,版本信息等 下面就来看看在Xamari ...

  5. ASP.Net MVC Action重定向跳出Controller和Area

    1.重定向方法简介 [HttpPost] public ActionResult StudentList( string StudName, string studName, DateTime Bir ...

  6. 重温Bootstrap

    预热 ★ 学习要点 1. 理解其GridSystem(栅格排版): 2. 熟悉其所提供的各种CSS样式及显示效果: 3. 知道提供了哪些直接可用的UI组件,以及如何使用JavaScript去调整其交互 ...

  7. 设计模式(二)简单工厂模式(Simple Factory Pattern)

    一.引言 这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理解的模式——简单工厂模式. 二.简单工厂 ...

  8. 背水一战 Windows 10 (25) - MVVM: 通过 x:Bind 实现 MVVM(不用 Command)

    [源码下载] 背水一战 Windows 10 (25) - MVVM: 通过 x:Bind 实现 MVVM(不用 Command) 作者:webabcd 介绍背水一战 Windows 10 之 MVV ...

  9. sql执行循序

    (8) select (9) distinct (11) top 1 (6) Table1.id,COUNT(Table1.name) as nameCount (1) from Table1 (3) ...

  10. C标准头文件<stdio.h>

    是很多人学C语言接触的第一个头文件,顾名思义,stdio就是"标准输入输出",其中声明了一组关于输入输出的类型,宏和函数,其中就包括了打印著名的"hello,world! ...