开发需求:

       java语言与数据源结合,生成可视化图片,结合echarts 框架 将生成的图片写入到word 文档中,不采用前台生成等操作。

难点:

       后台如何生成图片,这是这个需求的难点,通过调研,有许多技术,比如Graphics2D、jfreechart、PhantomJS等等,Graphics2D 生成一些简单的图片比如二维码,海报等等,jfreechart 生成图片比较硬,需要各种调试,当然也可以生成好看的图片,对于懒的我来说,已经不在考虑了。最后决定使用PhantomJS技术来解决这个需求。

开发过程:

       实现这个技术,需要对这个技术有个初步的了解,在网上各种搜索,其实最后明白就是搭建个服务,我们后台直接请求这个服务生成图片,返回给我们, PhantomJS是一个无界面的,可脚本编程的WebKit浏览器引擎,供我们请求进行各种操作。

安装环境:

      下载对应系统地址: http://phantomjs.org/download       一. window系统:

java生成饼状图 java生成echarts图表_java生成饼状图


1.配置环境变量:

系统 – 高级系统设置 – 环境变量 --系统变量 设置PATH

java生成饼状图 java生成echarts图表_java生成饼状图_02


2.进入我们的cmd 窗口,phantomjs 即可看到效果。

3.使用一下它们提供的例子:

phantomjs e:\phantomjs-2.1.1-windows\examples\hello.js

Hello,world!

4.说明安装成功。

      二. linux 系统:

1.解压压缩包:

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

2.设置环境变量,并使得配置文件生效:

export PATH=${PATH}:/opt/phantomjs/bin

source /etc/profile

3.phantomjs 即可看到生效

注意:phantomjs: error while loading shared libraries: libfontconfig.so.1: cannot open shared object file: No such file or directory

解决办法:

yum install fontconfig freetype2 (yum安装)

3.使用一下它们提供的例子:

phantomjs opt\phantomjs\examples\hello.js

Hello,world!

4.说明安装成功!

实现需求:

java通过连接 phantomjs 来实现后端生成echarts .生成效果如下:

java生成饼状图 java生成echarts图表_window 安装 phantomjs _03


首先 后端封装参数,生成option 通过http 请求得到对应的 图片 base64;

主要代码:

option.ftl:

{
    xAxis: {
        type: 'value',
        show: false
    },
    yAxis: {
        type: 'category',
        data: ${categories},
        splitLine:{
            show: false
        },
        axisLine: {
            show: false
        },
        axisTick:{
            show: false
        },
        axisLabel:{
            fontSize: 14,
            fontFamily:'黑体'
        }
    },
    grid:{
        left: '110px',
        top: '0px',
        right: '60px',
        bottom: '12px'
     },
    color: ${colorValue},
    series: [{
        data: ${values},
        type: 'bar',
        barWidth: '20px',
        label: {
            show: true,
            position: 'right',
            formatter: '{b}',
            color: '#000',
            fontFamily:'黑体'
        }
  }]
}

EchartsUtils工具类:

public class EchartsUtil {
    private static  Properties configProperties;
    private static String url;
    private static final String SUCCESS_CODE = "1";



    /**
     *
     * @param option
     * @param width
     * @param height
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     */
    public static String generateEchartsBase64(String option,String width,String height) throws ClientProtocolException, IOException {
        if(StringUtils.isBlank(url)){
            configProperties = SpringContextHolder.getBean("configProperties");
            url = MapUtils.getString(configProperties, "phantomjs.url");
        }
        String base64 = "";
        if (option == null) {
            return base64;
        }
        option = option.replaceAll("\\s+", "").replaceAll("\"", "'");

        // 将option字符串作为参数发送给echartsConvert服务器
        Map<String, String> params = new HashMap();
        params.put("opt", option);
        params.put("width",width);
        params.put("height",height);

        String response = httpRequestUtils.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;
    }
}

FreemarkerUtil 工具类:

public class FreemarkerUtil {

