由于最近项目需要在java后台生成echarts图片,花时间研究了下这个,顺便分享下;
1.首先需要先下载echarts本地服务器;
可以去官网下载也可以直接去我的网盘下载 ,也可以去这个官网下载最新的 https://www.jianshu.com/p/dfc28fd7d786
(1)网盘:链接:https://pan.baidu.com/s/1kTZ9JWsU48PTTG809HurRA 提取码:b69t
(2)获取后放入本地解压到例如D:/TEST下
D:\TEST\phantomjs-2.1.1-windows\bin\phantomjs.exe D:\TEST\saintlee-echartsconvert-master\echartsconvert\echarts-convert.js -s -p 6666
解压之后可以使用cmd命令启动这个服务,输入以上命令出现 echarts-convert server start success. [pid]=10500 提示即启动成功;
2.此服务启动成功后就是代码了
以下是springboot项目整体结构了采用了Maven导包方式,需要utils下和pom文件需要导入相应的包
(1)导入pom.xml包
<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> <!-- 阿里JSON解析器 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.68</version> </dependency>
<!-- pool 对象池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
(2)3个工具类分别如下,根据需求可自行修改逻辑
package com.lxp.demo.utils;/** * @projectName: ruoyi * @packageName: com.rmis.common.utils.chart * @className: HttpUtil * @description: ${description} * @author: hrs * @date: 2020-07-16 15:25 */ 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; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; 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 (Map.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; } }
package com.lxp.demo.utils;/** * @projectName: ruoyi * @packageName: com.rmis.common.utils.chart * @className: FreemarkerUtil * @description: ${description} * @author: hrs * @date: 2020-07-16 15:26 */ import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import java.io.IOException; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.Map; /** * @author msh * @date2020/7/16 */ 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.setClassForTemplateLoading(FreemarkerUtil.class,templateDirectory); // 生成模板对象 Template template = configuration.getTemplate(templateFileName); // 将datas写入模板并返回 try (StringWriter stringWriter = new StringWriter()) { template.process(datas, stringWriter); stringWriter.flush(); return stringWriter.getBuffer().toString(); } } }
package com.lxp.demo.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import freemarker.template.TemplateException; import org.apache.http.client.ClientProtocolException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sun.misc.BASE64Decoder; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author msh * @date2020/7/16 */ public class EchartsUtil { /** * 临时文件夹路径 */ public static final String TEMP_FILE_PATH = "D:/tempFile/"; private static final String SUCCESS_CODE = "1"; private static final Logger logger = LoggerFactory.getLogger(EchartsUtil.class); 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("http://localhost:6666", 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; } public static void getImage(Map<String, Object> datas) throws IOException { // 生成option字符串 String option = null; try { if (!datas.containsKey("ftl")){ logger.error("没有指定生成图表的模板!"); } option = FreemarkerUtil.generateString((String) datas.get("ftl"), "/template", datas); } catch (TemplateException e) { logger.error(e.getMessage()); } // 根据option参数 String base64 = generateEchartsBase64(option); File file = new File(TEMP_FILE_PATH); if(!file.exists()) { // 如果不存在就创建文件 file.mkdir(); } BASE64Decoder decoder = new BASE64Decoder(); try (OutputStream out = new FileOutputStream(TEMP_FILE_PATH+"test.jpg")){ // 解密 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图模板 option.ftl 如下:
{ title: { text: '功率调节计算' }, tooltip: { trigger: 'axis' }, legend: { data: ['AO', 'AO*'] }, xAxis: { type: 'category', boundaryGap: false, data: ${aohour} }, yAxis: { type: 'value' }, series: [ { name: 'AO', type: 'line', stack: '总量', data: ${aoList}, smooth : true }, { name: 'AO*', type: 'line', stack: '总量', data: ${aoxList}, smooth : true }, ] }
(3)最后一部是执行EchartUtils的测试方法
public static void main(String[] args) { //制造数据 List<String> aoxList = new ArrayList<>(); aoxList.add("2"); aoxList.add("4"); aoxList.add("7");aoxList.add("9"); aoxList.add("10"); aoxList.add("9"); aoxList.add("8"); aoxList.add("8"); aoxList.add("7"); List<String> aoList = new ArrayList<>(); aoList.add("1"); aoList.add("4"); aoList.add("7");aoList.add("9"); aoList.add("10"); aoList.add("10"); aoList.add("10"); aoList.add("10"); aoList.add("10"); List<String> aohour = new ArrayList<>(); aohour.add("1");aohour.add("2");aohour.add("3");aohour.add("4");aohour.add("5");aohour.add("6");aohour.add("7"); aohour.add("8");aohour.add("9"); // 模板参数 HashMap<String, Object> datas = new HashMap<>(); //aohour、aoList、aoxList对应模板/template/option.ftl中的x和y轴的名字,模板可自行修改, //ftl 为设置模板的名字。路径在/templates下 datas.put("aoxList", JSON.toJSONString(aoxList)); datas.put("aoList", JSON.toJSONString(aoList)); datas.put("aohour", JSON.toJSONString(aohour)); datas.put("ftl", "option.ftl"); try { EchartsUtil.getImage(datas); } catch (IOException e) { e.printStackTrace(); } }
执行后在代码设置的路径下会生成这样的图片及完成功能,后续会继续如何将图片以及文字替换掉word模板文档中的字和图片