通过echarts的jar包,Java后台生成一张图片,并把图片插入到word中。关于word插图片的代码在下一章。
需要用到的工具PhantomJS,Echarts-convert.js,jquery.js,echarts.js。
PhantomJS是一个不需要浏览器的富客户端。
官方介绍:PhantomJS是一个基于 WebKit 的服务器端JavaScript API。它全面支持web而不需浏览器支持,支持各种Web标准:DOM处理,CSS选择器, JSON,Canvas,和SVG。
PhantomJS常用于页面自动化,网络监测,网页截屏,以及无界面测试等。
通常我们使用PhantomJS作为爬虫工具。传统的爬虫只能单纯地爬取html的代码,对于js渲染的页面,就无法爬取,如Echarts统计图。而PhantomJS正可以解决此类问题。
我们可以这么理解PhantomJS,PhantomJS是一个无界面、可运行脚本的谷歌浏览器。
PhantomJS安装非常简单,官网http://phantomjs.org/download.html下载最新的安装包, 安装包有Windows,Mac OS X, Linux 64/32 bit,选择对应的版本下载解压即可使用,在下载包里有个example文件夹,里面对应了许多示例供参考。
为方便使用,我们将phantomjs添加至环境变量中。
windows下操作:
path 下添加 C:\Users\ming\Desktop\java-echarts\phantomjs-2.1.1-windows\bin
打开cmd,查看是否配置成功
C:\Users\ming>phantomjs --version
2.1.1
linux 下操作:
export PHANTOMJS=/usr/local/phantomjs/phantomjs-2.1.1-linux-x86_64
export PATH=$PATH:$PHANTOMJS/bin
# or
export PATH=$PATH:/usr/local/phantomjs/phantomjs-2.1.1-linux-x86_64/bin
# 刷新配置
source /etc/profile
注:linux虽然不需要其他的依赖包,但仍旧需要GLIBCXX_3.4.9和GLIBC_2.7,当然大多数linux是有这两个依赖包的。
安装包下 example 文件夹下提供了好多示例,这里以hello.js 为例,在example文件夹下输入 phantomjs hello.js 命令 会输出 Hello, world! 更多用法可参考官方文档。
C:\Users\ming\Desktop\java-echarts\phantomjs-2.1.1-windows\examples>phantomjs hello.js
Hello, world!
上面讲述了PhantomJS如何使用,下面我们就从Echarts官网使用JS截图的方式来获取我们想要的图片
Echartsconvert (Gitee)copy下来代码
注意:因为该源码长期没有更新,script目录下echarts.min.js太过于老旧,无法支持目前Echarts的图形,请大家copy下代码后,更新替换其文件 。最新echarts.min.js下载传送门
其中echarts-convert.js就是我们要使用到的主C,这个Js就相当于帮我们去Echarts官方运行Dome->生成折线图/柱状图->保存到指定文件夹下
jquery.js自行下载对应版本,我的是3.6.3
附上echarts-converts.js文件
;(function (window, document, undefined) {
"use strict";
// 引入module
var system = require('system'), // 获取参数
path = phantom.libraryPath,
command = require(path + '/module/command.js');// 参数module
/**
* phantomJs 全局异常监听
* @param msg
* @param trace
*/
phantom.onError = function (msg, trace) {
var msgStack = ['Convert ERROR: ' + msg];
if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function (t) {
msgStack.push(' -> ' + (t.file || t.sourceURL) + ': ' + t.line + (t.function ? ' (in function ' + t.function + ')' : ''));
});
}
console.error(msgStack.join('\n'));
phantom.exit(1);
};
/**
* 参数
* @type {Command}
*/
var commandParams = command
.version('0.0.1')
.option('-s, --server', 'provide echarts convert http server')
.option('-p, --port ', 'change server port when add -s or --server', 9090)
.option('-o, --opt ', 'add the param of echarts method [ eChart.setOption(opt) ]')
.option('-t, --type ', 'provide file/base64 for image, default file', /^(file|base64)$/i, 'base64')
.option('-f, --outfile ', 'add output of the image file path')
.option('-w, --width ', 'change image width', '600')
.option('-h, --height ', 'change image height', '400')
.parse(system.args);
// ***********************************
// Echarts转换器
// ***********************************
function Convert(params) {
this.params = params || commandParams; // 参数命令
this.external = {
JQUERY3: path + '/script/jquery-3.6.3.min.js',
ECHARTS: path + '/script/echarts.min.js',
ECHARTS_CHINA: path + '/script/china.js'
}; // 外部js
}
/**
* 初始化
*/
Convert.prototype.init = function () {
var params = this.params;
this.check(params);
if (params.server) {
this.server(params);
} else {
this.client(params);
}
};
/**
* 参数检查
* @param params
*/
Convert.prototype.check = function (params) {
if (undefined === params.server && undefined === params.opt) {
this.error("option argument missing -o, --opt ");
}
if (undefined !== params.opt) {
var isJson = this.checkJson(params.opt);
if (!isJson) {
this.error("--opt args not json string");
}
}
if ('file' === params.type && undefined === params.outfile) {
this.createTmpDir();
}
};
/**
* 检查是否是json字符串
* @param value
* @returns {boolean}
*/
Convert.prototype.checkJson = function (value) {
var re = /^\{[\s\S]*\}$|^\[[\s\S]*\]$/;
// 类型为string
if (typeof value !== 'string') {
return false;
}
// 正则验证
if (!re.test(value)) {
return false;
}
// 是否能解析
try {
value = "\"" + value + "\"";
JSON.parse(value);
} catch (err) {
return false;
}
return true;
};
/**
* 创建临时目录,并指定输出路径
*/
Convert.prototype.createTmpDir = function () {
var fs = require('fs'); // 文件操作
var tmpDir = fs.workingDirectory + '/tmp';
// 临时目录是否存在且可写
if (!fs.exists(tmpDir)) {
if (!fs.makeDirectory(tmpDir)) {
this.error('Cannot make ' + tmpDir + ' directory\n');
}
}
this.params.outfile = tmpDir + "/" + new Date().getTime() + ".png";
};
/**
* 服务
* @param params
*/
Convert.prototype.server = function (params) {
var server = require('webserver').create(), // 服务端
convert = this;
var listen = server.listen(params.port, function (request, response) {
/**
* 输出
* @param data
* @param success
*/
function write(data, success, msg) {
response.statusCode = 200;
response.headers = {
'Cache': 'no-cache',
'Content-Type': 'application/json;charset=utf-8'
};
response.write(convert.serverResult(data, success, msg));
response.close();
}
//获取参数
var args = convert.serverGetArgs(request);
if (args.opt !== undefined) {
var check = convert.serverCheckAndSet(params, args);
if (check) {
convert.client(params, write);
} else {
write("", false, "failed to get image, please check parameter [opt] is a JSON");
}
} else {
write("", false, "failed to get image, missing parameter [opt]");
}
});
// 判断服务是否启动成功
if (!listen) {
this.error("could not create echarts-convert server listening on port " + params.port);
} else {
console.log("echarts-convert server start success. [pid]=" + system.pid);
}
};
/**
* 服务参数检查和赋值
* @param params
* @param args
* @returns {boolean}
*/
Convert.prototype.serverCheckAndSet = function (params, args) {
if (this.checkJson(args.opt)) {
params.opt = args.opt;
} else {
return false;
}
if (/^(file|base64)$/i.exec(args.type)) {
params.type = args.type;
}
if (!isNaN(args.width)) {
params.width = args.width;
}
if (!isNaN(args.height)) {
params.height = args.height;
}
return true;
};
/**
* 结果返回
* @param data
* @param success
* @param msg
*/
Convert.prototype.serverResult = function (data, success, msg) {
var result = {
code: success ? 1 : 0,
msg: undefined === msg ? success ? "success" : "failure" : msg,
data: data
};
return JSON.stringify(result);
};
/**
* 获取参数
* @param request
* @returns {{}}
*/
Convert.prototype.serverGetArgs = function (request) {
var args = {};
if ('GET' === request.method) {
var index = request.url.indexOf('?');
if (index !== -1) {
var getQuery = request.url.substr(index + 1);
args = this.serverParseArgs(getQuery);
}
} else if ('POST' === request.method) {
var postQuery = request.post;
args = this.serverParseArgs(postQuery);
}
return args;
};
/**
* 解析参数
* @param query 字符串
* @returns {{}} 对象
*/
Convert.prototype.serverParseArgs = function (query) {
var args = {},
pairs = query.split("&");
for (var i = 0; i < pairs.length; i++) {
var pos = pairs[i].indexOf('=');
if (pos === -1)
continue;
var key = pairs[i].substring(0, pos);
var value = pairs[i].substring(pos + 1);
// 中文解码,必须写两层
value = decodeURIComponent(decodeURIComponent(value));
args[key] = value;
}
return args;
};
/**
* 访问渲染
* @param params
* @param fn
*/
Convert.prototype.client = function (params, fn) {
var page = require('webpage').create(); // 客户端
var convert = this,
external = this.external,
render,
output;
/**
* 渲染
* @returns {*}
*/
render = function () {
switch (params.type) {
case 'file':
// 渲染图片
page.render(params.outfile);
return params.outfile;
case 'base64':
default:
var base64 = page.renderBase64('PNG');
return base64;
}
};
/**
* 输出
* @param content 内容
* @param success 是否成功
*/
output = function (content, success, msg) {
if (params.server) {
fn(content, success, msg);
page.close();
} else {
console.log(success ? "[SUCCESS]:" : "[ERROR]:" + content);
page.close();
convert.exit(params);// exit
}
};
/**
* 页面console监听
* @param msg
* @param lineNum
* @param sourceId
*/
page.onConsoleMessage = function (msg, lineNum, sourceId) {
console.log(msg);
};
/**
* 页面错误监听
* @param msg
* @param trace
*/
page.onError = function (msg, trace) {
output("", false, msg); // 失败,返回错误信息
};
// 空白页
page.open("about:blank", function (status) {
// 注入依赖js包
var hasJquery = page.injectJs(external.JQUERY3);
var hasEchart = page.injectJs(external.ECHARTS);
var hasEchartChina = page.injectJs(external.ECHARTS_CHINA);
// 检查js是否引用成功
if (!hasJquery && !hasEchart) {
output("Could not found " + external.JQUERY3 + " or " + external.ECHARTS, false);
}
// 创建echarts
page.evaluate(createEchartsDom, params);
// 定义剪切范围,如果定义则截取全屏
page.clipRect = {
top: 0,
left: 0,
width: params.width,
height: params.height
};
// 渲染
var result = render();
// 成功输出,返回图片或其他信息
output(result, true);
});
};
/**
* 创建eCharts Dom层
* @param params 参数
*/
function createEchartsDom(params) {
// 动态加载js,获取options数据
$('