零 基本介绍
Highcharts 是一个用纯JavaScript编写的一个图表库, 能够很简单便捷的在web网站或是web应用程序添加有交互性的图表,并且免费提供给个人学习、个人网站和非商业用途使用。HighCharts支持的图表类型有曲线图、区域图、柱状图、饼状图、散状点图和综合图表。
推荐几个web中常用js图表插件本例中除用到Highcharts表格插件外,还用到ajax网页异步刷新技术,指定Action method属性并使用通配符,采用JSON数据格式进行数据集的传输。
一 功能描述
通过ajax调用action从后台获取数据集,应用highcharts图表插件,在前端以柱状图或折线图的形式对数据进行直观展示。
二 实现流程
1 JSP页面布局
2 Action业务逻辑编写
3 struts.xml配置
4 ajax及highcharts图表js脚本编写
三 解决问题
1 highcharts应用
2 为action指定method属性及使用通配符
3 通过<s:select></s:select>标签指定请求参数
四 详细设计
1 JSP页面布局
在JSP页内放置两个highchart图表
第一个图表以line style展示 不同尺寸的图像在不同压缩方式下的压缩总时间对比
第二个图表一column style展示 某一尺寸图像在不同压缩方式下的压缩各部分时间对比
chart.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>highcharts图表插件应用</title>
<script type="text/javascript" src="js/jquery-*.**.*.min.js"></script>
<!--自己编写的js脚本 -->
<script type="text/javascript" src="js/analysis.js"></script>
</head>
<body style="background: #fac234">
<!--highcharts表格插件需要的js脚本 -->
<script src="js/test/highcharts.js"></script>
<script src="js/test/exporting.js"></script>
<s:submit style="float:left;" id="drawLine" value="查询历史数据" ></s:submit>
<div id="container" style="width:60%; height: 400px; margin: 0 auto"></div>
<s:select id="sizeSelect" list="{256,512,1024,2048,4096}"></s:select>
<s:submit style="float:left;" id="drawBar" value="查询历史数据" ></s:submit>
<div id="partTimeCompare" style="width:60%; height: 400px; margin: 0 auto"></div>
</body>
</html>
2 Action业务逻辑编写
该Action业务逻辑有两个功能,对应Action内的两个函数方法。
TotalTimeLine()方法用于从数据库中查询全部历史压缩时间数据,并统计不同尺寸图像大小不同压缩方式下的平均时间。
partTimeCompare()方法根据传入的图片尺寸参数,从数据库中查询该尺寸图像的所有历史时间数据,并分类整理(这部分和我要实现的实际需求有关,不赘述)。
下面将使用通配符的方式为action指定method方法,对struts.xml中配置的同一个action映射不同方法,以精简代码。
----注意----
对数据库进行相关操作需要导入sqljdbc.jar包
本类中所用的Variable.java及DBTools.java将不被列出
DrawPictrueAction.java
package com.wlkfz.action;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
import org.apache.commons.lang.Validate;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.views.xslt.ArrayAdapter;
import com.opensymphony.xwork2.Action;
import com.wlkfz.bean.DBTools;
import com.wlkfz.bean.Variable;
public class DrawPictrueAction implements Action {
private Connection conn = null;
private Statement state = null;
private ResultSet rs = null;
private JSONObject data = new JSONObject();
private int imgSize ;
private int cpsWays = Variable.cpsWays;
@Override
public String execute() throws Exception {
//action 默认调用方法 JSON template
queryAndAnalysisTotalTime();
HttpServletResponse response=ServletActionContext.getResponse();
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(data.toString());
return null;
}
public String partTimeCompare() throws IOException{
System.out.println("imgSize="+imgSize);
//同一图片尺寸 不同压缩方式 total dwt spiht时间对比
try {
conn = DBTools.getConnection();
state = conn.createStatement();
String sql = "select * from mytest..compress_time where image_size="+imgSize;
rs = state.executeQuery(sql);
// float time[][] = new float[3][4]; //二维数组
float totalTime[] = new float[cpsWays];
float dwtTime[] = new float[cpsWays];
float spihtTime[] = new float[cpsWays];
while (rs.next()) {
int cpsWay = rs.getInt("cps_way");
float tTime = rs.getFloat("total_time");
float dTime = rs.getFloat("dwt_total");
float sTime = rs.getFloat("spiht_total");
if (totalTime[cpsWay]!=0) {
totalTime[cpsWay] = (totalTime[cpsWay]+tTime)/2;
}else {
totalTime[cpsWay] = tTime;
}
if (dwtTime[cpsWay]!=0) {
dwtTime[cpsWay] = (dwtTime[cpsWay]+dTime)/2;
}else {
dwtTime[cpsWay] = dTime;
}
if (spihtTime[cpsWay]!=0) {
spihtTime[cpsWay] = (spihtTime[cpsWay]+sTime)/2;
}else {
spihtTime[cpsWay] = sTime;
}
}
List<List<Float>> cpsPartTimeSet = new ArrayList<List<Float>>();
for (int i = 0; i < 3; i++) {
List<Float> temp = new ArrayList<Float>();
for (int j = 0; j < cpsWays; j++) {
switch (i) {
case 0:
temp.add(dwtTime[j]);
break;
case 1:
temp.add(spihtTime[j]);
break;
case 2:
temp.add(totalTime[j]);
break;
default:
break;
}
}
cpsPartTimeSet.add(temp);
}
data.put("partTimeList", cpsPartTimeSet);
} catch (Exception e) {
e.printStackTrace();
}finally{
DBTools.closeRs(rs);
DBTools.closeState(state);
DBTools.closeConn(conn);
}
HttpServletResponse response=ServletActionContext.getResponse();
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(data.toString());
return null;
}
public String TotalTimeLine() throws IOException{
System.out.println("call TotalTimeLine()");
queryAndAnalysisTotalTime();
HttpServletResponse response=ServletActionContext.getResponse();
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(data.toString());
return null;
}
private void queryAndAnalysisTotalTime(){
//准备数据
//查询总时间并求平均值
try {
conn = DBTools.getConnection();
state = conn.createStatement();
String sql = "select * from mytest..compress_time";
rs = state.executeQuery(sql);
float time[][] = new float[Variable.imgKinds][Variable.cpsWays];
while (rs.next()) {
int cpsWay = rs.getInt("cps_way");
int iamgeSize = rs.getInt("image_size");
float totalTime = rs.getFloat("total_time");
int sizeIndex = (int) (Math.log(iamgeSize/Variable.imgBase)/Math.log(2));
if (time[sizeIndex][cpsWay]!=0) {
time[sizeIndex][cpsWay] = (time[sizeIndex][cpsWay]+totalTime)/2;
}else {
time[sizeIndex][cpsWay] = totalTime;
}
}
List<List<Float>> aveTimeForCpsWay = new ArrayList<List<Float>>();
for (int i = 0; i < Variable.cpsWays; i++) {
List<Float> temp = new ArrayList<Float>();
for (int j = 0; j < Variable.imgKinds; j++) {
temp.add(time[j][i]);
}
aveTimeForCpsWay.add(temp);
}
data.put("aveTime", aveTimeForCpsWay);
} catch (Exception e) {
e.printStackTrace();
}finally{
DBTools.closeRs(rs);
DBTools.closeState(state);
DBTools.closeConn(conn);
}
}
public int getImgSize() {
return imgSize;
}
public void setImgSize(int imgSize) {
this.imgSize = imgSize;
}
}
3 struts.xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<package name="default" extends="struts-default">
<action name="draw_*" class="com.wlkfz.action.DrawPictrueAction" method="{1}">
<result name="success">/welcome.jsp</result>
<result name="fail">/showPic.jsp</result>
</action>
</package>
<!-- Add packages here -->
</struts>
在该struts.xml配置中,使用了通配符的方式,在Action的name属性中使用通配符后,可用一个<action.../>元素代替多个逻辑Action
上面的<action name="draw_*".../>元素不是定义了一个普通的Action,而是定义了一系列的逻辑Action---只要用户请求的URL是draw_*.action的模式,都可以用该Action来处理。配置该action元素时,还制定了method属性(method属性用于指定处理用户请求的方法),但该method属性使用了一个表达式{1},该表达式的值就是name属性值中第一个*的值,例如,如果用户请求的URL为draw_TotalTimeLine.action,则调用DrawPictrueAction类的TotalTimeLine方法。
4 ajax及highcharts图表js脚本编写
使用jQuery为JSP页内的两个按钮监听鼠标点击事件,在按钮click事件的方法内通过Ajax与DrawPictrueAction进行交互,并获取Action返回的JSON数据集合。在Ajax的回调函数内调用HighCharts插件提供的表格创建方法。
analysis.js
$(document).ready(function(){
$('#drawLine').click(function() {
$.getJSON("draw_TotalTimeLine.action",
function(result){
$('#container').highcharts({
chart: {
type: 'line'
},
title: {
text: '针对不同图像大小的不同压缩方式的总压缩时间对比'
},
subtitle: {
text: 'Source: WorldClimate.com'
},
xAxis: {
categories: ['256', '512', '1024', '2048', '4096']
},
yAxis: {
title: {
text: '时间 (ms)'
}
},
plotOptions: {
line: {
dataLabels: {
enabled: true
},
enableMouseTracking: false
}
},
series: [{
name: '基于CPU的串行压缩方式',
data: result.aveTime[0]
/*data: [19.64658,34.45484,135.8212,501.099,974.0006]*/
}, {
name: '基于GPU的并行压缩方式',
data: result.aveTime[1]
/*data: [26.54384,99.13428,466.198,2225.544,4933.468]*/
},{
name: 'CPU多线程并行拆包方案',
data: result.aveTime[2]
/*data: [26.54384,99.13428,466.198,2225.544,4933.468]*/
},{
name: '基于GPU的码流段拼接优化方案',
data: result.aveTime[3]
/*data: [26.54384,99.13428,466.198,2225.544,4933.468]*/
}]
});
});
/*getJSON方法必须要传回一个JSON对象*/
});
$("#drawBar").click(function() {
var size = $("#sizeSelect option:selected").text();
/*获取<s:select>当前选中的value值*/
$.getJSON("draw_partTimeCompare.action",{"imgSize":size},function(result){
$('#partTimeCompare').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Monthly Average Rainfall'
},
subtitle: {
text: 'Source: WorldClimate.com'
},
xAxis: {
categories: [
'基于CPU的串行压缩方式',
'基于GPU的并行压缩方式',
'CPU多线程并行拆包方案',
'基于GPU的码流段拼接优化方案',
],
crosshair: true
},
yAxis: {
min: 0,
title: {
text: 'Time (ms)'
}
},
tooltip: {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [{
name: 'DWT',
data: result.partTimeList[0]
}, {
name: 'SPIHT',
data: result.partTimeList[1]
}, {
name: 'TOTAL',
data: result.partTimeList[2]
}]
});
});
});
});