這裏使用的highchart是2014-01-09從官網下載的版本,版本號是3.0.8,html
當過了幾天後,發現版本號變成了3.0.9,不禁得的感嘆highchart的版本更新之快。java
在jsp中使用highchart的步驟:jquery
第一步:引入highchart必需的js文件web
<! -- jquery的js要在引入highchart插件的js以前引入 --> <script src="<%=basePath%>js/Highcharts3.0.8/jquery-1.8.3.js"> </script> <!-- 實現highchart核心功能的js --> <script src="<%=basePath%>js/Highcharts3.0.8/highcharts.js"> </script> <!-- 導出和打印相關的js ,由於這裏修改過的exporting.js包含中文,使用 charset="UTF-8" 進行指定 --> <script src="<%=basePath%>js/Highcharts3.0.8/exporting.js" charset="UTF-8"> </script>
開發過程遇到的問題:sql
1) Js的引入順序錯了,致使highchart的圖表出不來,json
Highchart插件中用到了jquery,當時jquery-1.8.3.js的引入順序放到了highchart插件js的下面,數組
致使當加載highchart插件用到的js時,找不到jquery的js,報出某個js的函數不合法瀏覽器
所以 jquery的js要在引入highchart的js以前引入網絡
2) exporting.js 打印下載的js中,提示的都是英文,oracle
要顯示中文,這裏採用的方法是修改exporting.js
p(s.lang,{printChart:"打印報表",downloadPNG:"下載爲PNG格式圖片",downloadJPEG:"下載爲JPEG格式圖片",
downloadPDF:"下載爲PDF格式文檔",downloadSVG:"下載爲SVG格式矢量圖片",contextButtonTitle:"打印 下載"});
修改後的效果:
當修改了exporting.js後,當保存時,無法保存js,提示編碼問題
解決方法是:
window>>preferences>>general>>content types 在右邊的窗口中打開列表,選中"JavaScript",在下面的"default encoding"右邊的輸入框中輸入"utf-8",再點"update"按鈕
單擊打印下載時,顯示的下拉框在大部分的ie瀏覽器中顯示的很難看,火狐下正常
緣由: 上面的下拉框顯示很長,是因爲hr標籤的緣由,致使hr的寬度按照 100%進行了顯示
解決方法:
在顯示highchart圖標的jsp頁面中,添加hr的樣式
<style>
hr{height: 0;margin: 0;padding: 0;width: 0;}
</style>
第二步:組裝添加顯示highchart圖表所用的數據
顯示highchart圖標的js代碼
$(function () {
//填充數據使用,使用jquery來獲取隱藏域的值
var xAxisTimeInfo = $("#xAxisTime").val();
var totalRecordInfo = $("#totalRecord").val();
var totalRecordHYInfo = $("#totalRecordHY").val();
var totalRecordLJInfo = $("#totalRecordLJ").val();
$('#container').highcharts({
chart: {
type: 'spline'
},
title: {
text: '每個月訂單數量統計'
},
subtitle: {
text: ''
},
exporting:{
filename:"訂單統計", //下載顯示的文件名稱
sourceWidth: 1000, //下載圖片的寬度
sourceHeight: 550, //下載圖片的高度
//指定下載圖片的url,這裏使用的本地的java代碼,沒有使用官網的代碼(那//樣會受到highchart官網的網絡限制,這裏的java代碼是結合的struts1來//實現的,在java代碼解決了導出圖片中中文亂碼的問題以及下載文件名亂碼//的問題,詳見java代碼中說明) url:'<%=basePath%>shop/newOrder/orderPre/exportImage.do'//這裏是一個重點哦,也能夠修改exporting.js中對應的url }, /** * 去掉圖標的右下角HightCharts.com 的圖標 */ credits: { enabled : false, //設置false就不會顯示右下角的官網連接 //右下角鏈接的顯示位置 position:{ align: 'right',x: -8, verticalAlign: 'bottom',y: -390 }, //右下角連接的地址href:'<%=basePath%>shop/newOrder/orderPre/orderSearch4HighCharts.do?type=1', text:'區域圖表',//右下角鏈接的名字 style : {cursor:'pointer',color:'#909090',fontSize:'20px'} }, xAxis: { categories: eval(xAxisTimeInfo) }, yAxis: { min: 0, title: { text: '單位 (個)' } }, //鼠標旁邊的提示框的樣式 //1. point.y:.0f 提示框中顯示的y軸單位的小數點位數 //2. style="width:160px;height:50px" 提示框的寬高 //3. point.key 座標的x軸的值 tooltip: { headerFormat: '<span style="font-size:20px;">{point.key}</span><table style="width:160px;height:50px">', pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' + '<td style="padding:0"><b>{point.y:.0f} </b></td></tr>', footerFormat: '</table>', shared: true, useHTML: true }, plotOptions: { column: { pointPadding: 0.2, borderWidth: 0 } }, //圖例的顯示名稱和數據 //這裏使用了eval函數處理一下,使用jquery獲取到的隱藏域的值 //不然不會顯示 series: [{ name: '裸機數量', data: eval(totalRecordLJInfo) }, { name: '訂單總量', data: eval(totalRecordInfo) }, { name: '合約機數量', data: eval(totalRecordHYInfo) }] }); });
基本的highchart顯示的數據格式是:
X軸數據信息
圖例和顯示數據的格式:
所以咱們要作的就是根據需求,在java後臺組裝好上面的數據,填充到highchart的js代碼中便可
導出的Java後臺代碼 (使用的是struts1)沒有在struts的配置文件中配置,直接是在jsp中url請求
struts1版的結合highchart導出圖片的java代碼
使用highchart調用本地的java類導出圖片時,用到的jar包
batik-all-1.6.jar fop.jar xerces-2.9.0.jar
/** * 配合highchart插件導出圖片 * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward exportImage (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { log.info("圖片導出................"); request.setCharacterEncoding("gb2312");//設置編碼,解決亂碼問題 String type = request.getParameter("type"); String svg = request.getParameter("svg"); response.setCharacterEncoding("gb2312");//設置編碼,解決亂碼問題 String filename = request.getParameter("filename"); filename = filename==null?"chart":filename; ServletOutputStream out = response.getOutputStream(); log.info("type :"+type+" filename:"+filename); if (null != type && null != svg) { svg = svg.replaceAll(":rect", "rect"); String ext = ""; Transcoder t = null; if (type.equals("image/png")) { ext = "png"; t = new PNGTranscoder(); } else if (type.equals("image/jpeg")) { ext = "jpg"; t = new JPEGTranscoder(); }else if (type.equals("application/pdf")) { ext = "pdf"; t =(Transcoder) new PDFTranscoder(); }else if(type.equals("image/svg+xml")) ext = "svg"; //解決下載文件的文件名的亂碼 response.addHeader("Content-Disposition", "attachment; filename="+ new String (filename.getBytes("gb2312"),"iso-8859-1") + "."+ext); response.addHeader("Content-Type", type); if (null != t) { TranscoderInput input = new TranscoderInput(new StringReader(svg)); TranscoderOutput output = new TranscoderOutput(out); try { t.transcode(input, output); } catch (TranscoderException e) { out.print("Problem transcoding stream. See the web logs for more details."); e.printStackTrace(); } } else if (ext.equals("svg")) { OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); writer.append(svg); writer.close(); } else out.print("Invalid type: " + type); } else { response.addHeader("Content-Type", "text/html"); out.println("Usage:\n\tParameter [svg]: The DOM Element to be converted." + "\n\tParameter [type]: The destination MIME type for the elment to be transcoded."); } out.flush(); out.close(); return null; }
使用highchart生成報表信息的部分後臺java代碼
開發中遇到的問題
java代碼片斷
Dao層的代碼片斷,查詢數據封裝成map,而後把map數據放到List中,而後在把list放到map中,調用json-lib插件轉換成json數據
List ltHY = findSQL(dto, sqlHY.toString(), list.toArray()); List adminSqlTotalHY = new ArrayList(); //使用的LinkedHashMap,放到map中的數據使用順序的 Map<String ,String> totalRecordHYMap = new LinkedHashMap<String ,String>(); for (int i = 0; ltHY!=null && i < ltHY.size(); i++) { Object[] obj = (Object[]) ltHY.get(i); totalRecordHYMap.put(obj[0]!=null?String.valueOf(obj[0]):"" ,obj[1]!=null? String.valueOf(obj[1]):""); } adminSqlTotalHY.add(totalRecordHYMap); //保存到map中 Map recordInfo = new LinkedHashMap(); recordInfo.put("Record_total", adminSqlTotalList); recordInfo.put("Record_LJ", adminSqlTotalLJ); recordInfo.put("Record_HY", adminSqlTotalHY); //把map數據轉化爲json數據 JSONObject jsonObjectFromMap =JSONObject.fromObject(recordInfo); dto.setAddress(jsonObjectFromMap.toString());
action層代碼
/** * 1. 構造HighChart的x軸用到的每個月時間數據信息 (月份不足兩位的沒有補0,直接放在request中)<P/> * 2. 返回值map中月份不足2位的,進行了補0,該map在構造每個月訂單數量統計時使用 * @throws ParseException */ private Map extractHighChartXAxisInfo(HttpServletRequest request) throws ParseException { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); Calendar curr = Calendar.getInstance(); Calendar curr2 = curr; Date beginPayDate = curr.getTime(); // 傳進來的當前時間 curr2.add(Calendar.YEAR, -1); curr2.add(Calendar.MONTH, 1); Date endPayDate = curr2.getTime(); // 上一年的時間 GregorianCalendar[] ga=getDate(simpleDateFormat.format(endPayDate), simpleDateFormat.format(beginPayDate)); //循環數組 StringBuffer stringBuffer = new StringBuffer(); Map initMap = new LinkedHashMap(); stringBuffer.append("["); for(GregorianCalendar e:ga) { stringBuffer.append("'"+modifyTimeAnthor(e)+"',"); initMap.put(modifyTime(e), 0); } //當ga數組中有數據時才刪除末尾的 逗號 if(stringBuffer.length()>1){ stringBuffer.deleteCharAt(stringBuffer.length()-1); } stringBuffer.append("]"); log.info("x軸用到的每個月時間數據信息 (月份不足兩位的沒有補0) "+stringBuffer.toString()); request.setAttribute("highChartXAxisInfo", stringBuffer.toString()); return initMap; }
/** * * @param startTime * @param endTime * @return 返回開始時間和結束時間之間的每個月 * 如:2013.1 2013.2 2013.3 2013.4 2013.5 2013.6 2013.7 * @throws ParseException */ public static GregorianCalendar[] getDate(String startTime,String endTime) throws ParseException { Vector<GregorianCalendar> v=new Vector<GregorianCalendar>(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM"); GregorianCalendar gc1=new GregorianCalendar(),gc2=new GregorianCalendar(); gc1.setTime(sdf.parse(startTime)); gc2.setTime(sdf.parse(endTime)); do{ GregorianCalendar gc3=(GregorianCalendar)gc1.clone(); v.add(gc3); gc1.add(Calendar.MONTH, 1); }while(!gc1.after(gc2)); return v.toArray(new GregorianCalendar[v.size()]); } //按格式獲取時間,月份不足兩位的補0 public static String modifyTime(GregorianCalendar e){ String curdate = e.get(Calendar.YEAR)+""; if((e.get(Calendar.MONTH)+1)<10){ curdate = curdate+".0" +(e.get(Calendar.MONTH)+1); }else { curdate = curdate+"."+(e.get(Calendar.MONTH)+1); } return curdate; } //按格式獲取時間,月份不足兩位的沒有補0 public static String modifyTimeAnthor(GregorianCalendar e){ String curdate = e.get(Calendar.YEAR)+""; curdate = curdate+"."+(e.get(Calendar.MONTH)+1); return curdate; } /** * 1. 傳遞查詢時間段的日期信息<p/> * 2. 要求查詢當月以及向前倒推11個月(總共12的月)的數據<p/> * 3. 如當前日期是 2014.01,則構造開始時間2013.02,結束時間2014.02,都是因爲oracle的between and * @param mulOrderDTO */ private void passDateInfo(TMulOrderCountDTO mulOrderDTO) { //傳遞月份信息 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM"); Calendar curr = Calendar.getInstance(); //注意這裏把curr變量的引用賦值給了curr2,當curr的值變化時,會影響到curr2的值 Calendar curr2 = curr; curr.add(Calendar.MONTH, 1); Date beginPayDate = curr.getTime(); // 傳進來的當前時間 curr2.add(Calendar.YEAR, -1); Date endPayDate = curr2.getTime(); // 上一年的時間 mulOrderDTO.setBeginPayDate(simpleDateFormat.format(endPayDate)); mulOrderDTO.setEndPayDate(simpleDateFormat.format(beginPayDate)); }
/** * 構造每月 訂單總量、合約機總量、裸機總量的字符串信息,用於填充highChart插件 * @param request * @param str */ @SuppressWarnings("unchecked") private void extractHighChartRecordInfo(HttpServletRequest request, String str,Map initMap) { //接受最初傳進來的map,使用了LinkedHashMap的構造方法,參數爲map //因爲數據的顯示問題,這裏構造了初始化的LinkedHashMap(帶順序) Map originalTotalMap = new LinkedHashMap(initMap); Map originalTotalLJMap = new LinkedHashMap(initMap); Map originalTotalHYMap = new LinkedHashMap(initMap); //把json數據從新轉換爲Map數據 Map<String, Object> m = parseJSON2Map(str); //遍歷map,拿到map的key的集合的迭代對象 Iterator<Map.Entry<String,Object>> iterator = m.entrySet().iterator(); while(iterator.hasNext()){ //拿到當前的迭代對象 Map.Entry<String, Object> me = iterator.next(); //拿到當前迭代對象的key(能夠看作map的key) String key = me.getKey(); String keyW = key.substring(key.indexOf("_")+1); if("LJ".equals(keyW)){ //拿到當前迭代對象的value,是List對象,取第一個元素拿到map List li = (List) me.getValue(); //拿到map Map map = (Map) li.get(0); //覆蓋一下初始化map的數據 originalTotalLJMap.putAll(map); //拿到實際上保存數據的Map集合,如保存每個月裸機訂單數據的map Iterator<Map.Entry<String,Object>> iterator1 = originalTotalLJMap.entrySet().iterator(); StringBuffer stringBufferLJ = new StringBuffer(); stringBufferLJ.append("["); log.info("解析每個月裸機數據.................................................."); while(iterator1.hasNext()){ Map.Entry<String, Object> mea = iterator1.next(); //這裏的getKey獲取到是月份 如:2013.1 String keya = mea.getKey(); log.info(keya+" "+mea.getValue()); // getValue()是獲取當月的訂單數量,保存到StringBuffer中,並處理//StringBuffer數據使得知足highchart插件的要求 stringBufferLJ.append(mea.getValue()+","); } //當iterator1中有數據時才刪除掉末尾的逗號 if(stringBufferLJ.length()>1){ stringBufferLJ.deleteCharAt(stringBufferLJ.length()-1); } stringBufferLJ.append("]"); log.info("裸機訂單數量 :"+stringBufferLJ.toString()); request.setAttribute("totalRecordLJ", stringBufferLJ.toString()); } if("HY".equals(keyW)){ List li = (List) me.getValue(); //拿到map Map map = (Map) li.get(0); originalTotalHYMap.putAll(map); Iterator<Map.Entry<String,Object>> iterator1 = originalTotalHYMap.entrySet().iterator(); StringBuffer stringBufferHY = new StringBuffer(); stringBufferHY.append("["); log.info("解析每個月合約機數據.................................................."); while(iterator1.hasNext()){ Map.Entry<String, Object> mea = iterator1.next(); String keya = mea.getKey(); stringBufferHY.append(mea.getValue()+","); log.info(keya+" "+mea.getValue()); } //當iterator1中有數據時才刪除掉末尾的逗號 if(stringBufferHY.length()>1){ stringBufferHY.deleteCharAt(stringBufferHY.length()-1); } stringBufferHY.append("]"); log.info("合約機訂單數量 :"+stringBufferHY.toString()); request.setAttribute("totalRecordHY", stringBufferHY.toString()); } if("total".equals(keyW)){ List li = (List) me.getValue(); //拿到map Map map = (Map) li.get(0); originalTotalMap.putAll(map); Iterator<Map.Entry<String,Object>> iterator1 = originalTotalMap.entrySet().iterator(); StringBuffer stringBufferTotal = new StringBuffer(); stringBufferTotal.append("["); log.info("解析每個月訂單總量數據.................................................."); while(iterator1.hasNext()){ Map.Entry<String, Object> mea = iterator1.next(); String keya = mea.getKey(); stringBufferTotal.append(mea.getValue()+","); log.info(keya+" "+mea.getValue()); } //當iterator1中有數據時才刪除掉末尾的逗號 if(stringBufferTotal.length()>1){ stringBufferTotal.deleteCharAt(stringBufferTotal.length()-1); } stringBufferTotal.append("]"); log.info("總訂單數量 :"+stringBufferTotal.toString()); request.setAttribute("totalRecord", stringBufferTotal.toString()); } } }
highcharts效果圖
附上jsp的代碼
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <head> <script src="<%=basePath%>js/Highcharts3.0.8/jquery-1.8.3.js"></script> <script src="<%=basePath%>js/Highcharts3.0.8/highcharts.js"></script> <script src="<%=basePath%>js/Highcharts3.0.8/exporting.js" charset="UTF-8"></script> <style> hr{height: 0;margin: 0;padding: 0;width: 0;} </style> <script> $(function () { var xAxisTimeInfo = $("#xAxisTime").val(); var totalRecordInfo = $("#totalRecord").val(); var totalRecordHYInfo = $("#totalRecordHY").val(); var totalRecordLJInfo = $("#totalRecordLJ").val(); $('#container').highcharts({ chart: { type: 'column' }, title: { text: '每個月訂單數量統計' }, subtitle: { text: '' }, exporting:{ filename:"訂單統計", sourceWidth: 1000, sourceHeight: 550, url:'<%=basePath%>shop/newOrder/orderPre/exportImage.do'//這裏是一個重點哦,也能夠修改exporting.js中對應的url }, /** * 去掉圖標的右下角HightCharts.com 的圖標 */ credits: { enabled : false, position:{ align: 'right',x: -8, verticalAlign: 'bottom',y: -390 }, href:'<%=basePath%>shop/newOrder/orderPre/orderSearch4HighCharts.do?type=1', text:'區域圖表', style : {cursor:'pointer',color:'#909090',fontSize:'20px'} }, xAxis: { categories: eval(xAxisTimeInfo) }, yAxis: { min: 0, title: { text: '單位 (個)' } }, tooltip: { headerFormat: '<span style="font-size:20px;">{point.key}</span><table style="width:160px;height:50px">', pointFormat: '<tr><td style="padding:0">{series.name}: </td>' + '<td style="padding:0"><b>{point.y:.0f} </b></td></tr>', footerFormat: '</table>', shared: true, useHTML: true }, plotOptions: { column: { pointPadding: 0.2, borderWidth: 0 } }, series: [{ name: '裸機數量', data: eval(totalRecordLJInfo) }, { name: '訂單總量', data: eval(totalRecordInfo) }, { name: '合約機數量', data: eval(totalRecordHYInfo) }] }); });