SpringBoot純後臺生成Echarts圖片(一)

yzf01發表於2021-09-09

       在實際的生產應用中,我們常常需要將資料進行視覺化,生成一些圖文報表以供前端使用與檢視。而我們使用的最多的圖表生成外掛工具就是。為了生成相關的圖文報表,我們可以透過前端結合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/,如需轉載,請註明出處,否則將追究法律責任。

相關文章