前不久項目組須要將測試相關的質量數據經過每日自動生成報表展現,並自動經過將報表做爲郵件正文內容知會到干係人郵箱。那麼問題來了,報表生成了,可是郵件怎麼發送,由於highcharts等報表都是經過JS和HTML在前端瀏覽器進行渲染生成的,而最要命的是郵箱爲了安全起見通常都不支持JS,因此就算後臺計算出了報表所需的數據,可是也沒法在郵件內容中生成報表。 後來想到phantomjs這個神器,它是一個基於webkit的內核瀏覽器,能夠不彈出瀏覽器界面在內存中模擬打開網頁,進而加載須要的東東(固然包括highchars等依靠JS生成的報表渲染); 因而採用如下解決方案:javascript
1. 用JAVA從數據庫查詢出報表須要的各類數據php
2. 在服務器經過JAVA跨進程調用phantomjs啓動進程打開指定的URL,加載和渲染highchars報表html
3. 等待若干秒,渲染完highchars報表後,調用phantomjs的網頁截屏功能,將固然網頁內容(報表內容)截圖保存成一個指定URI的圖片PNG或者JPG,保存到服務器某個指定目錄前端
4. 在郵件中直接用<img src="服務器上保存的報表圖片URI"> 進行引用加載圖片java
相關參考代碼:jquery
1. 新建你的JAVA類,發送郵件主JAVA方法:web
。。。。用java去數據庫取出報表所需數據,省略。。。shell
// 初始化趨勢圖片數據庫
ServletContext servletContext = ContextLoaderListener.getCurrentWebApplicationContext().getServletContext();
String ip = "IP";
int port = 8080;
String contextPath = servletContext.getContextPath();apache
String url =
"http://" + ip + ":" + port + contextPath + "/" + "router.do?service=testReport.testReportChart";
rootMap.put("chartUrl", url);
// String outfile = "/images"+contextPath+"/testReportChart/"+new Date().getTime()+"_"+new
// Random().nextInt(9999)+".png" ;
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmSS");
Date date = new Date();
String outfile_suffix =
"testReportChart/" + sdf.format(date) + date.getTime() + "_" + new Random().nextInt(9999) + ".png";
String outfile = "/xxx路徑/apache-tomcat-7.0.54/webapps/ROOT/" + outfile_suffix;
String outfileUrl = "http://" + ip + ":" + port + "/" + outfile_suffix;
// phantomjs文件存放位置
String infile = servletContext.getRealPath("/") + "js/phantomjs/capture.js";
try
{
//PhantomjsUtil.initHighchartImage爲調用phantomjs並返回結果 infile爲phantomjs腳本文件,outfile爲phantomjs生成圖片後保存的服務器URI
if ("success".equalsIgnoreCase(PhantomjsUtil.initHighchartImage(infile, url, outfile)))
{
rootMap.put("count404Image", outfileUrl);
}
else
{
// 默認圖片
rootMap.put("count404Image", "http://URL/1208_tOl.gif");
}
}
catch (Exception e)
{
// 默認圖片
rootMap.put("count404Image", "http://url/1208_tOl.gif");
e.printStackTrace();
}
。。。
result = testReportService.sendTemplateMail(rootMap, from, toEmail, cc, subject, templateName);
}
2.新建JAVA類PhantomjsUtil.java實現phantomjs調用(確保服務器上安裝好了phantomjs以及配置好環境變量)
package com.vipshop.util.hcharts.svg;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class PhantomjsUtil
{
/**
* @author sea.zeng
* @param infile String infile = " d:/phantomjs/capture.js " ;
* @param url String url = " http://ip:8080/xxx/router.do?service=xxxReport.xxxReportChart " ;
* @param outfile String outfile = " D:/phantomjs/testReportChart"+new Date().getTime()+"_"+new
* Random().nextInt(9999)+".png" ;
* @return String fail success
* @throws IOException
*/
public static String initHighchartImage(String infile, String url, String outfile)
throws IOException
{
String shell = " phantomjs ";
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(shell + " " + infile + " " + url + " " + outfile);
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuffer sbf = new StringBuffer();
String tmp = "";
while ((tmp = br.readLine()) != null)
{
sbf.append(tmp);
}
return sbf.toString();
}
}
3. 新建phantomjs的腳本文件capture.js並存放到指定目錄js/phantomjs/下
var page = require('webpage').create();
var system = require('system') ;
var url = system.args[1];
var outUri = system.args[2];
page.viewportSize = { width: 1400, height: 450 };
page.open(url, function (status) {
if (status !== 'success') {
console.log('fail');
} else {
window.setTimeout(function () {
console.log('success');
page.render(outUri);
phantom.exit();
}, 10000);
}
});
4. highchars圖表定義文件testReport_chart.ftl
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>xxxx趨勢圖</title>
<script type="text/javascript" src="http://${rootMap.ip}:${rootMap.port}/xxx/js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="http://${rootMap.ip}:${rootMap.port}/xxx/js/highcharts.js"></script>
<script type="text/javascript" src="http://${rootMap.ip}:${rootMap.port}/xxx/js/exporting.js"></script>
<script type="text/javascript" src="http://${rootMap.ip}:${rootMap.port}/xxx/js/highcharts-3d.js"></script>
<script>
</script>
</head>
<body>
<div id="container" style="min-width:700px;height:400px"></div>
</body>
</html>
<script>
function initHighCharts(newCountArray,closeCountArray,datesArray)
{
var closeDate = datesArray;
var closeArray = eval('([' + closeCountArray + '])');
var newArray = eval('([' + newCountArray + '])');
$('#container').highcharts({
chart: {
type: 'line'
},
title: {
text: '缺陷日新增與日關閉趨勢圖'
},
subtitle: {
text: 'App-特賣會'
},
xAxis: {
/*categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']*/
categories:closeDate
},
yAxis: {
title: {
text: '單位 (個)'
}
},
tooltip: {
enabled: false,
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+this.x +': '+ this.y +'°C';
}
},
plotOptions: {
line: {
dataLabels: {
enabled: true
},
enableMouseTracking: false
}
},
series: [{
name: '日新增',
data: newArray
}, {
name: '日關閉',
data: closeArray
}]
});
}
//異步獲得須要的版本統計數據
function queryCountList()
{
var version = $('#version').val();
if( isEmpty(version))
{
alert("不要偷懶,請先選擇版本吧...");
document.getElementById('version').focus();
return false;
}
$.post("bugzillapost.php",
{
methodType:'queryCountList',
version:version
},
function(data)
{
$("#content").html("");
var obj = JSON.parse(data);
if (obj.bugzillaCountList != undefined )
{
var bugzillaCountList = JSON.parse(obj.bugzillaCountList);
var trHtml = '' ;
if(null != bugzillaCountList && bugzillaCountList.length > 0)
{
for(var i=0;i < bugzillaCountList.length;i ++ )
{
var trClass = (i%2 == 0) ?"odd":"even" ;
trHtml += '<tr class=\"'+trClass+'\">';
trHtml += '<td >'+(i+1)+'</td>';
trHtml += '<td >'+bugzillaCountList[i].rep_platform+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].op_sys+'</td>';
trHtml += '<td >'+bugzillaCountList[i].bug_severity+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].today_new+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].today_close+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].today_reopen+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].total_reopen+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].to_fix+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].to_reg+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].closed+'</td>' ;
trHtml += '<td >'+bugzillaCountList[i].sub_total+'</td>' ;
trHtml += ' </tr>';
}
$("#content").prepend (trHtml);
$('table[id$="tableItem"]').find("tr").bind('click',function(event){
$('table[id$="tableItem"]').find("tr").removeClass("selected");
$(this).addClass("selected");
});
}
}
var newCountArray = JSON.parse(obj.newCountArray);
var closeCountArray = JSON.parse(obj.closeCountArray);
var datesArray = JSON.parse(obj.datesArray);
//newCountArray,closeCountArray,datesArray爲異步從後臺數據查出的數組,這裏先異步從PHP或者JAVA去數據庫取數據
initHighCharts(newCountArray,closeCountArray,datesArray);
});
}
</script>
5. 郵件經過報表圖片服務器的URL直接引用截圖保存後的報表
<h3><strong>附圖. xxxx趨勢圖<span style="font-size:12px">(<a href="${rootMap.chartUrl}" target="_blank">點擊查看詳細趨勢圖</a>)</span></strong></h3>
<div>
<img src = "${rootMap.countImage}" />
</div>
本着資源共享的原則,歡迎各位朋友在此基礎上完善,並進一步分享,讓咱們的實現更加優雅。若是有任何疑問和須要進一步交流能夠加我QQ 1922003019或者直接發送QQ郵件給我溝通
sea 20150610 中國:廣州: VIP