当前位置:   article > 正文

Java 用 PhantomJS+ECharts 在linux环境生成图片,然后发送带图片的邮件_phantom echarts linux执行命令

phantom echarts linux执行命令

第一步:下载并安装PhantomJS

下载地址:Download PhantomJS

下载完成后解压

tar -xjvf phantomjs-2.1.1-linux-x86_64.tar.bz2

将可执行文件放入系统路径,并进行连接(必须是全路径)

sudo ln -s home/software/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/bin/phantomjs

授权

chmod 777 phantomjs

测试Phantomjs

第二步:准备生成图片相关的脚本

1. echarts.min.js
下载地址:https://echarts.baidu.com/download.html

下载最新的 release 版本,解压出来的文件夹里的 dist 目录里可以找到最新版本的 echarts 库。

2. jquery-3.2.1.min.js
我用了3.2.1这个版本,具体版本没有限制。

3. echarts-convert.js

  1. (function () {
  2. var system = require('system');
  3. var fs = require('fs');
  4. var config = {
  5. // define the location of js files
  6. JQUERY: 'jquery-3.2.1.min.js',
  7. //ESL: 'esl.js',
  8. ECHARTS: 'echarts.min.js',
  9. // default container width and height
  10. DEFAULT_WIDTH: '600',
  11. DEFAULT_HEIGHT: '700'
  12. }, parseParams, render, pick, usage;
  13. usage = function () {
  14. console.log("\nUsage: phantomjs echarts-convert.js -options options -outfile filename -width width -height height"
  15. + "OR"
  16. + "Usage: phantomjs echarts-convert.js -infile URL -outfile filename -width width -height height\n");
  17. };
  18. pick = function () {
  19. var args = arguments, i, arg, length = args.length;
  20. for (i = 0; i < length; i += 1) {
  21. arg = args[i];
  22. if (arg !== undefined && arg !== null && arg !== 'null' && arg != '0') {
  23. return arg;
  24. }
  25. }
  26. };
  27. parseParams = function () {
  28. var map = {}, i, key;
  29. if (system.args.length < 2) {
  30. usage();
  31. phantom.exit();
  32. }
  33. for (i = 0; i < system.args.length; i += 1) {
  34. if (system.args[i].charAt(0) === '-') {
  35. key = system.args[i].substr(1, i.length);
  36. if (key === 'infile') {
  37. // get string from file
  38. // force translate the key from infile to options.
  39. key = 'options';
  40. try {
  41. map[key] = fs.read(system.args[i + 1]).replace(/^\s+/, '');
  42. } catch (e) {
  43. console.log('Error: cannot find file, ' + system.args[i + 1]);
  44. phantom.exit();
  45. }
  46. } else {
  47. map[key] = system.args[i + 1].replace(/^\s+/, '');
  48. }
  49. }
  50. }
  51. return map;
  52. };
  53. render = function (params) {
  54. var page = require('webpage').create(), createChart;
  55. var bodyMale = config.SVG_MALE;
  56. page.onConsoleMessage = function (msg) {
  57. console.log(msg);
  58. };
  59. page.onAlert = function (msg) {
  60. console.log(msg);
  61. };
  62. createChart = function (inputOption, width, height,config) {
  63. var counter = 0;
  64. function decrementImgCounter() {
  65. counter -= 1;
  66. if (counter < 1) {
  67. console.log(messages.imagesLoaded);
  68. }
  69. }
  70. function loadScript(varStr, codeStr) {
  71. var script = $('<script>').attr('type', 'text/javascript');
  72. script.html('var ' + varStr + ' = ' + codeStr);
  73. document.getElementsByTagName("head")[0].appendChild(script[0]);
  74. if (window[varStr] !== undefined) {
  75. console.log('Echarts.' + varStr + ' has been parsed');
  76. }
  77. }
  78. function loadImages() {
  79. var images = $('image'), i, img;
  80. if (images.length > 0) {
  81. counter = images.length;
  82. for (i = 0; i < images.length; i += 1) {
  83. img = new Image();
  84. img.onload = img.onerror = decrementImgCounter;
  85. img.src = images[i].getAttribute('href');
  86. }
  87. } else {
  88. console.log('The images have been loaded');
  89. }
  90. }
  91. // load opitons
  92. if (inputOption != 'undefined') {
  93. // parse the options
  94. loadScript('options', inputOption);
  95. // disable the animation
  96. options.animation = false;
  97. }
  98. // we render the image, so we need set background to white.
  99. $(document.body).css('backgroundColor', 'white');
  100. var container = $("<div>").appendTo(document.body);
  101. container.attr('id', 'container');
  102. container.css({
  103. width: width,
  104. height: height
  105. });
  106. // render the chart
  107. var myChart = echarts.init(container[0]);
  108. myChart.setOption(options);
  109. // load images
  110. loadImages();
  111. return myChart.getDataURL();
  112. };
  113. // parse the params
  114. page.open("about:blank", function (status) {
  115. // inject the dependency js
  116. page.injectJs(config.ESL);
  117. page.injectJs(config.JQUERY);
  118. page.injectJs(config.ECHARTS);
  119. var width = pick(params.width, config.DEFAULT_WIDTH);
  120. var height = pick(params.height, config.DEFAULT_HEIGHT);
  121. // create the chart
  122. var base64 = page.evaluate(createChart, params.options, width, height,config);
  123. fs.write("base64.txt",base64);
  124. // define the clip-rectangle
  125. page.clipRect = {
  126. top: 0,
  127. left: 0,
  128. width: width,
  129. height: height
  130. };
  131. // render the image
  132. page.render(params.outfile);
  133. console.log('render complete:' + params.outfile);
  134. // exit
  135. phantom.exit();
  136. });
  137. };
  138. // get the args
  139. var params = parseParams();
  140. // validate the params
  141. if (params.options === undefined || params.options.length === 0) {
  142. console.log("ERROR: No options or infile found.");
  143. usage();
  144. phantom.exit();
  145. }
  146. // set the default out file
  147. if (params.outfile === undefined) {
  148. var tmpDir = fs.workingDirectory + '/tmp';
  149. // exists tmpDir and is it writable?
  150. if (!fs.exists(tmpDir)) {
  151. try {
  152. fs.makeDirectory(tmpDir);
  153. } catch (e) {
  154. console.log('ERROR: Cannot make tmp directory');
  155. }
  156. }
  157. params.outfile = tmpDir + "/" + new Date().getTime() + ".png";
  158. }
  159. // render the image
  160. render(params);
  161. }());

