https://www.jianshu.com/p/41d5e08af0a7
https://www.cnblogs.com/bangejingting/p/6907628.html
有时候我们需要定时的生成一些报表图片,或者通过钉钉等发送给对应用户或群组;
第一步,本地生成报表,可以用baiduEchart等
第二部,自动渲染图片,进行截图
springMvc.xml添加: <bean id="beetlConfig" class="org.beetl.ext.spring.BeetlGroupUtilConfiguration" init-method="init"> <property name="configFileResource" value="classpath:beetl.properties" /> </bean> <bean id="beelViewResolver" class="org.beetl.ext.spring.BeetlSpringViewResolver"> <property name="suffix" value=".html" /> <property name="contentType" value="text/html;charset=UTF-8" /> <property name="order" value="0"/> <property name="config" ref="beetlConfig"/> <property name="cache" value="true"/> <property name="allowSessionOverride" value="true" /> <property name="allowRequestOverride" value="true" /> </bean> maven依赖: <!-- 在线生成图片导出 --> <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>com.dingtalk.chatbot</groupId> <artifactId>dingtalk-chatbot-sdk</artifactId> <version>0.9.0-SNAPSHOT</version> </dependency>
try { //渲染模版,生成HTML代码 Template template = groupTemplate.getTemplate(templateFile); template.binding("data", data); template.binding("title", title); template.binding("subTitle", subTitle); String html = template.render(); return html; } catch (Exception e) { log.warn("convertDataToGraph error", e); }
//写入到文件 private String convertHtmlToImage(String html, EnvType env) throws IOException { //写入到文件 String[] commands = null; writeToFile(html, API_RANK_RELEASE_HTML); commands = new String[]{"bash", "-c", phantomPath + " " + reportPath + CAPTURE_RELEASE_JS}; //生成图片 int status = 1; Process process = Runtime.getRuntime().exec(commands, null, new File(reportPath)); status = process.waitFor(); //执行名称出错,直接抛出异常 if (status != 0) { log.error("failed to generate the image status code:{}", status); throw new RuntimeException("failed to generate the image status code: " + status); } return imageTempPath; }
private void writeToFile(String html, String tempHtmlName) throws IOException { BufferedWriter writer = null; String fileName = reportPath + tempHtmlName; try { File oldFile = new File(fileName); if (oldFile.exists()) { oldFile.delete(); } writer = new BufferedWriter(new FileWriter(fileName)); writer.write(html); } finally { if (writer != null) { writer.close(); } } }
beetl.properties #\u914D\u7F6E\u5F15\u64CE\u5B9E\u73B0\u7C7B ENGINE=org.beetl.core.engine.FastRuntimeEngine #\u6307\u5B9A\u4E86\u5360\u4F4D\u7B26\u53F7\uFF0C\u9ED8\u8BA4\u662F${ }.\u4E5F\u53EF\u4EE5\u6307\u5B9A\u4E3A\u5176\u4ED6\u5360\u4F4D\u7B26 DELIMITER_PLACEHOLDER_START=${ DELIMITER_PLACEHOLDER_END=} #\u6307\u5B9A\u4E86\u8BED\u53E5\u7684\u5B9A\u754C\u7B26\u53F7\uFF0C\u9ED8\u8BA4\u662F<% %>,\u4E5F\u53EF\u4EE5\u6307\u5B9A\u4E3A\u5176\u4ED6\u5B9A\u754C\u7B26\u53F7 #DELIMITER_STATEMENT_START=@ #DELIMITER_STATEMENT_END=null #\u6307\u5B9AIO\u8F93\u51FA\u6A21\u5F0F\uFF0C\u9ED8\u8BA4\u662FFALSE,\u5373\u901A\u5E38\u7684\u5B57\u7B26\u8F93\u51FA\uFF0C\u518D\u8003\u8651\u9AD8\u6027\u80FD\u60C5\u51B5\u4E0B\uFF0C\u53EF\u4EE5\u8BBE\u7F6E\u6210true DIRECT_BYTE_OUTPUT = true #\u6307\u5B9A\u4E86\u652F\u6301HTML\u6807\u7B7E\uFF0C\u4E14\u7B26\u53F7\u4E3A#\uFF08\u53EA\u80FD\u7528\u4E00\u4E2A\u7B26\u53F7\u6807\u793A\uFF09\uFF0C\u9ED8\u8BA4\u914D\u7F6E\u4E0B\uFF0C\u6A21\u677F\u5F15\u64CE\u8BC6\u522B<#tag ></#tag> #\u8FD9\u6837\u7684\u7C7B\u4F3Chtml\u6807\u7B7E\uFF0C\u5E76\u80FD\u8C03\u7528\u76F8\u5E94\u7684\u6807\u7B7E\u51FD\u6570\u3002 HTML_TAG_SUPPORT = true HTML_TAG_FLAG = # #\u6307\u5B9A\u5141\u8BB8\u672C\u5730Class\u76F4\u63A5\u8C03\u7528 NATIVE_CALL = TRUE #\u6307\u5B9A\u6A21\u677F\u5B57\u7B26\u96C6\u662FUTF-8 TEMPLATE_CHARSET = UTF-8 #\u6307\u5B9A\u5F02\u5E38\u7684\u89E3\u6790\u7C7B\uFF0C\u9ED8\u8BA4\u662FConsoleErrorHandler\uFF0C\u4ED6\u5C06\u5728render\u53D1\u751F\u5F02\u5E38\u7684\u65F6\u5019\u5728\u540E\u53F0\u6253\u5370\u51FA\u9519\u8BEF\u4FE1\u606F(System.out)\u3002 ERROR_HANDLER = org.beetl.core.ConsoleErrorHandler #\u6307\u5B9A\u4E86\u672C\u5730Class\u8C03\u7528\u7684\u5B89\u5168\u7B56\u7565 NATIVE_SECUARTY_MANAGER= org.beetl.core.DefaultNativeSecurityManager #\u6307\u5B9A\u4E86\u9ED8\u8BA4\u4F7F\u7528\u7684\u6A21\u677F\u8D44\u6E90\u52A0\u8F7D\u5668 RESOURCE_LOADER=org.beetl.core.resource.ClasspathResourceLoader #\u914D\u7F6E\u4E86\u662F\u5426\u8FDB\u884C\u4E25\u683CMVC\uFF0C\u901A\u5E38\u60C5\u51B5\u4E0B\uFF0C\u6B64\u5904\u8BBE\u7F6E\u4E3Afalse. MVC_STRICT = FALSE #\u8D44\u6E90\u914D\u7F6E\uFF0Cresource\u540E\u7684\u5C5E\u6027\u53EA\u9650\u4E8E\u7279\u5B9AResourceLoader #classpath \u6839\u8DEF\u5F84(\u5176\u5B9E\u5C31\u662F\u524D\u7F00\u7684\u914D\u7F6E) RESOURCE.root= /report/ #\u662F\u5426\u68C0\u6D4B\u6587\u4EF6\u53D8\u5316 RESOURCE.autoCheck=true #\u81EA\u5B9A\u4E49\u811A\u672C\u65B9\u6CD5\u6587\u4EF6\u7684Root\u76EE\u5F55\u548C\u540E\u7F00 #RESOURCE.functionRoot = functions #RESOURCE.functionSuffix = fn #\u81EA\u5B9A\u4E49\u6807\u7B7E\u6587\u4EF6Root\u76EE\u5F55\u548C\u540E\u7F00 #RESOURCE.tagRoot = htmltag #RESOURCE.tagSuffix = tag ##### \u6269\u5C55 ############## ## \u5185\u7F6E\u7684\u65B9\u6CD5 #FN.date = org.beetl.ext.fn.DateFunction #FN.nvl = org.beetl.ext.fn.NVLFunction #FN.debug = org.beetl.ext.fn.DebugFunction #FN.exist = org.beetl.ext.fn.CheckExistFunction #FN.printf = org.beetl.ext.fn.Printf #FN.decode = org.beetl.ext.fn.DecodeFunction #FN.assert = org.beetl.ext.fn.AssertFunction #FN.print = org.beetl.ext.fn.Print #FN.println = org.beetl.ext.fn.Println #FN.trunc = org.beetl.ext.fn.TruncFunction #FN.trim = org.beetl.ext.fn.TruncFunction2 #FN.empty = org.beetl.ext.fn.EmptyFunction #FN.qmark = org.beetl.ext.fn.QuestionMark #FN.isEmpty = org.beetl.ext.fn.EmptyExpressionFunction #FN.parseInt = org.beetl.ext.fn.ParseInt #FN.parseDouble= org.beetl.ext.fn.ParseDouble #FN.range = org.beetl.ext.fn.Range ##\u5185\u7F6E\u7684\u529F\u80FD\u5305 #FNP.strutil = org.beetl.ext.fn.StringUtil #FNP.array = org.beetl.ext.fn.ArrayUtil ##\u5185\u7F6E\u7684\u683C\u5F0F\u5316\u51FD\u6570 #FT.dateFormat = org.beetl.ext.format.DateFormat #FT.numberFormat = org.beetl.ext.format.NumberFormat ##\u5185\u7F6E\u7684\u9ED8\u8BA4\u683C\u5F0F\u5316\u51FD\u6570 #FTC.java.util.Date = org.beetl.ext.format.DateFormat #FTC.java.sql.Date = org.beetl.ext.format.DateFormat #FTC.java.sql.Time = org.beetl.ext.format.DateFormat #FTC.java.sql.Timestamp = org.beetl.ext.format.DateFormat #FTC.java.lang.Short = org.beetl.ext.format.NumberFormat #FTC.java.lang.Long = org.beetl.ext.format.NumberFormat #FTC.java.lang.Integer = org.beetl.ext.format.NumberFormat #FTC.java.lang.Float = org.beetl.ext.format.NumberFormat #FTC.java.lang.Double = org.beetl.ext.format.NumberFormat #FTC.java.math.BigInteger = org.beetl.ext.format.NumberFormat #FTC.java.math.BigDecimal = org.beetl.ext.format.NumberFormat #FTC.java.util.concurrent.atomic.AtomicLong = org.beetl.ext.format.NumberFormat #FTC.java.util.concurrent.atomic.AtomicInteger = org.beetl.ext.format.NumberFormat ## \u6807\u7B7E\u7C7B #TAG.include= org.beetl.ext.tag.IncludeTag #TAG.includeFileTemplate= org.beetl.ext.tag.IncludeTag #TAG.layout= org.beetl.ext.tag.LayoutTag #TAG.delete= org.beetl.ext.tag.DeleteTag #TAG.htmltag= org.beetl.ext.tag.HTMLTagSupportWrapper #WEBAPP_EXT = com.ximalaya.southgate.admin.beetl.GlobalExt
captureRelease.js var page = require('webpage').create(); page.viewportSize = { width: 1920, height: 1080, orientation: 'landscape' }; page.open('apiRankRelease.html', function() { window.setTimeout(function () { page.render('apiRankRelease.png'); page.close(); phantom.exit(); }, 3000); });
reportPieRelease.html <!DOCTYPE html> <html style="height: 100%"> <head> <meta charset="utf-8"> <style> @font-face { font-family: "PingF"; src: url("font/PingFang-SC-Bold.ttf"),url("font/PingFang-SC-Light.ttf"),url("font/PingFang-SC-Regular.ttf"); } body { font-family: "PingF"; } </style> </head> <body style="height: 100%; margin: 0"> <div id="container" style=" width: 1920px;height: 1080px"></div> <div id="text"> push </div> <!--<script type="text/javascript" src="../lib/echarts/4/echarts.min.js"></script>--> <script src="http://echarts.baidu.com/dist/echarts.min.js"></script> <script type="text/javascript"> setTimeout(function () { var text = document.getElementById("text"); text.style.display="none"; var dom = document.getElementById("container"); var myChart = echarts.init(dom); var data = genData(20); option = { title : { text: '${title}', subtext: '${subTitle}', x:'center', textStyle:{ fontFamily: "PingF", fontSize:25 }, subtextStyle:{ fontFamily: "PingF", fontSize:23 } }, tooltip : { trigger: 'item', formatter: "{a} <br/>{b} : {c} ({d}%)", textStyle: { fontFamily: "PingF", fontSize: 20 } }, legend: { type: 'scroll', orient: 'vertical', right: 10, top: 80, bottom: 20, data: data.legendData, selected: data.selected, textStyle: { fontFamily: "PingF", fontSize: 23 } }, series : [ { name: '姓名', type: 'pie', radius : '35%', center: ['30%', '45%'], data: data.seriesData, itemStyle: { emphasis: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } }, label:{ //饼图图形上的文本标签 normal:{ show:true, textStyle : { fontFamily: "PingF", fontSize : 18 //文字的字体大小 } } } } ] }; function genData(count) { var legendData = []; var seriesData = []; var selected = {}; var i = 0; <%for(apiItem in data){%> name = '${apiItem.product}'; legendData.push(name); seriesData.push({ name: name, value: ${apiItem.amount} }); i++; selected[name] = i < 10; <%}%> return { legendData: legendData, seriesData: seriesData, selected: selected }; }; if (option && typeof option === "object") { myChart.setOption(option, true); } }, 1000); </script> </body> </html>