Java - PhantomJS + EChartsConvert实现ECharts图片保存到服务端
1、所需工具
1》phantomjs:官网下载http://phantomjs.org/download.html 国内镜像http://npm.taobao.org/dist/phantomjs/
2》EChartConvert:https://gitee.com/saintlee/echartsconvert
2、Maven依赖
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.7</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
3、使用phantomjs装载运行EChartConvert
1》phantomjs、EChartConvert解压即可使用
解压 phantomjs-2.1.1-windows.zip 和 saintlee-echartsconvert-master.zip。配置phantomjs环境变量。
命令行输入:<phantomjs路径> <EChartsConvert路径> -s -p <服务端口号>
Microsoft Windows [版本 6.1.]
版权所有 (c) Microsoft Corporation。保留所有权利。 C:\fyliu\software\phantomjs-2.1.-windows\echartsconvert-gitee>phantomjs echarts
-convert.js -s -p
echarts-convert server start success. [pid]=
4、项目目录结构

1》HttpUtil.java
package com.lfy.cn.PhantomJSEChartsTest.util; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils; public class HttpUtil { public static String post(String url, Map<String, String> params, String charset)
throws ClientProtocolException, IOException {
String responseEntity = ""; // 创建CloseableHttpClient对象
CloseableHttpClient client = HttpClients.createDefault(); // 创建post方式请求对象
HttpPost httpPost = new HttpPost(url); // 生成请求参数
List<NameValuePair> nameValuePairs = new ArrayList<>();
if (params != null) {
for (Entry<String, String> entry : params.entrySet()) {
nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
} // 将参数添加到post请求中
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, charset)); // 发送请求,获取结果(同步阻塞)
CloseableHttpResponse response = client.execute(httpPost); // 获取响应实体
HttpEntity entity = response.getEntity();
if (entity != null) {
// 按指定编码转换结果实体为String类型
responseEntity = EntityUtils.toString(entity, charset);
} // 释放资源
EntityUtils.consume(entity);
response.close(); return responseEntity;
}
}
2》FreemarkerUtil.java
package com.lfy.cn.PhantomJSEChartsTest.util; import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map; import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException; public class FreemarkerUtil {
private static final String path = FreemarkerUtil.class.getClassLoader().getResource("").getPath(); public static String generateString(String templateFileName, String templateDirectory, Map<String, Object> datas)
throws IOException, TemplateException {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_0); // 设置默认编码
configuration.setDefaultEncoding("UTF-8"); // 设置模板所在文件夹
configuration.setDirectoryForTemplateLoading(new File(path + templateDirectory)); // 生成模板对象
Template template = configuration.getTemplate(templateFileName); // 将datas写入模板并返回
try (StringWriter stringWriter = new StringWriter()) {
template.process(datas, stringWriter);
stringWriter.flush();
return stringWriter.getBuffer().toString();
}
}
}
3》EchartsUtil.java
package com.lfy.cn.PhantomJSEChartsTest.util; import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import org.apache.http.client.ClientProtocolException; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; public class EchartsUtil {
private static String url = "http://localhost:6666";
private static final String SUCCESS_CODE = "1"; public static String generateEchartsBase64(String option) throws ClientProtocolException, IOException {
String base64 = "";
if (option == null) {
return base64;
}
option = option.replaceAll("\\s+", "").replaceAll("\"", "'"); // 将option字符串作为参数发送给echartsConvert服务器
Map<String, String> params = new HashMap<>();
params.put("opt", option);
String response = HttpUtil.post(url, params, "utf-8"); // 解析echartsConvert响应
JSONObject responseJson = JSON.parseObject(response);
String code = responseJson.getString("code"); // 如果echartsConvert正常返回
if (SUCCESS_CODE.equals(code)) {
base64 = responseJson.getString("data");
}
// 未正常返回
else {
String string = responseJson.getString("msg");
throw new RuntimeException(string);
} return base64;
}
}
option.ftl
{
title: {
text:'${title}',
x:'middle',
textAlign:'center'
},
xAxis: {
type: 'category',
data: ${categories}
},
yAxis: {
type: 'value'
},
series: [{
data: ${values},
type: 'bar'
}]
}
App.java
package com.lfy.cn.PhantomJSEChartsTest; import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap; import org.apache.http.client.ClientProtocolException; import com.alibaba.fastjson.JSON;
import com.lfy.cn.PhantomJSEChartsTest.util.EchartsUtil;
import com.lfy.cn.PhantomJSEChartsTest.util.FreemarkerUtil; import freemarker.template.TemplateException;
import sun.misc.BASE64Decoder; public class App {
public static void main(String[] args) throws ClientProtocolException, IOException, TemplateException {
// 变量
String title = "水果";
String[] categories = new String[] { "苹果", "香蕉", "西瓜" };
int[] values = new int[] { 3, 2, 1 }; // 模板参数
HashMap<String, Object> datas = new HashMap<>();
datas.put("categories", JSON.toJSONString(categories));
datas.put("values", JSON.toJSONString(values));
datas.put("title", title); // 生成option字符串
String option = FreemarkerUtil.generateString("option.ftl", "/com/lfy/cn/PhantomJSEChartsTest/template", datas); // 根据option参数
String base64 = EchartsUtil.generateEchartsBase64(option); System.out.println("BASE64:" + base64);
generateImage(base64, "C:/Users/lfy/Desktop/test.png");
} public static void generateImage(String base64, String path) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
try (OutputStream out = new FileOutputStream(path)){
// 解密
byte[] b = decoder.decodeBuffer(base64);
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
out.write(b);
out.flush();
}
}
}
运行结果:生成一张ECharts图片

