为了账号安全,请及时绑定邮箱和手机立即绑定

SpringBoot纯后台生成Echarts图片(一)

2019.10.12 18:11 4011浏览

       在实际的生产应用中,我们常常需要将数据进行可视化,生成一些图文报表以供前端使用与查看。而我们使用的最多的图表生成插件工具就是Echarts。为了生成相关的图文报表,我们可以通过前端结合js等来生成,另外也可以使用纯后台(Java代码)来生成。这里我们就介绍使用SpringBoot框架通过API传递参数的方式,纯Java代码而不使用前端来生成相关的图表。

本篇以生成柱状图为例:

一、项目的工程结构

http://img4.sycdn.imooc.com/5da1988e000183ba04400925.jpg

二、项目依赖说明

(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>
    <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.9</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.59</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.github.abel533/ECharts -->
    <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=http://127.0.0.1:6666
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", "https://www.imooc.com/u/1323320", "2510736432@qq.com"))
                .termsOfServiceUrl("https://swagger.io/swagger-ui/")
                .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 = "http://localhost:6666";

    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下载地址:

https://phantomjs.org/download.html  

API地址:http://phantomjs.org/api/

(2)saintlee-echartsconvert-master.zip下载地址:(github地址及文档)https://gitee.com/saintlee/echartsconvert/   说明:此插件有缺陷,生成不了饼图,这个后面再说。

安装配置:

1. 首先需要安装这两个插件

2. 可将phantomjs-2.1.1-windows.zip添加到系统path变量下,我的安装路径:D:\softpack\echarts\phantomjs-2.1.1-windows\bin(此变量加到path变量环境下),也可以不操作此步

3. 配置好后,启动服务,启动cmd命令窗口,命令行输入<phantomjs路径> <EChartsConvert路径> -s -p <服务端口号>

http://img4.sycdn.imooc.com/5da1a29b0001778810300230.jpg


五、结合Swagger文档测试

环境配置完成之后,启动服务,swagger文档:http://localhost:8095/swagger-ui.html

测试数据:

{
  "barParamList": {
    "barName": [
      "A罩杯", "B罩杯", "C罩杯", "D罩杯", "E罩杯", "F罩杯","G罩杯"
    ],
    "barValue": [
      43364, 13899, 12000, 2181, 21798, 1796, 1300
    ],
    "legendName": "胸罩图例"
  },
  "horizontal": true,
  "title": "胸罩使用人数"
}

效果展示:

http://img2.sycdn.imooc.com/5da1a4ac0001e30208000400.jpg

http://img1.sycdn.imooc.com/5da1a49d00018dfc08000400.jpg

由于篇幅太长,分享就到这里,未完待续!

另外推荐为大家推荐几门与Java相关的实战课程,望笑纳!

(1)一站式学习Java网络编程 全面理解BIO/NIO/AIO

(2)Spring Boot开发理财平台产品系统

(3)Java分布式仿小米卡包后台开发实战

(4)聚焦Java性能优化 打造亿级流量秒杀系统

发文不易,请多多支持!如果帮助到了你,请点个赞!如果你急需代码,可以联系我!

点击查看更多内容

本文首次发布于慕课网 ,转载请注明出处,谢谢合作

5人点赞

若觉得本文不错,就分享一下吧!

评论

相关文章推荐

正在加载中
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消