SpringBoot純後臺生成Echarts圖片(一)
在實際的生產應用中,我們常常需要將資料進行視覺化,生成一些圖文報表以供前端使用與檢視。而我們使用的最多的圖表生成外掛工具就是。為了生成相關的圖文報表,我們可以透過前端結合js等來生成,另外也可以使用純後臺(Java程式碼)來生成。這裡我們就介紹使用框架透過API傳遞引數的方式,純Java程式碼而不使用前端來生成相關的圖表。
本篇以生成柱狀圖為例:
一、專案的工程結構
二、專案依賴說明
(1)pom.xml依賴配置如下:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.9</version> </dependency> <!-- --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.59</version> </dependency> <!-- --> <dependency> <groupId>com.github.abel533</groupId> <artifactId>ECharts</artifactId> <version>3.0.0.6</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> <!-- 新增swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <!-- swagger2-UI --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
(2)application.properties屬性檔案配置
server.port=8095 img-url=image/ request-url= img-url-path=F:/echarts/ #HttpServletRequest 的屬性是否可以覆蓋 controller 中 model 的同名項 spring.freemarker.allow-request-override=false #HttpSession 的屬性是否可以覆蓋 controller 中 model 的同名項 spring.freemarker.allow-session-override=false #是否開啟快取 spring.freemarker.cache=false #模板檔案編碼 spring.freemarker.charset=UTF-8 #是否檢查模板位置 spring.freemarker.check-template-location=true #Content-Type 的值 spring.freemarker.content-type=text/html #是否將 HttpServletRequest 中的屬性新增到 Model 中 spring.freemarker.expose-request-attributes=false #是否將 HttpSession 中的屬性新增到 Model 中 spring.freemarker.expose-session-attributes=false #模板檔案字尾 spring.freemarker.suffix=.ftl #模板檔案位置 spring.freemarker.template-loader-path=classpath: /templates/
三、專案程式碼說明
(1)common模組-JsonResult.java
package com.lhf.springboot.common; /** * @ClassName: JsonResult * @Author: liuhefei * @Description: TODD * @Date: 2019/8/13 17:55 */ public class JsonResult<T> { private int status = 0; private T data; private String errMsg; public JsonResult(T data) { this.data = data; } public JsonResult(int status, String errMsg) { this.status = status; this.errMsg = errMsg; } public JsonResult(int status, T data, String errMsg) { this.status = status; this.data = data; this.errMsg = errMsg; } public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getErrMsg() { return errMsg; } public void setErrMsg(String errMsg) { this.errMsg = errMsg; } }
(2)config模組-SwaggerConfig.java
package com.lhf.springboot.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; /** * @ClassName: SwaggerConfig * @Author: liuhefei * @Description: TODD * @Date: 2019/5/29 19:26 */ @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.lhf.springboot")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder().title("Api介面介面") .description("api介面描述資訊") .contact(new Contact("liuhefei", "", "2510736432@qq.com")) .termsOfServiceUrl("") .version("1.0") .build(); } }
(3)echarts-pojo模組(資料模型)-BarData.java
package com.lhf.springboot.echarts.pojo; import lombok.Data; /** * @ClassName: BarData * @Author: liuhefei * @Description: TODD * @Date: 2019/8/15 16:08 */ public class BarData { private String title; //標題 private BarParam barParamList; private Boolean isHorizontal; //是否水平放置 //省略get/set方法 }
(4)echarts-pojo模組(資料模型)-BarParam.java
package com.lhf.springboot.echarts.pojo; /** * @ClassName: BarParam * @Author: liuhefei * @Description: TODD * @Date: 2019/8/15 16:11 */ public class BarParam { private Object[] barName; private Object[] barValue; private String legendName; //省略get/set方法 }
(5)echarts模組-EchartsConfig.java(介面)
package com.lhf.springboot.echarts; /** * @ClassName: EchartsConfig * @Author: liuhefei * @Description: TODD * @Date: 2019/8/22 18:16 */ public interface EchartsConfig { /** * 測試檔案生成的目錄 */ String EXPORT_PATH = ""; /** * 透過view控制所有測試是否開啟瀏覽器 */ Boolean VIEW = true; }
(6)echarts模組-EnhancedOption.java(實現類,對GsonOption.java做一層封裝)
package com.lhf.springboot.echarts; import com.github.abel533.echarts.json.GsonOption; import com.github.abel533.echarts.json.GsonUtil; import com.github.abel533.echarts.json.OptionUtil; /** * @ClassName: EnhancedOption * @Author: liuhefei * @Description: TODD * @Date: 2019/8/22 18:15 */ public class EnhancedOption extends GsonOption implements EchartsConfig { private String filepath; /** * 輸出到控制檯 */ public void print() { GsonUtil.print(this); } /** * 輸出到控制檯 */ public void printPretty() { GsonUtil.printPretty(this); } /** * 在瀏覽器中檢視 */ public void view() { if (!VIEW) { return; } if (this.filepath != null) { try { OptionUtil.browse(this.filepath); } catch (Exception e) { this.filepath = OptionUtil.browse(this); } } else { this.filepath = OptionUtil.browse(this); } } /** * 匯出到指定檔名 * * @param fileName * @return 返回html路徑 */ public String exportToHtml(String fileName) { return exportToHtml(EXPORT_PATH, fileName); } }
(7)echarts-option模組(組裝圖表option)-EchartBar.java(組裝柱狀圖option)(核心)
package com.lhf.springboot.echarts.option; import com.github.abel533.echarts.Legend; import com.github.abel533.echarts.axis.AxisLabel; import com.github.abel533.echarts.axis.AxisLine; import com.github.abel533.echarts.axis.CategoryAxis; import com.github.abel533.echarts.axis.ValueAxis; import com.github.abel533.echarts.code.Magic; import com.github.abel533.echarts.code.Position; import com.github.abel533.echarts.code.Tool; import com.github.abel533.echarts.feature.MagicType; import com.github.abel533.echarts.json.GsonOption; import com.github.abel533.echarts.series.Bar; import com.github.abel533.echarts.series.Series; import com.github.abel533.echarts.style.ItemStyle; import com.github.abel533.echarts.style.LineStyle; import com.github.abel533.echarts.style.TextStyle; import com.github.abel533.echarts.style.itemstyle.Normal; import com.lhf.springboot.echarts.EnhancedOption; import com.lhf.springboot.echarts.pojo.BarData; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * @ClassName: EchartBar * @Author: liuhefei * @Description: TODD * @Date: 2019/8/15 15:26 */ public class EchartBar { /** * 生成單柱狀圖 * @param //isHorizontal 是否水平放置 * @param //color 柱狀圖顏色,可以不設定,預設為紅色 * @param //title 柱狀圖示題 * @param //xdatas 橫軸資料 * @param //ydatas 縱軸資料 * @return */ public static GsonOption createBar(BarData barData){ /*String[] citis = { "廣州", "深圳", "珠海", "汕頭", "韶關", "佛山" }; int[] datas = { 6030, 7800, 5200, 3444, 2666, 5708 }; String title = "地市資料"; String[] colors = { "rgb(2,111,230)", "rgb(186,73,46)", "rgb(78,154,97)", "rgb(2,111,230)", "rgb(186,73,46)", "rgb(78,154,97)" };*/ String title = barData.getTitle(); boolean isHorizontal = barData.getHorizontal(); Object[] xdatas = barData.getBarParamList().getBarName(); Object[] ydatas = barData.getBarParamList().getBarValue(); String legendName = barData.getBarParamList().getLegendName(); Bar bar = new Bar(); //圖類別(柱狀圖) //title EnhancedOption option = new EnhancedOption(); option.title(title); //標題 option.title().textStyle().fontSize(15).color("red").fontWeight("bolder"); //工具欄 toolbox /*option.toolbox().show(true).feature(Tool.mark, //輔助線 Tool.dataView, //資料檢視 new MagicType(Magic.line, Magic.bar), //線圖,柱狀圖切換 Tool.restore, //還原 Tool.saveAsImage //儲存圖片 ); option.toolbox().show(true).feature();*/ //tooltip option.tooltip().show(true).formatter("{a}<br/>{b} : {c}"); //顯示工具提示,設定提示格式 //legend Legend legend = new Legend(); TextStyle textStyle = new TextStyle(); textStyle.color("red"); textStyle.fontSize(15); textStyle.fontWeight("bolder"); legend.setData(Collections.singletonList(legendName)); legend.setTextStyle(textStyle); option.setLegend(legend); //圖例 //axisLabel AxisLabel axisLabel = new AxisLabel(); TextStyle textStyle1 = new TextStyle(); textStyle1.fontSize(15); textStyle1.fontWeight("bolder"); axisLabel.show(true); axisLabel.textStyle(textStyle1); //axisLine AxisLine axisLine = new AxisLine(); LineStyle lineStyle = new LineStyle(); lineStyle.color("#315070"); lineStyle.width(4); axisLine.lineStyle(lineStyle); //xAxis CategoryAxis category = new CategoryAxis();// 軸分類 category.data(xdatas);// 軸資料類別 category.axisLabel(axisLabel); // x軸文字樣式 category.axisLine(axisLine); //x軸樣式 //yAxis ValueAxis valueAxis = new ValueAxis(); valueAxis.axisLabel().show(true).textStyle().fontSize(15).fontWeight("bolder"); //y軸文字樣式 valueAxis.axisLine().lineStyle().color("#315070").width(4); //y軸樣式 //series bar.name(legendName); Normal normal = new Normal(); normal.setShow(true); if(barData.getHorizontal() == false){ normal.position(Position.inside); }else { normal.position(Position.top); } normal.color("green"); normal.textStyle().color("red").fontSize(15).fontWeight("bolder"); //bar.setBarWidth("40"); //柱條寬度 //bar.setBarMaxWidth(100); //柱條最大寬度 //bar.setBarMinHeight(10); //柱條最小高度 bar.label().normal(normal); //迴圈資料 for(int i = 0;i < xdatas.length;i++){ int data = (int) ydatas[i]; String color = "rgb(2,111,230)"; //類目對應的柱狀圖 Map<String, Object> map = new HashMap<>(2); map.put("value", data); map.put("itemStyle", new ItemStyle().normal(new Normal().color(color))); bar.data(map); } if(isHorizontal){ //橫軸為類別,縱軸為值 option.xAxis(category); //x軸 option.yAxis(valueAxis); //y軸 }else { //橫軸為值,縱軸為類別 option.xAxis(valueAxis); //x軸 option.yAxis(category); //y軸 } option.series(bar); return option; } }
(8)util模組工具類:這些工具類都是比較常用的,也可以用到其他地方,因此這裡我都列舉出來
EchartsUtil.java:將option轉化為圖片編碼base64
package com.lhf.springboot.util; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import org.apache.http.client.ClientProtocolException; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * @ClassName: EchartsUtil * @Author: liuhefei * @Description: 生成echarts工具類:將生成的option轉化為base64編碼 * @Date: 2019/8/15 12:10 */ public class EchartsUtil { //private static String url = ""; private static final String SUCCESS_CODE = "1"; public static String generateEchartsBase64(String option, String url) 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; } }
FileUtil.java: 將圖片base64編碼轉化為圖片檔案
package com.lhf.springboot.util; import sun.misc.BASE64Decoder; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; /** * @ClassName: FileUtil * @Author: liuhefei * @Description: 將圖片base64編碼轉化為圖片 * @Date: 2019/8/15 18:52 */ public class FileUtil { public static File generateImage(String base64, String path) throws IOException { BASE64Decoder decoder = new BASE64Decoder(); File file = new File(path); String fileName = file.getName(); System.out.println("file = " + file); //建立臨時檔案 //File tempFile = File.createTempFile(fileName, ".png"); //FileOutputStream fos = new FileOutputStream(tempFile);*/ 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(); return file; } /* finally { //關閉臨時檔案 fos.flush(); fos.close(); try { Thread.sleep(10000); tempFile.deleteOnExit();//程式退出時刪除臨時檔案 } catch (InterruptedException e) { e.printStackTrace(); } } */ } public static void deleteFile(File file) { //File file = new File(); String fileName = file.getName(); // 如果檔案路徑所對應的檔案存在,並且是一個檔案,則直接刪除 if (file.exists() && file.isFile()) { if (file.delete()) { System.out.println("刪除單個檔案" + fileName + "成功!"); } else { System.out.println("刪除單個檔案" + fileName + "失敗!"); } } else { System.out.println("刪除單個檔案失敗:" + fileName + "不存在!"); } } }
HttpUtil.java:Http請求工具類
package com.lhf.springboot.util; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import org.apache.commons.lang3.StringUtils; import org.apache.http.*; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.config.RequestConfig; 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.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * @ClassName: HttpUtil * @Author: liuhefei * @Description: Http工具類 * @Date: 2019/8/15 12:10 */ public class HttpUtil { private static Logger logger = LoggerFactory.getLogger(HttpUtil.class); /** * 傳送post請求 * @param url * @param params * @param charset * @return * @throws ClientProtocolException * @throws IOException */ public static String post(String url, Map<String, String> params, String charset) throws ClientProtocolException, IOException { logger.info("httpPostRequest url : " + url + " paramMap : " + params); 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(); //System.out.println("responseEntity = " + responseEntity); return responseEntity; } public static String postUrl(String url, Map<String, Object> params, String charset) { String responseEntity = ""; // 建立CloseableHttpClient物件 CloseableHttpClient client = HttpClients.createDefault(); // 建立post方式請求物件 HttpPost httpPost = new HttpPost(url); // 將引數新增到post請求中 httpPost.setEntity(new StringEntity(JSON.toJSONString(params), charset)); // 傳送請求,獲取結果(同步阻塞) CloseableHttpResponse response = null; try { response = client.execute(httpPost); // 獲取響應實體 HttpEntity entity = response.getEntity(); if (entity != null) { // 按指定編碼轉換結果實體為String型別 responseEntity = EntityUtils.toString(entity, charset); } // 釋放資源 EntityUtils.consume(entity); } catch (Exception e) { e.printStackTrace(); } finally { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } return responseEntity; } /** * post請求(用於請求json格式的引數) * @param url * @param params * @return */ public static String doPost(String url, String params) throws Exception { logger.info("httpPostRequest url : " + url + " paramMap : " + params); CloseableHttpClient httpclient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(url);// 建立httpPost httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Content-Type", "application/json"); String charSet = "UTF-8"; StringEntity entity = new StringEntity(params, charSet); //logger.info("entity = " + entity); httpPost.setEntity(entity); CloseableHttpResponse response = null; try { response = httpclient.execute(httpPost); //logger.info("response = " + response); StatusLine status = response.getStatusLine(); int state = status.getStatusCode(); if (state == HttpStatus.SC_OK) { HttpEntity responseEntity = response.getEntity(); String jsonString = EntityUtils.toString(responseEntity); logger.info("post請求響應結果:{}", jsonString); return jsonString; } else{ logger.error("請求返回:"+state+"("+url+")"); } } finally { if (response != null) { try { response.close(); } catch (IOException e) { logger.error(e.getMessage()); } } try { httpclient.close(); } catch (IOException e) { logger.error(e.getMessage()); } } return null; } /** * http傳送POST請求 * * @author J.M.C * @since 2019年1月16日 * @param url 長連線URL * @param paramsJson 請求引數body * @return result 字串 */ public static String doPostJson(String url, JSONObject paramsJson) { logger.info("httpPostRequest url : " + url + " paramMap : " + paramsJson); if(StringUtils.isBlank(url)){ logger.error("httpPostRequest url is null"); return null; } String result = ""; try { // 建立httpClient例項 CloseableHttpClient httpClient = HttpClients.createDefault(); // 建立httpPost遠端連線例項 HttpPost httpPost = new HttpPost(url); // 配置請求引數例項 RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)// 設定連線主機服務超時時間 .setConnectionRequestTimeout(10000)// 設定連線請求超時時間 .setSocketTimeout(30000)// 設定讀取資料連線超時時間 .build(); // 為httpPost例項設定配置 httpPost.setConfig(requestConfig); // 設定請求頭 httpPost.addHeader("content-type", "application/json;charset=utf-8"); // 封裝post請求引數 httpPost.setEntity(new StringEntity(paramsJson.toJSONString(), Charset.forName("UTF-8"))); // httpClient物件執行post請求,並返回響應引數物件 // HttpResponse httpResponse = httpClient.execute(httpPost); CloseableHttpResponse httpResponse = httpClient.execute(httpPost); // 從響應物件中獲取響應內容 result = EntityUtils.toString(httpResponse.getEntity()); //logger.info("result = {}" , result); } catch (UnsupportedEncodingException e) { logger.error("URLUtil.httpPostRequest encounters an UnsupportedEncodingException : {}",e); } catch (IOException e) { logger.error("URLUtil.httpPostRequest encounters an IOException : {}",e); } logger.info("URLUtil.httpPostRequest -----result----: " + result); return result; } public static String send(String url, JSONObject jsonObject,String encoding) throws Exception{ logger.info("httpPostRequest url : " + url + " jsonObject : " + jsonObject); String body = ""; //建立httpclient物件 CloseableHttpClient client = HttpClients.createDefault(); //建立post方式請求物件 HttpPost httpPost = new HttpPost(url); String strParam = JSONObject.toJSONString(jsonObject); //System.out.println("strParam = " + strParam); //裝填引數 StringEntity entity = new StringEntity(strParam, "utf-8"); entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json")); //設定引數到請求物件中 httpPost.setEntity(entity); //System.out.println("請求地址:"+ url); //System.out.println("請求引數:"+ entity.toString()); //設定header資訊 //指定報文頭【Content-type】、【User-Agent】 //httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); httpPost.setHeader("Content-type", "application/json"); httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //執行請求操作,並拿到結果(同步阻塞) CloseableHttpResponse response = client.execute(httpPost); //獲取結果實體 HttpEntity entityResult = response.getEntity(); if (entityResult != null) { //按指定編碼轉換結果實體為String型別 body = EntityUtils.toString(entityResult, encoding); } EntityUtils.consume(entityResult); //釋放連結 response.close(); //logger.info("body = {}", body); return body; } public static JSONObject doPost(String url,JSONObject json){ logger.info("httpPostRequest url : " + url + " jsonObject : " + json); CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost post = new HttpPost(url); JSONObject response = null; try { StringEntity s = new StringEntity(json.toString()); s.setContentEncoding("UTF-8"); s.setContentType("application/json");//傳送json資料需要設定contentType post.setEntity(s); HttpResponse res = httpClient.execute(post); if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ HttpEntity entity = res.getEntity(); String result = EntityUtils.toString(res.getEntity());// 返回json格式: //logger.info("result = {}", result); response = (JSONObject) JSONObject.parse(result); } } catch (Exception e) { throw new RuntimeException(e); } //logger.info("response = {}", response); return response; } }
ImageUtil.java:給圖片新增水印
package com.lhf.springboot.util; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; /** * @ClassName: ImageUtil * @Author: liuhefei * @Description: 給圖片新增水印工具類 * @Date: 2019/9/10 12:32 */ public class ImageUtil { /** * 給圖片新增水印文字、可設定水印文字的旋轉角度 * @param logoText 要寫入的文字 * @param srcImgPath 源圖片路徑 * @param newImagePath 新圖片路徑 * @param degree 旋轉角度 * @param color 字型顏色 * @param formaName 圖片字尾 */ public static void markImageByText(String logoText, String srcImgPath, String newImagePath, Integer degree, Color color, String formaName) { InputStream is = null; OutputStream os = null; try { // 1、源圖片 Image srcImg = ImageIO.read(new File(srcImgPath)); BufferedImage buffImg = new BufferedImage(srcImg.getWidth(null),srcImg.getHeight(null), BufferedImage.TYPE_INT_RGB); // 2、得到畫筆物件 Graphics2D g = buffImg.createGraphics(); // 3、設定對線段的鋸齒狀邊緣處理 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(srcImg.getScaledInstance(srcImg.getWidth(null), srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0, null); // 4、設定水印旋轉 if (null != degree) { g.rotate(Math.toRadians(degree), buffImg.getWidth()/2,buffImg.getHeight() /2); } // 5、設定水印文字顏色 g.setColor(color); // 6、設定水印文字Font g.setFont(new Font("宋體", Font.BOLD, buffImg.getHeight() /6)); // 7、設定水印文字透明度 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.15f)); // 8、第一引數->設定的內容,後面兩個引數->文字在圖片上的座標位置(x,y) g.drawString(logoText, buffImg.getWidth()/4 , buffImg.getHeight()/2); // 9、釋放資源 g.dispose(); // 10、生成圖片 os = new FileOutputStream(newImagePath); ImageIO.write(buffImg, formaName, os); } catch (Exception e) { e.printStackTrace(); } finally { try { if (null != is) is.close(); } catch (Exception e) { e.printStackTrace(); } try { if (null != os) os.close(); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { markImageByText("霜花似雪","F:\echarts\bar1567600917165oNeL.png","F:\echarts\new\bar1567600917135oNeL.png",45,new Color(200,10,1),"png"); } }
RandomUtils.java
package com.lhf.springboot.util; import java.util.Random; /** * @ClassName: RandomUtils * @Desc: 生成隨機字串 * @Author: liuhefei * @Date: 2019/2/28 14:16 */ public class RandomUtils { public static String getRandomString(int length){ //1. 定義一個字串(A-Z,a-z,0-9)即62個數字字母; String str="zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890"; //2. 由Random生成隨機數 Random random=new Random(); StringBuffer sb=new StringBuffer(); //3. 長度為幾就迴圈幾次 for(int i=0; i<length; ++i){ //從62個的數字或字母中選擇 int number=random.nextInt(62); //將產生的數字透過length次承載到sb中 sb.append(str.charAt(number)); } //將承載的字元轉換成字串 return sb.toString(); } public static String getRandomNum(int length){ //1. 定義一個字串(A-Z,a-z,0-9)即62個數字字母; String str="1234567890"; //2. 由Random生成隨機數 Random random=new Random(); StringBuffer sb=new StringBuffer(); //3. 長度為幾就迴圈幾次 for(int i=0; i<length; ++i){ //從10個的數字中選擇 int number=random.nextInt(10); //將產生的數字透過length次承載到sb中 sb.append(str.charAt(number)); } //將承載的字元轉換成字串 return sb.toString(); } public static void main(String[] args) { //這裡的32是生成32位隨機碼,根據你的需求,自定義 String random1 = getRandomString(32); System.out.println(random1); String random2 = getRandomNum(32); System.out.println(random2); } }
(8)controller模組(API介面)- EchartsController.java
package com.lhf.springboot.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.github.abel533.echarts.json.GsonOption; import com.lhf.springboot.common.JsonResult; import com.lhf.springboot.echarts.option.EchartBar; import com.lhf.springboot.echarts.option.EchartLine; import com.lhf.springboot.echarts.option.EchartPie; import com.lhf.springboot.echarts.pojo.BarData; import com.lhf.springboot.echarts.pojo.LinesData; import com.lhf.springboot.echarts.pojo.PieData; import com.lhf.springboot.util.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.jboss.logging.Logger; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.awt.*; import java.io.File; import java.util.Calendar; import java.util.HashMap; import java.util.Map; /** * @ClassName: EchartsController * @Author: liuhefei * @Description: 利用Java程式碼生成柱狀圖和折線圖 * @Date: 2019/9/26 10:37 */ @Api(value = "生成Echarts圖表API介面", tags = "Echarts圖表") @RequestMapping("/echarts") @RestController public class EchartsController { private final static Logger logger = Logger.getLogger(EchartsController.class); @Value("${img-url}") private String imgUrl; @Value("${img-url-path}") private String imgUrlPath; @Value("${request-url}") private String requestUrl; @ApiOperation(value = "生成柱狀圖") @RequestMapping(value = "/bar", method = RequestMethod.POST) public JsonResult createBar(@RequestBody BarData barData){ GsonOption option = EchartBar.createBar(barData); String optionStr = JSONObject.toJSONString(option); if(optionStr == null || "".equals(optionStr)){ return new JsonResult(-1, "Fail"); } logger.info("bar-optionStr = " + optionStr); File oldfile = null; File newfile = null; String oldFilePath = null; String newFilePath = null; try { // 根據option引數發起請求,轉換為base64 String base64 = EchartsUtil.generateEchartsBase64(optionStr, requestUrl); long nowStr = Calendar.getInstance().getTimeInMillis(); //圖片名 String imageName = "bar"+nowStr+ RandomUtils.getRandomString(4)+".png"; logger.info("bar圖片:" + imageName); oldfile = FileUtil.generateImage(base64, imgUrl+imageName); newfile = new File(imgUrl+"new"+imageName); oldFilePath = imgUrl+imageName; newFilePath = imgUrl+"new"+imageName; logger.info("file = " + oldfile); logger.info("oldFilePath = " + oldFilePath); logger.info("newFilePath = " + newFilePath); String logoText = "霜花似雪"; //新增水印 ImageUtil.markImageByText(logoText, oldFilePath, newFilePath, -15, new Color(190,190,190), "png"); }catch (Exception e){ logger.error("發生了異常," + e.getMessage()); return new JsonResult(-1, "Fail"); } return new JsonResult(1, newFilePath, "SUCCESS"); } }
四、外掛環境配置
為了生成圖片,我們需要藉助外掛來實現,這裡我們以windows環境為主來說明
需要的外掛:phantomjs-2.1.1-windows.zip 和 saintlee-echartsconvert-master.zip
(1)phantomjs-2.1.1-windows.zip下載地址:
API地址:
(2)saintlee-echartsconvert-master.zip下載地址:(github地址及文件) 說明:此外掛有缺陷,生成不了餅圖,這個後面再說。
安裝配置:
1. 首先需要安裝這兩個外掛
2. 可將phantomjs-2.1.1-windows.zip新增到系統path變數下,我的安裝路徑:D:softpackechartsphantomjs-2.1.1-windowsbin(此變數加到path變數環境下),也可以不操作此步
3. 配置好後,啟動服務,啟動cmd命令視窗,命令列輸入<phantomjs路徑> <EChartsConvert路徑> -s -p <服務埠號>
五、結合Swagger文件測試
環境配置完成之後,啟動服務,swagger文件:
測試資料:
{ "barParamList": { "barName": [ "A罩杯", "B罩杯", "C罩杯", "D罩杯", "E罩杯", "F罩杯","G罩杯" ], "barValue": [ 43364, 13899, 12000, 2181, 21798, 1796, 1300 ], "legendName": "胸罩圖例" }, "horizontal": true, "title": "胸罩使用人數" }
效果展示:
由於篇幅太長,分享就到這裡,未完待續!
另外推薦為大家推薦幾門與Java相關的實戰課程,望笑納!
(1)
(2)
(3)
(4)
發文不易,請多多支援!如果幫助到了你,請點個贊!如果你急需程式碼,可以聯絡我!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2334/viewspace-2823865/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 完整的 java/kotlin 生成 echarts 圖片方法JavaKotlinEcharts
- 將echarts生成的圖表變為圖片儲存起來Echarts
- java後臺壓縮圖片Java
- 純JS生成並下載各種文字檔案或圖片JS
- 圖片輪播--純cssCSS
- 後臺展示圖片點選放大
- 將任意bmp圖片大小重新設定後生成新的bmp圖片
- Retrofit+RxJava上傳圖片上傳圖片到後臺RxJava
- Flutter 生成圖片Flutter
- pyecharts生成圖片Echarts
- 純前端 Canvas 實現 HTML 轉圖片,自動生成微信閱讀卡片前端CanvasHTML
- 如何生成WebP圖片Web
- 將 HTML 生成圖片HTML
- 圖片生成database 64Database
- python生成圖片Python
- 從ORACLE 生成圖片Oracle
- 網站後臺修改圖片新聞?公司網站圖片怎麼修改?網站
- 重拾圖片純淨之美:Topaz DeNoise AI,一鍵解決圖片降噪問題AI
- 在微信小程式中使用 echarts 圖片-例 折線圖微信小程式Echarts
- 使用freemarker將echarts圖片儲存到word中Echarts
- 短視訊平臺搭建,生成圖片形狀的位置
- 基於canvas生成圖片Canvas
- 某AI圖片生成網AI
- html input type=file 選擇圖片,圖片預覽 純html js實現圖片預覽HTMLJS
- 生成 Charts 圖片,併傳送 Charts 圖片郵件
- Java後臺Html轉圖片和獲取頁面屬性值,及圖片拼接JavaHTML
- 圖片純前端JS壓縮的實現前端JS
- 純CSS3實現圖片展示特效CSSS3特效
- 純前端實現 JPG 圖片壓縮 | canvas前端Canvas
- AlamofireImage 使用 – swift載入網路圖片,縮放圖片,生成圓形圖片Swift
- golang 生成圖片驗證碼Golang
- php生成二維碼圖片PHP
- android非同步生成圖片Android非同步
- java生成一張圖片Java
- KindEditor 圖片上傳後生成帶域名絕對路徑配置方法
- springboot mybatis 後臺框架平臺 整合程式碼生成器 shiro 許可權Spring BootMyBatis框架
- Android壓縮圖片後再上傳圖片Android
- Android-圖片壓縮(二)-純乾貨Android