注:本文出自https://www.jianshu.com/p/dfc28fd7d786,支持原创。
Java - PhantomJS + EChartsConvert实现ECharts图片保存到服务端的更多相关文章
- ASP.NET Core单文件和多文件上传并保存到服务端
前言: 在我们日常开发中,关于图片,视频,音频,文档等相关文件上传并保存到服务端中是非常常见的一个功能,今天主要是把自己在开发中常用的两种方式记录下来方便一下直接使用,并且希望能够帮助到有需要的同学! ...
- miniui datagrid 保存到服务端,使用.NET 自带 JSON 转换时发现日期格式不兼容。
使用 miniui datagrid 修改表格后,保存到服务端,然后使用 .NET 自带 JSON 转换,会抛出DateTime 内容“2015-12-27T11:02:28”未按 JSON 的要求以 ...
- php+tcpdf如何把生成的pdf文件保存在服务端
tcpdf组件目前应用得非常广泛,但是对于如何把生成的pdf文件自动保存在服务端却很少有人提及.让我们先来看看标准输出代码: //服务器存档模式 $pdf->Output('output.p ...
- TCP客户端图片上传服务端保存本地示例
//TCP客户端public class TCPClient { public static void main(String[] args)throws IOException { Socket s ...
- java基于socket的网络通信,实现一个服务端多个客户端的群聊,传输文件功能,界面使用Swing
最近在复习java的io流及网络编程.但复习写那些样板程序总是乏味的.便准备写个项目来巩固.想来想去还是聊天项目比较好玩.如果日后完成的比较好自己也可以用(哈哈哈).并且自己后面也要继续巩固java多 ...
- android-HttpClient上传信息(包括图片)到服务端
需要下载apache公司下的HttpComponents项目下的HTTPCLIENT ----------地址为http://hc.apache.org/downloads.cgi 主要是用到了htt ...
- 微信小程序开发之多图片上传+服务端接收
前言: 业务需求,这次需要做一个小程序同时选中三张图片一起上传到服务端,后端使用的.NET WEBAPI接收数据保存. 使用技术: 在这章中将会使用到微信小程序wx.uploadFile(Object ...
- java 网络编程基础 TCP/IP协议:服务端ServerSocket;客户端Socket; 采用多线程方式处理网络请求
1.Java中客户端和服务器端通信的简单实例 Java中能接收其他通信实体连接请求的类是ServerSocket,ServerSocket对象用于监听来自客户端的Socket连接,如果没有连接,它将一 ...
- JAVA学习第六十三课 — 关于client服务端 && URL类 & URLConnection
常见的client和服务端 client: 浏览器:IE:弹窗体,猎豹:弹窗体.多标签,争强效果 服务端: server:TomCat:1.处理请求 2.给予应答 想让TomC ...
随机推荐
- hexo+github+Theme Art Design文章发布
新建 hexo new "YYYY-MM-DD-title" 为了更好的标识文章和防止重复,文章对应的markdown文件的命名应该遵循:YYYY-MM-DD-title 格式. ...
- HDU-3605-Escape(最大流, 状态压缩)
链接: https://vjudge.net/problem/HDU-3605 题意: 2012 If this is the end of the world how to do? I do not ...
- GO语言学习笔记5-defer的使用
1. 什么是defer defer是Go语言提供的一种用于注册延迟调用的机制:让函数或语句可以在当前函数执行完毕后(包括通过return正常结束或者panic导致的异常结束)执行. 2. defer的 ...
- (57)Linux驱动开发之三Linux字符设备驱动
1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...
- centos网卡配置NM_CONTROLLED=”yes” 慎用
今天有1台服务器修改了 /etc/sysconfig/network-scripts/ifcfg-eth0 配置文件中的一个参数: NM_CONTROLLED=“yes” 修改成 NM_CONTROL ...
- [LeetCode]-algorithms-Median of Two Sorted Arrays
There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two ...
- python正则之特殊表达式 .*?{}
. 能匹配所有字符--单个字符,除了\n >>> re.match(r".","1") <_sre.SRE_Match object a ...
- install_github无法安装 Rwebdriver包的解决方法
1.通过install_githtb安装Rwebdriver包的错误如下: 提示不能打开URL,但是将URL地址输入浏览器地址栏,则可以下载包到本地 2.在网上搜索,发现可以通过本地文件来安装(ins ...
- ActiveMQ从入门到精通(二)
接上一篇<ActiveMQ从入门到精通(一)>,本篇主要讨论的话题是:消息的顺序消费.JMS Selectors.消息的同步/异步接受方式.Message.P2P/PubSub.持久化订阅 ...
- leetcode 234 回文链表 Palindrome Linked List
要求用O(n)时间,和O(1)空间,因此思路是用本身链表进行判断,既然考虑回文,本方法思想是先遍历一次求链表长度,然后翻转前半部分链表:然后同时对前半部分链表和后半部分链表遍历,来判断对应节点的值是否 ...