    public static String generateString(HttpServletRequest httpRequest, String templateFileName, String templateDirectory, Map<String, Object> datas)
            throws IOException, TemplateException {
        Configuration configuration = new Configuration();

        configuration.setDefaultEncoding("UTF-8");

        // 设置模板所在文件夹
        String separator = File.separator;
        //如何区分是window 还是 liunx 系统
        String filedownload = "";
        if ("\\".equals(separator)) {
            System.out.println("windows下");
            filedownload = httpRequest.getSession().getServletContext().getRealPath("/WEB-INF/resources/file") + "/";
            filedownload = filedownload.replace("/", "\\");
        }
        // liunx 下
        if ("/".equals(separator)) {
            System.out.println("linux下");
            filedownload = httpRequest.getSession().getServletContext().getRealPath("/WEB-INF/resources/file") + "/" ;
            filedownload = filedownload.replace("\\", "/");
        }
        configuration.setDirectoryForTemplateLoading(new File(filedownload));
        // 生成模板对象
        Template template = configuration.getTemplate(templateFileName);

        // 将datas写入模板并返回
        try (StringWriter stringWriter = new StringWriter()) {
            template.process(datas, stringWriter);
            stringWriter.flush();
            return stringWriter.getBuffer().toString();
        }
    }

测试代码块:

public void getphantomjs(){
        // 变量
        String[] categories = new String[] { "苹果", "香蕉", "西瓜" };
        String[]  color= new String[] {"#008000"};
        Map <String,Object> dataMap=new HashMap<>();
        List dataList = new ArrayList<>();
        dataMap.put("name","B");
        dataMap.put("value",40);
        dataList.add(dataMap);
        dataMap=new HashMap<>();
        dataMap.put("name","AA");
        dataMap.put("value",60);
        dataList.add(dataMap);
        dataMap=new HashMap<>();
        dataMap.put("name","AAA");
        dataMap.put("value",100);
        dataList.add(dataMap);
        Object[] values = dataList.toArray();
        HashMap<String, Object> datas = new HashMap<>();
        //对应option.ftl 变量
        datas.put("categories", JSON.toJSONString(categories));
        datas.put("values", JSON.toJSONString(values));
        datas.put("colorValue",JSON.toJSONString(color));
        String option = null;
        try {
            option = FreemarkerUtil.generateString(getHttpRequest(),"option.ftl", "", datas);
            String base64 = EchartsUtil.generateEchartsBase64(option,"555","96");
            generateImage(base64, "D:\\test.png");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
    }


    public static void generateImage(String base64, String path) throws IOException {
        BASE64Decoder decoder = new BASE64Decoder();
        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();
        }
    }

``
2019/04/28 新增
  遗留2个问题:
      1. 关于启动 phantomjs
      2. linux 字体安装 生成与window一样的图片

第一个问题:

java生成饼状图 java生成echarts图表_java后台生成echart图片_04


打开js 查看

java生成饼状图 java生成echarts图表_window 安装 phantomjs _05


其目的就是启动时加载这个 别人封装好的js插件,传入参数生成想要的结果。

(默认端口号9090)

window 启动:

phantomjs C:\Users\LENOVO\Desktop\安装phantomjs\echartsconvert\echarts-convert.js -s

linux 后台启动:

nohup phantomjs /opt/phantomjs/echartsconvert/echarts-convert.js -s &

附件echarts-convert.js 下载路径:

第二个问题:
Linux系统安装windos字体步骤如下:
1、复制字体
  在“C:\Windows\Fonts”目录下找到所要安装字体,这里以“SIMHEI.TTF”为例。
2、上传字体至CentOS系统
  在/usr/share/fonts目录下建立一个子目录,比如/HEITIFONTS. 上传“SIMHEI.TTF”字体至此目录。
3、进入此目录安装
cd /usr/share/fonts/HEITIFONTS
运行以下命令建立字体索引信息,更新字体缓存:
sudo mkfontscale
sudo mkfontdir
sudo fc-cache -fv
执行以下命令让字体生效
source /etc/profile
安装可能遇到的问题与解决办法
1.权限问题:
cd /usr/share/fonts/HEITIFONTS
chmod 755 *.ttf
2.提示 “ mkfontscale: command not found”,用yum安装: yum install mkfontscale
提示 “ fc-cache: command not found” yum install fontconfig
若需要重启服务器: reboot
查看已安装的字体: fc-list

总结:
在开发过程中,还需要进一步更改,封装等等操作,如有疑问,请留言。。。