注意:三个脚本放一起

第三步:后端代码编写

1.安装EChart 依赖

  1. <dependency>
  2. <groupId>com.github.abel533</groupId>
  3. <artifactId>ECharts</artifactId>
  4. <version>2.2.7</version>
  5. </dependency>

2.用echarts提供的sdk拼接生成options,并保存json文件到服务器,然后使用Java传cmd命令调用 PhantomJS + EchartsConvert 命令读取json,生成 echarts 图片

  1. private InputStream createChart() {
  2. //choList 为List<choList>
  3. //生成饼图图片
  4. InputStream pieInputStream = this.createChart(choList,"pie");
  5. //生成柱状图
  6. InputStream histogramInputStream = this.createChart(choList,"histogram");
  7. // 发邮件
  8. String title = "测试邮件" + DateUtils.getDate();
  9. String from= "ceshifajianren@163.com";
  10. String user= "ceshifajianren@163.com";
  11. String emailPassword= "******";
  12. String fromCNname = "测试管理系统";
  13. String content = "测试邮件!"
  14. String[] addrs = {"ceshi@163.com"};
  15. try {
  16. SendMail.sendMailImage(from, fromCNname, user, emailPassword, content, title, addrs, "", pieInputStream, histogramInputStream);
  17. } catch (Exception e) {
  18. log.error("发送邮件失败--->" + e.getMessage());
  19. }
  20. }
  1. //生成图片
  2. private InputStream createChart(List<choList> choList,String fileType) {
  3. String phantomjs = "/home/phantomjs/phantomjs/bin/phantomjs";
  4. String JSpath = "/home/phantomjs/echartsconvert/convert.js";
  5. String path = "/home/echartspath/";
  6. String dateTime = DateUtils.dateTime();
  7. String jsonfile = dateTime + fileType + ".json";
  8. String imagefile = dateTime + fileType + ".png";
  9. String option = "";
  10. InputStream fileInputStream = null;
  11. try {
  12. //生成option
  13. if("pie".equals(fileType)) {
  14. option = createPieChartOption(choList);
  15. }else {
  16. option = createHistogramOption(choList);
  17. }
  18. FtpUtil ftpshell = new FtpUtil("121.1.1.1",22,"ccc","ccc***");
  19. // option上传
  20. ftpshell.connect();
  21. ftpshell.writeContent(option, echartsPath, jsonfile);
  22. System.out.println("创建option");
  23. // 生成图片
  24. ftpshell.sshconnect();
  25. String cmd = phantomjsPath + " " + echartsconvertPath + " -infile " + echartsPath + jsonfile + " -outfile " + echartsPath + imagefile;
  26. System.out.println(cmd);
  27. ftpshell.execShell(cmd);
  28. //读取图片
  29. fileInputStream = ftpshell.getsftp(echartsPath + imagefile);
  30. ftpshell.disConnect();
  31. } catch (Exception e) {
  32. log.error("生成图片,读取图片失败--->" + e.getMessage());
  33. }
  34. return fileInputStream;
  35. }
  1. //生成饼图
  2. private String createPieChartOption(List<choList> choList) {
  3. List<Map<String, Object>> list = new ArrayList<>();
  4. for (choListch : choList) {
  5. Map<String, Object> map = new HashMap<>();
  6. map.put("name", ch.getProcorr());
  7. map.put("value", ch.getStatis());
  8. list.add(map);
  9. }
  10. //创建Option
  11. Option option = new GsonOption();
  12. option.title(new Title().text("占比").x("middle"));
  13. option.tooltip(Trigger.item);
  14. option.legend(new Legend().orient(Orient.vertical).left("left"));
  15. //饼图数据
  16. Pie pie = new Pie("占比");
  17. //循环数据
  18. for (Map<String, Object> objectMap : list) {
  19. //饼图数据
  20. pie.data(new PieData(objectMap.get("name").toString() + " " + objectMap.get("value"), objectMap.get("value")));
  21. }
  22. //设置数据
  23. option.series(pie);
  24. String optionStr = option.toString().replace(" ", "");
  25. return optionStr;
  26. }
  1. //生成柱状图
  2. private String createHistogramOption(List<choList> choList) {
  3. String[] colors = { "#546fc6", "#91cb74",
  4. "#fac859", "#ee6666", "#73c0de",
  5. "#3ba372", "#fb8351", "#9a60b4"};
  6. List<Map<String, Object>> list = new ArrayList<>();
  7. for (choListch : choList) {
  8. Map<String, Object> map = new HashMap<>();
  9. map.put("name", ch.getProcorr()); //人名
  10. map.put("value", ch.getStatis()); //数量
  11. map.put("itemStyle",
  12. new ItemStyle().normal(new Normal().color(colors[new Random().nextInt(8)])));
  13. list.add(map);
  14. }
  15. //创建Option
  16. Option option = new GsonOption();
  17. option.title(new Title().text("统计").x("middle"));
  18. option.tooltip(Trigger.item);
  19. option.legend(new Legend().orient(Orient.vertical).left("left"));//设置布局方式
  20. //设置x轴数据
  21. CategoryAxis categoryAxis = new CategoryAxis();
  22. for (Changeorder ch : choList) {
  23. categoryAxis.data(ch.getProcorr());
  24. }
  25. option.xAxis(categoryAxis);
  26. //设置y轴 这里不给指定数据 自动调整
  27. ValueAxis valueAxis = new ValueAxis();
  28. option.yAxis(valueAxis);
  29. //填充柱状图数据
  30. Bar bar = new Bar("统计");
  31. //循环数据
  32. for (Map<String, Object> objectMap : list) {
  33. bar.data(objectMap);
  34. }
  35. //设置顶端显示数值
  36. bar.setLabel(new ItemStyle().normal(new Normal().show(true).position(Position.top)));
  37. //设置数据
  38. option.series(bar);
  39. String optionStr = option.toString().replace(" ", "");
  40. return optionStr;
  41. }

 3. 发送邮件

  1. public static boolean sendMailImage(String from, String fromCNname,String user, String password, String text, String title, String[] addrs, String recipient, InputStream pieImageInputStream, InputStream histogramImageInputStream) throws Exception {
  2. // 1.创建参数配置, 用于连接邮件服务器的参数配置
  3. Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
  4. final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
  5. Properties props = System.getProperties();
  6. props.setProperty("mail.smtp.host", mailHost);
  7. props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
  8. props.setProperty("mail.smtp.socketFactory.fallback", "false");
  9. props.setProperty("mail.smtp.port", "465");
  10. props.setProperty("mail.smtp.socketFactory.port", "465");
  11. props.put("mail.smtp.auth", "true");
  12. // 2. 根据配置创建会话对象, 用于和邮件服务器交互,不要用defaultInstance!!!!!!
  13. Session session = Session.getInstance(props, new Authenticator() {
  14. @Override
  15. protected PasswordAuthentication getPasswordAuthentication() {
  16. return new PasswordAuthentication(user, password);
  17. }
  18. });
  19. session.setDebug(true); // 设置为debug模式, 可以查看详细的发送 log
  20. // -- Create a new message -- 1. 创建一封邮件
  21. Message msg = new MimeMessage(session);
  22. // -- Set the FROM and TO fields --
  23. String nick = javax.mail.internet.MimeUtility.encodeText(fromCNname); //设置发件人中文名称 ***<213321@163.com>
  24. msg.setFrom(new InternetAddress(nick+" <"+from+">"));
  25. // msg.setFrom(new InternetAddress(from));
  26. InternetAddress[] toAddrs = new InternetAddress[addrs.length];
  27. if (StringUtils.isNotBlank(recipient)) {
  28. InternetAddress reciAddr = new InternetAddress(recipient); //抄送
  29. msg.setRecipient(Message.RecipientType.CC, reciAddr);
  30. }
  31. for (int i = 0; i < toAddrs.length; i++) {
  32. toAddrs[i] = new InternetAddress(addrs[i]);
  33. }
  34. msg.setRecipients(Message.RecipientType.TO, toAddrs);
  35. msg.setSubject(title);
  36. //创建富文本对象
  37. BodyPart mdp = new MimeBodyPart();//新建一个存放信件内容的BodyPart对象
  38. mdp.setContent(text, "text/html;charset=utf-8");//给BodyPart对象设置内容和格式/编码方式
  39. MimeMultipart mm = new MimeMultipart();//新建一个多功能邮件块对象用来存放BodyPart对象
  40. mm.addBodyPart(mdp);//将BodyPart加入到MimeMultipart对象中(可以加入多个BodyPart)
  41. mm.addBodyPart(createImageMimeBodyPart(pieImage)); //将图片插入MimeMultipart对象中
  42. mm.addBodyPart(createImageMimeBodyPart(histogramImage)); //将图片插入MimeMultipart对象中
  43. /**
  44. * mixed:混合关系,一般正文和附件组合使用mixed,如果不设置,javamail默认会使用mixed
  45. * related:关联关系,一般html引用了图片这类内嵌资源,正文和图片组合使用related
  46. * alternative:同时存在纯文本与超文本,使用boundary分割
  47. */
  48. mm.setSubType("related");
  49. //将封装好的数据保存到Message中
  50. msg.setContent(mm);
  51. msg.setSentDate(new Date());
  52. // Transport.send(msg);
  53. System.out.println("Message sent.");
  54. return true;
  55. }
  56. // 封装图片MimeBodyPart
  57. private static MimeBodyPart createImageMimeBodyPart(InputStream imageInputStream) throws Exception {
  58. MimeBodyPart image = new MimeBodyPart();
  59. image.setDataHandler(new DataHandler(new ByteArrayDataSource(imageInputStream, "application/octet-stream"))); //javamail jaf
  60. image.setContentID(IdUtils.fastSimpleUUID());//设置对应资源文件的唯一标识符,即MIME协议对于邮件得结构组织格式中得content-id头字段
  61. return image;
  62. }

(使用-options不能生成图片,只能使用-infile,指定json文件全目录,原因未知) 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/715651
推荐阅读
相关标签
  

闽ICP备14008679号