|
最近做的一個(gè)在線氣象觀測網(wǎng)站要實(shí)現(xiàn)一個(gè)需求:使用圖表展示最近五天溫濕度等氣象要素的曲線變化 具體效果參考:http://www./showInfoIndex.jsp 圖示如下(2016-5-25日的數(shù)據(jù)): 下面就詳述一下實(shí)現(xiàn)過程吧(注:相較于原網(wǎng)頁我隱去了很多內(nèi)容,本實(shí)現(xiàn)過程就只專注于Echarts圖表實(shí)現(xiàn))
一: HTML頁面部分,代碼如下: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www./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運(yùn)行最新的渲染模式 -->
<meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 初始化移動(dòng)瀏覽顯示 -->
<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>- 觀測數(shù)據(jù) -</title>
</head>
<body>
<!-- 顯示Echarts圖表 -->
<div style="height:410px;min-height:100px;margin:0 auto;" id="main"></div>
<script type="text/javascript">
// 基于準(zhǔn)備好的dom,初始化echarts實(shí)例
var myChart = echarts.init(document.getElementById('main'));
// 指定圖表的配置項(xiàng)和數(shù)據(jù)
var option = {
title: { //圖表標(biāo)題
text: '過去五天數(shù)據(jù)圖表'
},
tooltip: {
trigger: 'axis', //坐標(biāo)軸觸發(fā)提示框,多用于柱狀、折線圖中
/*
控制提示框內(nèi)容輸出格式
formatter: '{b0}<br/><font color=#FF3333> ● </font>{a0} : {c0} ℃ ' +
'<br/><font color=#53FF53>● </font>{a1} : {c1} % ' +
'<br/><font color=#68CFE8> ● </font>{a3} : {c3} mm ' +
'<br/><font color=#FFDC35> ● </font>{a4} : {c4} m/s ' +
'<br/><font color=#B15BFF> ● </font>{a2} : {c2} hPa '
*/
},
dataZoom: [
{
type: 'slider', //支持鼠標(biāo)滾輪縮放
start: 0, //默認(rèn)數(shù)據(jù)初始縮放范圍為10%到90%
end: 100
},
{
type: 'inside', //支持單獨(dú)的滑動(dòng)條縮放
start: 0, //默認(rèn)數(shù)據(jù)初始縮放范圍為10%到90%
end: 100
}
],
legend: { //圖表上方的類別顯示
show:true,
data:['溫度(℃)','濕度(%)','雨量(mm)','風(fēng)速(m/s)','壓強(qiáng)(hPa)']
},
color:[
'#FF3333', //溫度曲線顏色
'#53FF53', //濕度曲線顏色
'#B15BFF', //壓強(qiáng)圖顏色
'#68CFE8', //雨量圖顏色
'#FFDC35' //風(fēng)速曲線顏色
],
toolbox: { //工具欄顯示
show: true,
feature: {
saveAsImage: {} //顯示“另存為圖片”工具
}
},
xAxis: { //X軸
type : 'category',
data : [] //先設(shè)置數(shù)據(jù)值為空,后面用Ajax獲取動(dòng)態(tài)數(shù)據(jù)填入
},
yAxis : [ //Y軸(這里我設(shè)置了兩個(gè)Y軸,左右各一個(gè))
{
//第一個(gè)(左邊)Y軸,yAxisIndex為0
type : 'value',
name : '溫度',
/* max: 120,
min: -40, */
axisLabel : {
formatter: '{value} ℃' //控制輸出格式
}
},
{
//第二個(gè)(右邊)Y軸,yAxisIndex為1
type : 'value',
name : '壓強(qiáng)',
scale: true,
axisLabel : {
formatter: '{value} hPa'
}
}
],
series : [ //系列(內(nèi)容)列表
{
name:'溫度(℃)',
type:'line', //折線圖表示(生成溫度曲線)
symbol:'emptycircle', //設(shè)置折線圖中表示每個(gè)坐標(biāo)點(diǎn)的符號;emptycircle:空心圓;emptyrect:空心矩形;circle:實(shí)心圓;emptydiamond:菱形
data:[] //數(shù)據(jù)值通過Ajax動(dòng)態(tài)獲取
},
{
name:'濕度(%)',
type:'line',
symbol:'emptyrect',
data:[]
},
{
name:'壓強(qiáng)(hPa)',
type:'line',
symbol:'circle', //標(biāo)識(shí)符號為實(shí)心圓
yAxisIndex: 1, //與第二y軸有關(guān)
data:[]
},
{
name:'雨量(mm)',
type:'bar', //柱狀圖表示
//barMinHeight: 10, //柱條最小高度,可用于防止某數(shù)據(jù)項(xiàng)的值過小而影響交互
/* label: { //顯示值
normal: {
show: true,
position: 'top'
}
}, */
data:[]
},
{
name:'風(fēng)速(m/s)',
type:'line',
symbol:'emptydiamond',
data:[]
}
]
};
myChart.showLoading(); //數(shù)據(jù)加載完之前先顯示一段簡單的loading動(dòng)畫
var tems=[]; //溫度數(shù)組(存放服務(wù)器返回的所有溫度值)
var hums=[]; //濕度數(shù)組
var pas=[]; //壓強(qiáng)數(shù)組
var rains=[]; //雨量數(shù)組
var win_sps=[]; //風(fēng)速數(shù)組
var dates=[]; //時(shí)間數(shù)組
$.ajax({ //使用JQuery內(nèi)置的Ajax方法
type : "post", //post請求方式
async : true, //異步請求(同步請求將會(huì)鎖住瀏覽器,用戶其他操作必須等待請求完成才可以執(zhí)行)
url : "ShowInfoIndexServlet", //請求發(fā)送到ShowInfoIndexServlet處
data : {name:"A0001"}, //請求內(nèi)包含一個(gè)key為name,value為A0001的參數(shù);服務(wù)器接收到客戶端請求時(shí)通過request.getParameter方法獲取該參數(shù)值
dataType : "json", //返回?cái)?shù)據(jù)形式為json
success : function(result) {
//請求成功時(shí)執(zhí)行該函數(shù)內(nèi)容,result即為服務(wù)器返回的json對象
if (result != null && result.length > 0) {
for(var i=0;i<result.length;i++){
tems.push(result[i].tem); //挨個(gè)取出溫度、濕度、壓強(qiáng)等值并填入前面聲明的溫度、濕度、壓強(qiáng)等數(shù)組
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(); //隱藏加載動(dòng)畫
myChart.setOption({ //載入數(shù)據(jù)
xAxis: {
data: dates //填入X軸數(shù)據(jù)
},
series: [ //填入系列(內(nèi)容)數(shù)據(jù)
{
// 根據(jù)名字對應(yīng)到相應(yīng)的系列
name: '溫度',
data: tems
},
{
name: '濕度',
data: hums
},
{
name: '壓強(qiáng)',
data: pas
},
{
name: '雨量',
data: rains
},
{
name: '風(fēng)速',
data: win_sps
}
]
});
}
else {
//返回的數(shù)據(jù)為空時(shí)顯示提示信息
alert("圖表請求數(shù)據(jù)為空,可能服務(wù)器暫未錄入近五天的觀測數(shù)據(jù),您可以稍后再試!");
myChart.hideLoading();
}
},
error : function(errorMsg) {
//請求失敗時(shí)執(zhí)行該函數(shù)
alert("圖表請求數(shù)據(jù)失敗,可能是服務(wù)器開小差了");
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./2001/XMLSchema-instance" xmlns="http://xmlns./xml/ns/javaee" xsi:schemaLocation="http://xmlns./xml/ns/javaee http://xmlns./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>
關(guān)于ShowInfoIndexServlet,簡單說一下請求-響應(yīng)中間的過程: 客戶端發(fā)送圖表請求給Servlet,Servlet接收到請求后先獲取客戶端請求查看的氣象站名稱,然后從數(shù)據(jù)庫(SqlServer2005 Express版)中獲取最近五天內(nèi)該氣象站所有的采集數(shù)據(jù)(裝在List中),再用Gson工具將該List轉(zhuǎn)換成Json對象返回給客戶端,客戶端接收到返回的Json對象后對其進(jìn)行解析并將相應(yīng)數(shù)據(jù)填入Echarts中,然后作顯示; 其中Record.java是只對外提供get/set方法的用于封裝數(shù)據(jù)的普通實(shí)體類,DBUtil.java是JDBC方式下專門提供Connection、Statement、ResultSet等的數(shù)據(jù)庫工具類。 (原本的連接數(shù)據(jù)庫并獲取數(shù)據(jù)過程需經(jīng)過業(yè)務(wù)邏輯層與數(shù)據(jù)訪問層,較為復(fù)雜,這里隱去這兩層,直接在Servlet內(nèi)連接數(shù)據(jù)庫并拿取數(shù)據(jù)) Ps:墻裂建議使用PreparedStatement進(jìn)行參數(shù)化查詢,這樣可以有效避免SQL注入!
ShowInfoIndexServlet代碼如下: 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;
/**
* 響應(yīng)觀測記錄展示頁的Echarts圖表數(shù)據(jù)請求(使用json格式返回客戶端需要的數(shù)據(jù))
* @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"); //設(shè)定客戶端提交給servlet的內(nèi)容按UTF-8編碼
response.setCharacterEncoding("UTF-8"); //設(shè)定servlet傳回給客戶端的內(nèi)容按UTF-8編碼
response.setContentType("text/html;charset=UTF-8"); //告知瀏覽器用UTF-8格式解析內(nèi)容
String name = request.getParameter("name"); //獲取臺(tái)站名參數(shù)
//獲取當(dāng)天在內(nèi)的五天以前的0點(diǎn)格式字符串(用于數(shù)據(jù)庫查詢)
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -4); //獲取當(dāng)天在內(nèi)的五天以前的日期時(shí)間
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd 00:00:00"); //設(shè)定日期格式
String fiveDaysAgoStr = sdf1.format(cal.getTime()); //將五天前的日期時(shí)間按指定格式轉(zhuǎn)換成字符串
//獲取當(dāng)前時(shí)間并將其轉(zhuǎn)換成指定格式的字符串(用于數(shù)據(jù)庫查詢)
Date now = new Date();
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String nowStr = sdf2.format(now);
//System.out.println(nowStr);
//======================================連接數(shù)據(jù)庫操作============================================================================================
/*
* 連接數(shù)據(jù)庫并獲取五天內(nèi)該名稱的氣象站的所有采集數(shù)據(jù)
*/
List<Record> records = new ArrayList<Record>(); //用一個(gè)ArrayList來盛裝封裝了各氣象數(shù)據(jù)的對象
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection(); //獲取與數(shù)據(jù)庫的連接
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); //創(chuàng)建preparedStatement語句對象
pstmt.setString(1, name); //設(shè)定查詢參數(shù)
pstmt.setString(2, fiveDaysAgoStr);
pstmt.setString(3, nowStr);
rs = pstmt.executeQuery(); //獲取查詢到的結(jié)果集
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));
//將時(shí)間轉(zhuǎn)換成給定格式便于echarts的X軸日期坐標(biāo)顯示
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("查詢出錯(cuò),操作未完成!");
e.printStackTrace();
} finally {
//查詢結(jié)束后釋放資源
DBUtil.close(rs);
DBUtil.close(pstmt);
DBUtil.close(conn);
}
//======================================連接數(shù)據(jù)庫操作(完)============================================================================================
//將list中的對象轉(zhuǎn)換為Json格式的數(shù)組
Gson gson = new Gson();
String json = gson.toJson(records);
//System.out.println(json);
//將json數(shù)據(jù)返回給客戶端
response.setContentType("text/html; charset=utf-8");
response.getWriter().write(json);
}
}
alldata表部分?jǐn)?shù)據(jù)截圖:
Record類代碼如下: package EchartsExample;
import java.sql.*;
/**
* 封裝氣象數(shù)據(jù)信息
* @author zhong
*
*/
public class Record {
private String taizhan_num; //臺(tái)站名
private String tem; //溫度
private String hum; //濕度
private String pa; //壓強(qiáng)
private String rain; //雨量
private String win_dir; //風(fēng)向
private String win_sp; //風(fēng)速
private String dateStr; //觀測日期(用于Echarts顯示格式)
private Timestamp date; //觀測日期(原始格式)
/**
* 獲取觀測日期(用于echarts圖表展示);
* @return 觀測日期值
*/
public String getDateStr() {
return dateStr;
}
/**
* 設(shè)置觀測日期(用于echarts圖表展示);
* @param dateStr 待設(shè)置觀測日期值
*/
public void setDateStr(String dateStr) {
this.dateStr = dateStr;
}
/**
* 獲取產(chǎn)生該觀測記錄的臺(tái)站名稱;
* @return 臺(tái)站名稱
*/
public String getTaizhan_num() {
return taizhan_num;
}
/**
* 設(shè)置產(chǎn)生該觀測記錄的臺(tái)站名稱;
* @param taizhan_num 待設(shè)置臺(tái)站名稱
*/
public void setTaizhan_num(String taizhan_num) {
this.taizhan_num = taizhan_num;
}
/**
* 獲取溫度;
* @return 溫度值
*/
public String getTem() {
return tem;
}
/**
* 設(shè)置溫度;
* @param tem 待設(shè)置溫度值
*/
public void setTem(String tem) {
this.tem = tem;
}
/**
* 獲取濕度;
* @return 濕度值
*/
public String getHum() {
return hum;
}
/**
* 設(shè)置濕度;
* @param hum 待設(shè)置濕度值
*/
public void setHum(String hum) {
this.hum = hum;
}
/**
* 獲取壓強(qiáng);
* @return 壓強(qiáng)值
*/
public String getPa() {
return pa;
}
/**
* 設(shè)置壓強(qiáng);
* @param pa 待設(shè)置壓強(qiáng)值
*/
public void setPa(String pa) {
this.pa = pa;
}
/**
* 獲取雨量;
* @return 雨量值
*/
public String getRain() {
return rain;
}
/**
* 設(shè)置雨量;
* @param rain 待設(shè)置雨量值
*/
public void setRain(String rain) {
this.rain = rain;
}
/**
* 獲取風(fēng)向;
* @return 風(fēng)向值
*/
public String getWin_dir() {
return win_dir;
}
/**
* 設(shè)置風(fēng)向;
* @param win_dir 待設(shè)置風(fēng)向值
*/
public void setWin_dir(String win_dir) {
this.win_dir = win_dir;
}
/**
* 獲取風(fēng)速;
* @return 風(fēng)速值
*/
public String getWin_sp() {
return win_sp;
}
/**
* 設(shè)置風(fēng)向;
* @param win_sp 待設(shè)置風(fēng)向值
*/
public void setWin_sp(String win_sp) {
this.win_sp = win_sp;
}
/**
* 獲取觀測日期;
* @return 觀測日期
*/
public Timestamp getDate() {
return date;
}
/**
* 設(shè)置觀測日期;
* @param date 觀測日期值
*/
public void setDate(Timestamp date) {
this.date = date;
}
}
DBUitl類(數(shù)據(jù)庫工具類)代碼如下: package EchartsExample;
import java.sql.*;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;
/**
* 數(shù)據(jù)庫工具類(采用了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"); //設(shè)置連接的url
p.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); //載入數(shù)據(jù)庫驅(qū)動(dòng)
p.setUsername("sa"); //用于遠(yuǎn)程連接的用戶名
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() {}
/**
* 獲取一個(gè)數(shù)據(jù)庫連接(Connection);
* @return Database Connection
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 關(guān)閉傳入的Connection;
* @param conn 待關(guān)閉的Connection
*/
public static void close(Connection conn) {
try {
if (conn != null) {
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 關(guān)閉傳入的Statement;
* @param stmt 待關(guān)閉的Statement
*/
public static void close(Statement stmt) {
try {
if (stmt != null) {
stmt.close();
stmt = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 關(guān)閉傳入的ResultSet;
* @param rs 待關(guān)閉的ResultSet
*/
public static void close(ResultSet rs) {
try {
if (rs != null) {
rs.close();
rs = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
——————————————————————————我是小小分割線———————————————————————————————————— 關(guān)于遠(yuǎn)程連接(包括使用Eclipse連接)SqlServer2005我再多嘴兩句: 當(dāng)確認(rèn)連接的URL,驅(qū)動(dòng)加載,用戶名,密碼都配置正確時(shí),仍然拋出 java.lang.NullPointerException 的話,請打開開始菜單Microsoft SQL Server 2005軟件目錄下的SQL Server配置管理器: ①:啟用SQL Server 2005網(wǎng)絡(luò)配置 下的 SQLEXPRESS協(xié)議 內(nèi)的 TCP/IP 協(xié)議,并右鍵TCP/IP協(xié)議選擇屬性,確保IP地址一欄最末的TCP端口為1433,具體見下圖
②:啟用 SQL Native Client配置 下的 客戶端協(xié)議 內(nèi)的 TCP/IP 協(xié)議,并右鍵查看TCP/IP 屬性,確保端口為1433,具體見下圖
③:重新啟動(dòng) SQL Server 2005服務(wù) 下的 SQL Server服務(wù),詳情見下圖 至此,應(yīng)該就解決了java.lang.NullPointerException這個(gè)錯(cuò)誤了。 ————————————————————————我是小小分割線———————————————————————————————————— 讓我們再回到原來的Echarts圖表顯示過程上,你可以試著在后臺(tái)打印看看轉(zhuǎn)換出的Json字符串,關(guān)于Json的使用這里我不再多言解釋,具體可參考簡單易懂的官方教程:http://www.w3school.com.cn/json/
最后再貼一下實(shí)現(xiàn)效果吧: |
|
|