精华内容
下载资源
问答
  • 2022-03-22 22:54:28

    说明

    Java poi实现生成图表并附带表格数据展示
    

    一、效果图与模板

    1、模板
    在这里插入图片描述

    2、效果图
    在这里插入图片描述

    二、Word生成图标与报表工具类

    1.工具类

    代码如下:

    package com.ml.module.file.util.wordchart;
    
    import com.google.common.base.Strings;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Maps;
    import com.ml.module.file.domain.entity.ChartType;
    import com.ml.support.dto.ChartData;
    import org.apache.commons.collections.CollectionUtils;
    import org.apache.commons.collections.MapUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.ooxml.POIXMLDocumentPart;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
    import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
    import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
    import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
    import org.apache.poi.xwpf.usermodel.*;
    import org.apache.xmlbeans.XmlCursor;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
    
    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.util.*;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.stream.Collectors;
    
    /**
     * word图表模板与table工具类
     * 根据图表模板以及动态生成表格工具类
     */
    public class WordChartTplAndTableUtils {
        private static final BigDecimal bd2 = new BigDecimal("2");
    
        /**
         * 替换图表模板以及生产动态表格
         */
        public static void replaceChartTplAndCreateTable(XWPFDocument doc, List<WordTplDataSourceInput> charItems) {
            Map<String, TableDataSourceInput> inputMap = Maps.newHashMap();
            Map<String, POIXMLDocumentPart> chartsMap = getChartsMap(doc);//获取模板的图表
    
            AtomicInteger ao = new AtomicInteger(1);
            charItems.forEach(data -> {
                TableDataSourceInput table = new TableDataSourceInput();
                int sortNum = ao.getAndIncrement();
                table.setTextParam("table" + sortNum);
                POIXMLDocumentPart documentPart = chartsMap.get("/word/charts/chart" + sortNum + ".xml");
    
                switch (data.getChartType()) {
                    case REPORT:
                        table.setHeaders(data.getHeaders());
                        table.setDataSource(data.getDataSource());
                        break;
                    default:
                        setChartData((XWPFChart) documentPart, data.getTitle(), data.getCharts());
                }
    
                /**
                 * 1、标题值为paramColTitle+data里的group的值,作为标题
                 * 2、每一行的数据为,按data里的name进行分组,然后根据headers进行拼装
                 */
                if (data.getChartType() != ChartType.REPORT) {
                    List<String> titleArr = data.getCharts().stream().map(ChartData::getGroup).distinct().collect(Collectors.toList());
    
                    List<List<String>> dataSource = Lists.newArrayList();
                    Map<String, List<ChartData>> maps = data.getCharts().stream()
                        .collect(Collectors.groupingBy(ChartData::getName, LinkedHashMap::new, Collectors.toList()));
                    maps.forEach((k, v) -> {
                        List<String> dataItems = Lists.newArrayList();
                        dataItems.add(k);
                        //根据分组获取
                        Map<String, BigDecimal> groupMap = v.stream().collect(Collectors.toMap(ChartData::getGroup, ChartData::getXxxValue));
                        titleArr.forEach(group -> {
                            Object val = MapUtils.getObject(groupMap, group);
                            dataItems.add(Objects.isNull(val) ? "" : val.toString());
                        });
                        dataSource.add(dataItems);
                    });
    
                    titleArr.add(0, data.getParamColTitle());
                    table.setHeaders(titleArr);
                    table.setDataSource(dataSource);
                }
    
                inputMap.put(table.getTextParam(), table);
            });
    
            doParagraphs(doc, inputMap); // 处理段落文字数据,包括文字和表格、图片
        }
    
        /**
         * 处理图表
         * 获取word模板中的所有图表元素,用map存放
         * 为什么不用list保存:查看doc.getRelations()的源码可知,源码中使用了hashMap读取文档图表元素,
         * 对relations变量进行打印后发现,图表顺序和文档中的顺序不一致,也就是说relations的图表顺序不是文档中从上到下的顺序
         */
        private static Map<String, POIXMLDocumentPart> getChartsMap(XWPFDocument doc) {
            Map<String, POIXMLDocumentPart> chartsMap = new HashMap<>();
            //动态刷新图表
            List<POIXMLDocumentPart> relations = doc.getRelations();
            for (POIXMLDocumentPart poixmlDocumentPart : relations) {
                if (poixmlDocumentPart instanceof XWPFChart) {  // 如果是图表元素
                    String str = poixmlDocumentPart.toString();
                    System.out.println("str:" + str);
                    String key = str.replaceAll("Name: ", "")
                        .replaceAll(" - Content Type: application/vnd\\.openxmlformats-officedocument\\.drawingml\\.chart\\+xml", "").trim();
                    System.out.println("key:" + key);
    
                    chartsMap.put(key, poixmlDocumentPart);
                }
            }
    
            System.out.println("\n图表数量:" + chartsMap.size() + "\n");
    
            return chartsMap;
        }
    
        /**
         * 设置图标数据
         *
         * @param chart         模板图标
         * @param chartTitle    图标标题
         * @param chartDataList --》String[] series, String[] categories, Double[] values1, Double[] values2
         */
        private static void setChartData(XWPFChart chart, String chartTitle, List<ChartData> chartDataList) {
            if (CollectionUtils.isEmpty(chartDataList)) {//当传入的值为空时,暂时改为如下
                chartDataList.add(ChartData.of("无", "无", BigDecimal.ZERO));
            }
            final List<XDDFChartData> data = chart.getChartSeries();
            XDDFChartData bar = data.get(0);
    
            /*************设计数据源(Excel格式)开始**************/
            String[] series = chartDataList.stream().map(ChartData::getGroup).distinct().toArray(String[]::new);
            String[] categories = chartDataList.stream().map(ChartData::getName).distinct().toArray(String[]::new);
    
            final int numOfPoints = categories.length;
            //获取数据区间--》如:Sheet1!$A$2:$A$9
            final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));//第一列固定为分类
            final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);
    
            AtomicInteger ao = new AtomicInteger(1);//每一列代表一个序列
            for (String ser : series) {// 假设不包含分类序列
                int aoNum = ao.getAndIncrement();
                String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, aoNum, aoNum));
                Map<String, BigDecimal> valueMap = chartDataList.stream()
                    .filter(i -> ser.equals(i.getGroup()))
                    .collect(Collectors.toMap(ChartData::getName, ChartData::getXxxValue));
                Double[] values = getValues(categories, valueMap);
                XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values, valuesDataRange, aoNum);
                if (aoNum == 1) {
                    XDDFChartData.Series series1 = bar.getSeries().get(0);
                    series1.replaceData(categoriesData, valuesData);// 替换
                    series1.setTitle(ser, chart.setSheetTitle(ser, 0));
                } else {
                    XDDFChartData.Series series2 = bar.addSeries(categoriesData, valuesData);// 添加
                    series2.setTitle(ser, chart.setSheetTitle(ser, aoNum));
                }
            }
    
            chart.plot(bar);// 绘制(图表)
            chart.setTitleText(chartTitle); // https://stackoverflow.com/questions/30532612
            chart.setTitleOverlay(false);
        }
    
        /**
         * 1、值的顺序怎么保证呢???
         * 2、为空的值,是否能忽略???
         */
        private static Double[] getValues(String[] categories, Map<String, BigDecimal> valueMap) {
            List<Double> result = Lists.newArrayList();
            for (String cate : categories) {
                result.add(valueMap.getOrDefault(cate, BigDecimal.ZERO).doubleValue());
            }
    
            return result.toArray(new Double[0]);
        }
    
        /********************动态表格开始****************************/
        /**
         * 处理段落文字
         */
        private static void doParagraphs(XWPFDocument doc, Map<String, TableDataSourceInput> inputMap) {
            List<XWPFParagraph> paragraphList = doc.getParagraphs();
            if (paragraphList != null && paragraphList.size() > 0) {
                for (XWPFParagraph paragraph : paragraphList) {
                    List<XWPFRun> runs = paragraph.getRuns();
                    for (XWPFRun run : runs) {
                        String text = run.getText(0);
                        if (!Strings.isNullOrEmpty(text)) {
                            String param = StringUtils.substringBetween(text, "{", "}");
                            if (inputMap.containsKey(param)) {
                                TableDataSourceInput input = (TableDataSourceInput) MapUtils.getObject(inputMap, param);
                                createTable(doc, paragraph, run, input.headers, input.dataSource);
                            }
                        }
                    }
                }
            }
        }
    
        // 动态表格
        private static void createTable(XWPFDocument doc, XWPFParagraph paragraph, XWPFRun run, List<String> headers, List<List<String>> dataSource) {
            run.setText("", 0);
            XmlCursor cursor = paragraph.getCTP().newCursor();
            XWPFTable tableOne = doc.insertNewTbl(cursor);// ---这个是关键
    
            // 设置表格宽度,第一行宽度就可以了,这个值的单位,目前我也还不清楚,还没来得及研究
            tableOne.setWidth(8500);
    
            // 表格第一行,对于每个列,必须使用createCell(),而不是getCell(),因为第一行嘛,肯定是属于创建的,没有create哪里来的get呢
            XWPFTableRow tableOneRowOne = tableOne.getRow(0);//行
            AtomicInteger ao = new AtomicInteger(1);
            int num = headers.size();
            if (num == 0) return;
    
            int width = 100 / num;
            headers.forEach(i -> {
                if (ao.getAndIncrement() == 1)
                    setWordCellSelfStyle(tableOneRowOne.getCell(0), "微软雅黑", "9", 0, "left", "top", "#000000", "#FFFFFF", "" + width + "%", i);
                else
                    setWordCellSelfStyle(tableOneRowOne.createCell(), "微软雅黑", "9", 0, "left", "top", "#000000", "#FFFFFF", "" + width + "%", i);
            });
    
            // 动态添加数据
            dataSource.forEach(row -> {
                AtomicInteger pos = new AtomicInteger(0);
                XWPFTableRow tableOneRowTwo = tableOne.createRow();//行
                row.forEach(coll -> setWordCellSelfStyle(tableOneRowTwo.getCell(pos.getAndIncrement()), "微软雅黑", "9", 0, "left", "top", "#000000", "#FFFFFF", "" + width + "%", coll));
            });
        }
    
        /**
         * 设置表格样式
         */
        private static void setWordCellSelfStyle(XWPFTableCell cell, String fontName, String fontSize, int fontBlod,
                                                 String alignment, String vertical, String fontColor,
                                                 String bgColor, String cellWidth, String content) {
            if (null == cell) return;
            //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理
            BigInteger bFontSize = new BigInteger("24");
            if (Strings.isNullOrEmpty(fontSize)) {
                //poi对字体大小设置特殊,不支持小数,但对原word字体大小做了乘2处理
                BigDecimal fontSizeBD = new BigDecimal(fontSize);
                fontSizeBD = bd2.multiply(fontSizeBD);
                fontSizeBD = fontSizeBD.setScale(0, BigDecimal.ROUND_HALF_UP);//这里取整
                bFontSize = new BigInteger(fontSizeBD.toString());// 字体大小
            }
    
            // 设置单元格宽度
            cell.setWidth(cellWidth);
    
            //=====获取单元格
            CTTc tc = cell.getCTTc();
            //====tcPr开始====》》》》
            CTTcPr tcPr = tc.getTcPr();//获取单元格里的<w:tcPr>
            if (tcPr == null) {//没有<w:tcPr>,创建
                tcPr = tc.addNewTcPr();
            }
    
            //  --vjc开始-->>
            CTVerticalJc vjc = tcPr.getVAlign();//获取<w:tcPr>  的<w:vAlign w:val="center"/>
            if (vjc == null) {//没有<w:w:vAlign/>,创建
                vjc = tcPr.addNewVAlign();
            }
            //设置单元格对齐方式
            vjc.setVal(vertical.equals("top") ? STVerticalJc.TOP : vertical.equals("bottom") ? STVerticalJc.BOTTOM : STVerticalJc.CENTER); //垂直对齐
    
            CTShd shd = tcPr.getShd();//获取<w:tcPr>里的<w:shd w:val="clear" w:color="auto" w:fill="C00000"/>
            if (shd == null) {//没有<w:shd>,创建
                shd = tcPr.addNewShd();
            }
            // 设置背景颜色
            shd.setFill(bgColor.substring(1));
            //《《《《====tcPr结束====
    
            //====p开始====》》》》
            CTP p = tc.getPList().get(0);//获取单元格里的<w:p w:rsidR="00C36068" w:rsidRPr="00B705A0" w:rsidRDefault="00C36068" w:rsidP="00C36068">
    
            //---ppr开始--->>>
            CTPPr ppr = p.getPPr();//获取<w:p>里的<w:pPr>
            if (ppr == null) {//没有<w:pPr>,创建
                ppr = p.addNewPPr();
            }
            //  --jc开始-->>
            CTJc jc = ppr.getJc();//获取<w:pPr>里的<w:jc w:val="left"/>
            if (jc == null) {//没有<w:jc/>,创建
                jc = ppr.addNewJc();
            }
            //设置单元格对齐方式
            jc.setVal(alignment.equals("left") ? STJc.LEFT : alignment.equals("right") ? STJc.RIGHT : STJc.CENTER); //水平对齐
            //  <<--jc结束--
            //  --pRpr开始-->>
            CTParaRPr pRpr = ppr.getRPr(); //获取<w:pPr>里的<w:rPr>
            if (pRpr == null) {//没有<w:rPr>,创建
                pRpr = ppr.addNewRPr();
            }
            CTFonts pfont = pRpr.getRFonts();//获取<w:rPr>里的<w:rFonts w:ascii="宋体" w:eastAsia="宋体" w:hAnsi="宋体"/>
            if (pfont == null) {//没有<w:rPr>,创建
                pfont = pRpr.addNewRFonts();
            }
            //设置字体
            pfont.setAscii(fontName);
            pfont.setEastAsia(fontName);
            pfont.setHAnsi(fontName);
    
            CTOnOff pb = pRpr.getB();//获取<w:rPr>里的<w:b/>
            if (pb == null) {//没有<w:b/>,创建
                pb = pRpr.addNewB();
            }
            //设置字体是否加粗
            pb.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF);
    
            CTHpsMeasure psz = pRpr.getSz();//获取<w:rPr>里的<w:sz w:val="32"/>
            if (psz == null) {//没有<w:sz w:val="32"/>,创建
                psz = pRpr.addNewSz();
            }
            // 设置单元格字体大小
            psz.setVal(bFontSize);
            CTHpsMeasure pszCs = pRpr.getSzCs();//获取<w:rPr>里的<w:szCs w:val="32"/>
            if (pszCs == null) {//没有<w:szCs w:val="32"/>,创建
                pszCs = pRpr.addNewSzCs();
            }
            // 设置单元格字体大小
            pszCs.setVal(bFontSize);
            //  <<--pRpr结束--
            //<<<---ppr结束---
    
            //---r开始--->>>
            List<CTR> rlist = p.getRList(); //获取<w:p>里的<w:r w:rsidRPr="00B705A0">
            CTR r;
            if (rlist != null && rlist.size() > 0) {//获取第一个<w:r>
                r = rlist.get(0);
            } else {//没有<w:r>,创建
                r = p.addNewR();
            }
            //--rpr开始-->>
            CTRPr rpr = r.getRPr();//获取<w:r w:rsidRPr="00B705A0">里的<w:rPr>
            if (rpr == null) {//没有<w:rPr>,创建
                rpr = r.addNewRPr();
            }
            //->-
            CTFonts font = rpr.getRFonts();//获取<w:rPr>里的<w:rFonts w:ascii="宋体" w:eastAsia="宋体" w:hAnsi="宋体" w:hint="eastAsia"/>
            if (font == null) {//没有<w:rFonts>,创建
                font = rpr.addNewRFonts();
            }
            //设置字体
            font.setAscii(fontName);
            font.setEastAsia(fontName);
            font.setHAnsi(fontName);
    
            CTOnOff b = rpr.getB();//获取<w:rPr>里的<w:b/>
            if (b == null) {//没有<w:b/>,创建
                b = rpr.addNewB();
            }
            //设置字体是否加粗
            b.setVal(fontBlod == 1 ? STOnOff.ON : STOnOff.OFF);
            CTColor color = rpr.getColor();//获取<w:rPr>里的<w:color w:val="FFFFFF" w:themeColor="background1"/>
            if (color == null) {//没有<w:color>,创建
                color = rpr.addNewColor();
            }
            // 设置字体颜色
            if (!Strings.isNullOrEmpty(content) && content.contains("↓")) {
                color.setVal("43CD80");
            } else if (!Strings.isNullOrEmpty(content) && content.contains("↑")) {
                color.setVal("943634");
            } else {
                color.setVal(fontColor.substring(1));
            }
            CTHpsMeasure sz = rpr.getSz();
            if (sz == null) {
                sz = rpr.addNewSz();
            }
            sz.setVal(bFontSize);
            CTHpsMeasure szCs = rpr.getSzCs();
            if (szCs == null) {
                szCs = rpr.addNewSz();
            }
            szCs.setVal(bFontSize);
            //-<-
            //<<--rpr结束--
            List<CTText> tlist = r.getTList();
            CTText t;
            if (tlist != null && tlist.size() > 0) {//获取第一个<w:r>
                t = tlist.get(0);
            } else {//没有<w:r>,创建
                t = r.addNewT();
            }
            t.setStringValue(Strings.isNullOrEmpty(content) ? "" : content);
            //<<<---r结束---
        }
        /********************动态表格结束****************************/
    }
    
    

    2.入参WordTplDataSourceInput

    代码如下:

    @Getter @Setter
    public class WordTplDataSourceInput extends TableDataSourceInput {
        ChartType chartType = ChartType.BAR;//类型
    
        private String title;
        private List<ChartData> charts = Lists.newArrayList();
    
        private String paramColTitle;//参数列名称--》对应数据源(Excel)第一列的标题
    
        String textParam = "table1";//模板参数定义表格:最终格式为:${table1},只保留里面
        List<String> headers = Lists.newArrayList();// 标题/或表格头部
        List<List<String>> dataSource = Lists.newArrayList();
    }
    

    3.测试用例

    代码如下:

    public class ChartExampleService {
    
        @Test
        public void chart_example_test() throws Exception {
    
            final String fileInput = "C:\\file\\chart\\test\\line-chart-template.docx";  //
            try (FileInputStream argIS = new FileInputStream(fileInput)) {
                try (XWPFDocument doc = new XWPFDocument(argIS)) {// doc为模板文件
                    WordChartTplAndTableUtils.replaceChartTplAndCreateTable(doc, mockData());
                    // 保存返回
                    try (OutputStream out = new FileOutputStream("C:\\file\\chart\\test\\line_chart-demo-output.docx")) {
                        doc.write(out);
                    }
                }
                System.out.println("Done");
            }
        }
    
        private List<WordTplDataSourceInput> mockData() {
            List<WordTplDataSourceInput> result = Lists.newArrayList();
    
            WordTplDataSourceInput input1 = new WordTplDataSourceInput();
            input1.setChartType(ChartType.BAR);
            input1.setCharts(chartData());
            input1.setTitle("请假统计分析");
            input1.setParamColTitle("年月");
    
            result.add(input1);
    
            return result;
        }
    
        /**
         * 数据集
         */
        private List<ChartData> chartData() {
            List<ChartData> result = Lists.newArrayList();
    
            result.add(ChartData.of("测试-请假类型", "202001", BigDecimal.valueOf(4)));
            result.add(ChartData.of("测试-请假类型", "202002", BigDecimal.valueOf(4)));
            result.add(ChartData.of("测试-请假类型", "202003", BigDecimal.valueOf(3)));
            result.add(ChartData.of("请假测试类型", "202001", BigDecimal.valueOf(1.3)));
            result.add(ChartData.of("请假测试类型", "202002", BigDecimal.valueOf(2)));
    
    
            return result.stream()
                .sorted(Comparator.comparing(ChartData::getGroup)
                    .thenComparing(ChartData::getName))
                .collect(Collectors.toList());
        }
    }
    

    参考官网例子

    可以导POI官网查看相关资料,例子的网址为:
    https://poi.apache.org/components/spreadsheet/examples.html#linked-dropdown

    更多相关内容
  • 在工作中经常用到会有一些生成统计报告、请假等word的功能需求,小编之前做了一些报表的生成,使用过freemarker和poi,但是使用freemarker生成word有一些麻烦的点: 需要先将模板word转化为xml,而且在模板word中写...

    先给大家一个效果图:

    左侧是word模板,右侧是生成后的word文档。

     

    在工作中经常用到会有一些生成统计报告、请假等word的功能需求,小编之前做了一些报表的生成,使用过freemarker和poi,但是使用freemarker生成word有一些麻烦的点:

    1. 需要先将模板word转化为xml,而且在模板word中写好的占位符${obj}也会在转化为xml后被拆分开,还需要人工处理一次
    2. 在表格循环的时候,需要使用freemarker的<#list list as item>标签进行遍历
    3. 统计图表(饼图、折线图、柱状图等),图片适配度地,操作麻烦,图表需要人工修改大量xml中的标签已达到动态修改图表数据的效果,而word转为xml时,图片是已base64进行存储,在模板替换中我们需要将图片的base64码替换为占位符

    这就意味着使用freemarker需要我们预先编写好word模板再转化为xml,再对xml进行freemaker的标签、占位符等的处理后才能进行word生成,而且图表支持度很低。

    这里小编使用easypoi+jfree的形式进行word生成,使用jfree生成统计图表(饼图、折线图、柱状图等)图片,使用easypoi进行占位符替换、表格循环、图片插入已达到根据word模板生成word的效果。通过这个方式生成word只需要预先编写好word模板就可以进行word生成。

    但这个解决方案有一种缺点就是只支持07以后的word,也就是后缀为.docx的word文档。

    下面我就以Spring Boot项目为例举一个例子:

    开发工具:IntelliJ IDEA

    JDK:1.8

    以及项目目录结构:

    1、添加依赖:

            <dependency>
    			<groupId>cn.afterturn</groupId>
    			<artifactId>easypoi-base</artifactId>
    			<version>4.1.0</version>
    		</dependency>
    		<dependency>
    			<groupId>org.jfree</groupId>
    			<artifactId>jcommon</artifactId>
    			<version>1.0.24</version>
    		</dependency>
    		<dependency>
    			<groupId>org.jfree</groupId>
    			<artifactId>jfreechart</artifactId>
    			<version>1.5.0</version>
    		</dependency>

    2、编写jfreeutil工具类

    作为例子,我只封装了将图片转为字节数组和根据具有生成饼状图Image实体的两个方法,各位自行参考

    import cn.afterturn.easypoi.entity.ImageEntity;
    import lombok.extern.slf4j.Slf4j;
    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartUtils;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.StandardChartTheme;
    import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
    import org.jfree.chart.plot.PiePlot;
    import org.jfree.data.general.DefaultPieDataset;
    import org.springframework.util.Assert;
    import java.awt.*;
    import java.io.*;
    import java.util.Map;
    
    /**
     * @author 何昌杰
     *
     * 参考API博客 https://blog.csdn.net/dagecao/article/details/86536680
     */
    @Slf4j
    public class JfreeUtil {
    
        private static String tempImgPath="D:\\tempJfree.jpeg";
    
        /**
         * 将图片转化为字节数组
         * @return 字节数组
         */
        private static byte[] imgToByte(){
            File file = new File(tempImgPath);
            byte[] buffer = null;
            try {
                FileInputStream fis = new FileInputStream(file);
                ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
                byte[] b = new byte[1000];
                int n;
                while ((n = fis.read(b)) != -1) {
                    bos.write(b, 0, n);
                }
                fis.close();
                bos.close();
                buffer = bos.toByteArray();
            } catch (IOException e) {
                log.error(e.getMessage());
            }
            //删除临时文件
            file.delete();
            return buffer;
        }
    
        public static ImageEntity pieChart(String title, Map<String, Integer> datas, int width, int height) {
    
            //创建主题样式
            StandardChartTheme standardChartTheme = new StandardChartTheme("CN");
            //设置标题字体
            standardChartTheme.setExtraLargeFont(new Font("宋体", Font.BOLD, 20));
            //设置图例的字体
            standardChartTheme.setRegularFont(new Font("宋体", Font.PLAIN, 15));
            //设置轴向的字体
            standardChartTheme.setLargeFont(new Font("宋体", Font.PLAIN, 15));
            //设置主题样式
            ChartFactory.setChartTheme(standardChartTheme);
    
            //根据jfree生成一个本地饼状图
            DefaultPieDataset pds = new DefaultPieDataset();
            datas.forEach(pds::setValue);
            //图标标题、数据集合、是否显示图例标识、是否显示tooltips、是否支持超链接
            JFreeChart chart = ChartFactory.createPieChart(title, pds, true, false, false);
            //设置抗锯齿
            chart.setTextAntiAlias(false);
            PiePlot plot = (PiePlot) chart.getPlot();
            plot.setNoDataMessage("暂无数据");
            //忽略无值的分类
            plot.setIgnoreNullValues(true);
            plot.setBackgroundAlpha(0f);
            //设置标签阴影颜色
            plot.setShadowPaint(new Color(255,255,255));
            //设置标签生成器(默认{0})
            plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}({1})/{2}"));
            try {
                ChartUtils.saveChartAsJPEG(new File(tempImgPath), chart, width, height);
            } catch (IOException e1) {
                log.error("生成饼状图失败!");
            }
            ImageEntity imageEntity = new ImageEntity(imgToByte(), width, height);
            Assert.notNull(imageEntity.getData(),"生成饼状图对象失败!");
            return imageEntity;
        }
    }

    关于jfree的一些API接口,和图形图表属性设置各位可参考这篇博客

    注:@Slf4j注解需要添加lombok的依赖

    3、编写wordutil工具类

    import cn.afterturn.easypoi.word.WordExportUtil;
    import org.apache.poi.xwpf.usermodel.XWPFDocument;
    import org.springframework.util.Assert;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.util.Map;
    
    /**
     * @author 何昌杰
     */
    public class WordUtil {
        /**
         * 导出word
         * <p>第一步生成替换后的word文件,只支持docx</p>
         * <p>第二步下载生成的文件</p>
         * <p>第三步删除生成的临时文件</p>
         * 模版变量中变量格式:{{foo}}
         *
         * @param templatePath word模板地址
         * @param temDir       生成临时文件存放地址
         * @param fileName     文件名
         * @param params       替换的参数
         */
        public static void exportWord(String templatePath, String temDir, String fileName, Map<String, Object> params) {
            Assert.notNull(templatePath, "模板路径不能为空");
            Assert.notNull(temDir, "临时文件路径不能为空");
            Assert.notNull(fileName, "导出文件名不能为空");
            Assert.isTrue(fileName.endsWith(".docx"), "word导出请使用docx格式");
            if (!temDir.endsWith("/")) {
                temDir = temDir + File.separator;
            }
            File dir = new File(temDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            try {
                XWPFDocument doc = WordExportUtil.exportWord07(templatePath, params);
                String tmpPath = temDir + fileName;
                FileOutputStream fos = new FileOutputStream(tmpPath);
                doc.write(fos);
                fos.flush();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    4、编写word模板

    关于word中的更多表达式各位可参考easypoi文档的3节内容。

    5、编写测试类

    import java.util.ArrayList;
    import java.util.HashMap;
    import cn.afterturn.easypoi.entity.ImageEntity;
    import com.springclouddemo.freemarkerdemo.utils.JfreeUtil;
    import com.springclouddemo.freemarkerdemo.utils.WordUtil;
    
    /**
     * @author 何昌杰
     */
    public class WordDemo1 {
    
        public static void main(String[] args) {
            HashMap<String, Object> map = new HashMap<>(4);
    
            //模拟饼状图数据
            HashMap<String, Integer> datas = new HashMap<>(3);
            datas.put("一号",10);
            datas.put("二号",20);
            datas.put("三号",40);
            ImageEntity imageEntity = JfreeUtil.pieChart("测试",datas, 500, 300);
             map.put("picture", imageEntity);
    
            //模拟其它普通数据
            map.put("username", "张三");
            map.put("date", "2019-10-10");
            map.put("desc", "测试");
            map.put("boo", true);
    
            //模拟表格数据
            ArrayList<HashMap<String, String>> list = new ArrayList<>(2);
            HashMap<String, String> temp = new HashMap<>(3);
            temp.put("sn","1");
            temp.put("name","第一个人");
            temp.put("age","23");
            list.add(temp);
            temp = new HashMap<>(3);
            temp.put("sn","2");
            temp.put("name","第二个人");
            temp.put("age","24");
            list.add(temp);
            map.put("personlist",list);
            //word模板相对路径、word生成路径、word生成的文件名称、数据源
            WordUtil.exportWord("template/demo1.docx", "D:/", "生成文件.docx", map);
        }
    }

    6、运行测试

    生成后的word文档

    展开全文
  • 怎样用电脑制作条形统计图和柱形统计...WPS插入的统计图表怎么制作第一步:选取数据源首先,打开表格,在其中选取数据源,用鼠标框选出第一绘区的数据和第二绘区的数据,需要注意的是在框选的过程中,不要选第二绘区...

    怎样用电脑制作条形统计图和柱形统计图

    用电脑制作条形统计图和柱形统计图,可通过EXCEL表格实现。

    方法步骤如下:

    1、打开EXCEL表格,输入需要制作图表的相关数据,然后选中相关数据,点击插入选项卡中“柱形图”,并选择一个柱形图样式插入。

    e1fe9925bc315c6010ef370683b1cb13485477e4.jpg

    WPS插入的统计图表怎么制作

    第一步:选取数据源

    首先,打开表格,在其中选取数据源,用鼠标框选出第一绘区的数据和第二绘区的数据,需要注意的是在框选的过程中,不要选第二绘区的总数。

    第二步:创建图表,选择合适的双饼图

    在表格上方“插入”的选项卡中选择“图表”按钮,这样就会弹出的“选择图表”类型的对话框,选择左侧的“饼图”,在“饼图”的下拉式菜单中点击“双饼图”的图标,最后点“完成”。这样双饼图就创建好了。:

    第三步:设置图系列格式

    在饼状图上右击,在下拉列表中选择“数据系列格式”,开始设置图表的系列格式。

    打开“数据系列格式”对话框后,选择“选项”选项卡,选择“第二绘图区的数值”为“4”,因为第一绘图区中的“其他”组中包括4个类别。

    选择“数据标志”的选项卡勾选“类别名称”和“百分比”前面的对号,最后点击确定。

    常见的统计图有()(),条形统计图可以表示()...

    1、常见的统计图有(条形统计图、折线统计图、扇形统计图);

    2、条形统计图可以表示(数量)的多少;

    3、在制作统计图表前我们要做好的工作有 (搜集资料、整理数据)。

    统计图是利用点、线、面、体等绘制成几何图形,以表示各种数量间的关系及其变动情况的工具。表现统计数字大小和变动的各种图形总称。其中有条形统计图、扇形统计图、折线统计图、象形图等。在统计学中把利用统计图形表现统计资料的方法叫做统计图示法。

    28b40aec5ad2cc091fd6cab0d1e26a82.png

    扩展资料:

    统计图基本类型

    (1)条图:又称直条图,表示独立指标在不同阶段的情况,有两维或多维,图例位于右上方。

    (2)百分条图和圆图:描述百分比(构成比)的大小,用颜色或各种图形将不同比例表达出来。

    (3)线图:用线条的升降表示事物的发展变化趋势,主要用于计量资料,描述两个变量间关系。

    (4)半对数线图:纵轴用对数尺度,描述一组连续性资料的变化速度及趋势。

    (5)直方图:描述计量资料的频数分布。

    (6)散点图:描述两种现象的相关关系。

    (7)统计地图:描述某种现象的地域分布。

    参考资料:百度百科-统计图

    word文档怎么制作条形统计图

    方法/步骤

    首先呢,在桌面空白处右击鼠标点击“新建”中的“Microsoft Word文档”(看下图),这就是新建word文档,然后双击打开

    然后呢,打开word文档,找到菜单“插入”中的“图表”点击进入(看下图)

    d788d43f8794a4c27d7514d405f41bd5ac6e39fe.jpg

    谁能告诉我怎么在word上做圆形统计图。

    工具/材料:电脑、WORD。

    第一步,打开电脑进入桌面,打开软件进界面。

    10dfa9ec8a136327ff1377ae9f8fa0ec09fac7b5.jpg

    Word文档怎样制作统计图表

    方法/步骤

    登录需要编辑的文档,点击插入

    a8ec8a13632762d063481d92acec08fa513dc6ad.jpg

    ai的环形统计图怎么制作

    1、首先把扇形图画出来,再复制一层;

    2、 然后双击混合工具会出现个对话框;

    3、 分别点两个图层, 就可以做出来了。

    扇形统计图是用整个圆表示总数(单位“1”),用圆内各个扇形的大小表示各部分量占总量的百分之几,扇形统计图中各部分的百分比之和是单位“1”。通过扇形统计图可以很清楚地表示出各部分数量与总数之间的关系。与折线统计图不同的是,不能反应数量变化趋势;与条形统计图不同的是,不能很容易看出各种数量的多少。

    展开全文
  • Excel折线图面积图模板-销量面积累计统计表Excel图表
  • 整理数据和图表,导入到一份规范化的word中 准备工作 需求并不是很明确,就先实现word导出,我采用的是freemarker 首先:搭建一个boot项目 添加pom中的包 <!--web模块用作测试请求--> <...
    • 功能介绍

    1. 需求由来

           整理数据和图表,导入到一份规范化的word中

    1. 准备工作

          需求并不是很明确,就先实现word导出,我采用的是freemarker

          首先:搭建一个boot项目 

          添加pom中的包

       <!--web模块用作测试请求-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
     <!-- freemarker 模版引擎 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>
      <!-- fastjson-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.44</version>
            </dependency>
          <!--thymeleaf,方便页面数据传输-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
     <!--jquery-->
            <dependency>
                <groupId>org.webjars</groupId>
                <artifactId>jquery</artifactId>
                <version>3.4.0</version>
            </dependency>

       创建word模板

       记得一定要用office,不然导出的word可能会出现损坏

        接着在word中输入一些信息,如文字,表格等

       

       将文件另存为xml格式,最好是word2003的xml这样,高版本低配低版本的特性,保证下载下来的word都能用

      保存后用记事本打开这个xml文件,复制出来,去网上随便找个网站吧xml格式化一下,这样方便我们去阅读

    我这里经常用格式化的在线网址:http://www.bejson.com/otherformat/xml/

    在项目中创建一个.ftl结尾的文件,将刚刚格式化好的xml复制进去

    创建一个Controller方法,方便外部访问,这是测试方法

        private final ExportUtil exportUtil;
        @Autowired
        public WordController(ExportUtil exportUtil) {
            this.exportUtil = exportUtil;
        }
    
        @RequestMapping(value = "/wordDownload")
        public void wordDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
            Map<String, Object> map=new HashMap<>();
            map.put("title","hello ! ! 我是一个标题");
            List<Map<String, Object>> excelInfo=new ArrayList<>();
            for (int i=0;i<3;i++){
                Map<String, Object> info=new HashMap<>();
                info.put("name","张"+i);
                info.put("info","我是第"+i+"个介绍");
                excelInfo.add(info);
            }
            map.put("excelInfo",excelInfo);
            exportUtil.exportTemplateWord(response,request,map,"测试","word/Template.ftl");
        }
    

    基于freemarker工具类exportUtil

    package com.qxl.wordexport.util;
    
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.util.StringUtils;
    
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    import java.net.URLEncoder;
    import java.time.LocalDateTime;
    import java.util.Map;
    
    /**
     * @program: hotline
     * @author: Fulin
     * @create: 2018-12-10 17:59
     **/
    @Component
    public class ExportUtil {
    
        private static final String ENCODING = "utf-8";
        private static final String WORD_CONTENTTYPE = "application/msword";
    
        private static final String EXCEL_CONTENTTYPE = "application/x-download";
    
    
        //    private static final String BASE_PATH = ClassUtils.getDefaultClassLoader().getResourceAsStream()
        private static final String TEMPLATEFOLDER = BASE_PATH + File.separator + "templates";
    //    private static final String TEMPLATEFOLDER = BASE_PATH;
    
      /*  private static Configuration configuration;
    
        static {
            configuration = new Configuration(Configuration.VERSION_2_3_28);
            configuration.setDefaultEncoding("utf-8");
            try {
                configuration.setDirectoryForTemplateLoading(new File("/word"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    */
        private final Configuration configuration; //freeMarker configuration
    
        @Autowired
        public ExportUtil(Configuration configuration) {
            this.configuration = configuration;
        }
    
    
        /**
         * freemarker模版导出word
         *
         * @param response 响应
         * @param map      数据
         * @param title    标题
         * @param ftlFile  文件路径 templates 目录下的
         * @throws IOException IO异常
         */
        public  void exportTemplateWord(HttpServletResponse response, HttpServletRequest request, Map map, String title, String ftlFile) throws IOException {
            Template freemarkerTemplate = configuration.getTemplate(ftlFile);
            File file;
            String fileName = title+LocalDateTime.now().toString() + ".doc";
            if (!StringUtils.isEmpty(title)) {
                fileName = title + ".doc";
                if (isIE(request)) {
                    fileName = URLEncoder.encode(fileName, "UTF8");
                } else {
                    fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
                }
            }
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType(WORD_CONTENTTYPE);
            response.setCharacterEncoding(ENCODING);
            file = createDoc(map, freemarkerTemplate);
            //java7的新回收特性
            tempBuffer(response, file);
        }
    
        /**
         * freemarker模版导出excel
         *
         * @param response 响应
         * @param map      数据
         * @param title    标题
         * @param ftlFile  文件路径 templates 目录下的
         * @throws IOException IO异常
         */
        public  void exportTemplateExcel(HttpServletResponse response, Map map, String title, String ftlFile) throws IOException {
            Template freemarkerTemplate = configuration.getTemplate(ftlFile);
            File file;
            String fileName = title + LocalDateTime.now().toString() + ".xls";
            response.setHeader("Content-Disposition", "attachment;filename="
                    .concat(String.valueOf(URLEncoder.encode(fileName, ENCODING))));
            response.setContentType(EXCEL_CONTENTTYPE);
            response.setCharacterEncoding(ENCODING);
            file = createDoc(map, freemarkerTemplate);
            tempBuffer(response, file);
        }
    
        private static void tempBuffer(HttpServletResponse response, File file) throws IOException {
            //java7的新回收特性
            try (InputStream fin = new FileInputStream(file); ServletOutputStream out = response.getOutputStream()) {
                // 调用工具类的createDoc方法生成Word文档
                // 设置浏览器以下载的方式处理该文件名
                byte[] buffer = new byte[1024];  // 缓冲区
                int bytesToRead = -1;
                // 通过循环将读入的Word文件的内容输出到浏览器中
                while ((bytesToRead = fin.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesToRead);
                }
            } finally {
                if (file != null) {
                    boolean delete = file.delete();
                }
            }
        }
    
        private static File createDoc(Map<?, ?> dataMap, Template template) {
            String name = "temp";
            File f = new File(name);
            try {
                //这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开
                Writer w = new OutputStreamWriter(new FileOutputStream(f), ENCODING);
                template.process(dataMap, w);
                w.close();
            } catch (Exception ex) {
                ex.printStackTrace();
                throw new RuntimeException(ex);
            }
            return f;
        }
    
        private static boolean isIE(HttpServletRequest request) {
            return request.getHeader("USER-AGENT").toLowerCase().indexOf("msie") > 0 || request.getHeader("USER-AGENT").toLowerCase().indexOf("rv:11.0") > 0 || request.getHeader("USER-AGENT").toLowerCase().indexOf("edge") > 0;
        }
    
    }
    

    接着将map中的数据填充在word模板中,打开之前创建的  .ftl   结尾的文件,找到正文

    将这个文字替换成freemarker的表达式,取出我们的传进来数据

    访问我们项目路径:http://127.0.0.1:8080/wordDownload

    文件下载完毕,打开发现我们后台传过去标题也在上面了

    导出word功能已经完成,接着进行其他功能的实现

     

    • 开始制作

        制作word模板

          创建word文档,记得一定要用office

    另存为2003xml,后记事本打开,粘贴格式化后,项目中创建   .ftl    结尾文件,把格式化好的xml文件放进   .ftl 文件中

    <w:binData>中存放的是图片的base64编码,我们可以把他粘贴出来去在线解析网站中看一下是不是我们之前放的图片

     

    我常用在线解析网站:http://imgbase64.duoshitong.com/

    在这需要加上前缀   data:image/png;base64,      后面跟上<w:binData>标签内的字符串,效果如下

    这么说,我们只需要将往ftl文件对应的<w:binData>标签中放入图片的base64编码就可以,于是我开始想办法去获取图表的base64编码

      1.试用echarts

    echarts在平时用的比较多,所以打算先用echarts实现,先去官网找相关的js和文档,通过文档我们找到了这样一个方法,可以直接获取图表的base64编码,但是有一点需要注意,就是图表需要去除动画效果,不然无法获取   去除方法为        animation:false

    下面粘贴一下我测试页面代码,我在控制到打印一下我想要的信息

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.springframework.org/schema/mvc">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script th:src="@{/echarts/echarts.min.js}"></script>
        <script th:src="@{/webjars/jquery/3.4.0/jquery.js}"></script>
    </head>
    <body>
    <div id="myChart" style="width: 600px;height:600px;"></div>
    <script type="text/javascript">
        $(function () {
            echartsDemo();
        });
    
        function echartsDemo() {
            var myChart = echarts.init(document.getElementById("myChart"));
            option = {
                title : {
                    text: '某站点用户访问来源',
                    subtext: '纯属虚构',
                    x:'center'
                },
                tooltip : {
                    trigger: 'item',
                    formatter: "{a} <br/>{b} : {c} ({d}%)"
                },
                legend: {
                    orient: 'vertical',
                    left: 'left',
                    data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']
                },
                series : [
                    {
                        name: '访问来源',
                        type: 'pie',
                        radius : '75%',
                        center: ['50%', '50%'],
                        data:[
                            {value:335, name:'直接访问'},
                            {value:310, name:'邮件营销'},
                            {value:234, name:'联盟广告'},
                            {value:135, name:'视频广告'},
                            {value:1548, name:'搜索引擎'}
                        ],
                        itemStyle: {
                            emphasis: {
                                shadowBlur: 10,
                                shadowOffsetX: 0,
                                shadowColor: 'rgba(0, 0, 0, 0.5)'
                            }
                        }
                    }
                ],
                animation:false
            };
            myChart.setOption(option);
            var imgData = myChart.getConnectedDataURL();
            console.log(imgData);
        }
    </script>
    </body>
    </html>

    拿到生成的base64编码,去看一下对不对

    粘贴后,放入之前转码网站,发现没问题,现在只需要把这段base64编码提交到后台,放入ftl模板中,我们的word导出功能就做完了

     

    功能都实现了,那么是不是就结束了呢,不,这只是刚刚开始,由于任务布置的时候只是让实现功能,布置任务的人给我说,项目中的图表是用highcharts

        2.试用highcharts

    第一次用highcharts,我就去官网看了半天,发现只有一个图片下载的方法,但是这个图片我是拿不到的,我只能换一种思路,用外部的插件,去网上找了半天最后选取了 canvg.js,还有一种是html2canvas.min.js,这里我介绍canvg.js的实现,如果有兴趣可以自己研究一下另外一种,下面是他的前段代码

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script th:src="@{/webjars/jquery/3.4.0/jquery.js}"></script>
        <script th:src="@{/highcharts/highcharts.js}"></script>
        <script th:src="@{/highcharts/exporting.js}"></script>
        <script th:src="@{/canvg/canvg.js}"></script>
    </head>
    <body>
    <h1>首页</h1>
    
    <div id="hightCharts"></div>
    
    <canvas id="canvasId" style="display: none"></canvas>
    
    <script type="text/javascript">
    
        Highcharts.chart('hightCharts', {
            chart: {
                plotBackgroundColor: null,
                plotBorderWidth: null,
                plotShadow: false,
                type: 'pie'
            },
            title: {
                text: '2018年1月浏览器市场份额'
            },
            tooltip: {
                pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
            },
            plotOptions: {
                pie: {
                    allowPointSelect: true,
                    cursor: 'pointer',
                    dataLabels: {
                        enabled: true,
                        format: '<b>{point.name}</b>: {point.percentage:.1f} %',
                        style: {
                            color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
                        }
                    }
                }
            },
            series: [{
                name: 'Brands',
                colorByPoint: true,
                data: [{
                    name: 'Chrome',
                    y: 61.41,
                    sliced: true,
                    selected: true
                }, {
                    name: 'Internet Explorer',
                    y: 11.84
                }, {
                    name: 'Firefox',
                    y: 10.85
                }, {
                    name: 'Edge',
                    y: 4.67
                }, {
                    name: 'Safari',
                    y: 4.18
                }, {
                    name: 'Sogou Explorer',
                    y: 1.64
                }, {
                    name: 'Opera',
                    y: 1.6
                }, {
                    name: 'QQ',
                    y: 1.2
                }, {
                    name: 'Other',
                    y: 2.61
                }]
            }]
        });
        var chartData = $("#hightCharts").highcharts().getSVG();
        canvg(canvasId,chartData);
        function convertCanvas(canvas) {
            var image = new Image();
            image.src = canvas.toDataURL("image/png");
            return image
        }
        var canvas = document.createElement('canvasId');
        var imageData = convertCanvas(canvasId).src;
        console.log(imageData);
    
    </script>
    </body>
    </html>

    在控制台上拿到打印的信息,放到在线解码网站,图片生成成功,另外我这找到另外一种后台的生成方法,挺好用的,但是如果生成多张图片,可能会比较麻烦,因为这篇文章中把前台单独生成了一个项目,以请求的方式拿到图片,这是链接

    弄了这么多感觉已经到了尾声,终于,我拿到了项目!发现项目里压根没有highcharts,但是我找到了amchart(此处应有黑人感叹号!!!),这是什么鬼,我一搞后台的,用了这么多前台的插件,但是还没完成?!算了,继续看amchart吧

        3.试用amchart

    心平气和去amchart官网翻文档,中间踩的坑就不多说了,下面是官方文档给的方法

    接着是我的前段代码

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script th:src="@{/webjars/jquery/3.4.0/jquery.js}"></script>
        <!-- Resources -->
        <script src="https://www.amcharts.com/lib/4/core.js"></script>
        <script th:src="@{/amcharts/charts.js}"></script>
    </head>
    <body>
    <h1>首页</h1>
        <!-- HTML -->
        <div id="chartdiv" style="width: 100%;height: 500px"></div>
    
    <script type="text/javascript">
            $(function () {
                aaa();
            });
            function aaa() {
                var chart = am4core.create("chartdiv", am4charts.PieChart);
                chart.data = [ {
                    "country": "Lithuania",
                    "litres": 501.9
                }, {
                    "country": "Czech Republic",
                    "litres": 301.9
                }, {
                    "country": "Ireland",
                    "litres": 201.1
                }, {
                    "country": "Germany",
                    "litres": 165.8
                }, {
                    "country": "Australia",
                    "litres": 139.9
                }, {
                    "country": "Austria",
                    "litres": 128.3
                }, {
                    "country": "UK",
                    "litres": 99
                }, {
                    "country": "Belgium",
                    "litres": 60
                }, {
                    "country": "The Netherlands",
                    "litres": 50
                } ];
                var pieSeries = chart.series.push(new am4charts.PieSeries());
                pieSeries.dataFields.value = "litres";
                pieSeries.dataFields.category = "country";
                chart.exporting.getImage("png").then(function(imgData) {
                    console.log(imgData);
                });
    
            }
    
    </script>
    </body>
    </html>

    控制台拿到打印信息,没问题

        4.坑爹的IE7

    这回总可以了吧,欣喜的跑起项目,看着项目再跑,总觉得事情没有这么简单,果然Chrome不兼容,赶紧过去问了一下,适用于IE,并且还要是兼容模式,赶紧打开IE调试兼容模式,看到默认是IE7,心里已经凉了半截,因为这几个图表只能适用于IE9+,我试试看调高一点的版本,结果凉凉,突然想到项目里用的是amchart,那么我amchart一定是能用的,兴奋赶紧去尝试一下,发现项目中amchart是老版本,新版本的方法不兼容,凉透了,脑中灵光一现,不是还有一个html2canvas.js嘛,麻溜的就去官网看,结果发现,最低适配到IE9,这可咋整,难道天要亡我?不行不行,我又去任务发布人哪里问了一下,能不能不用amchart,因为我实现不了,他说可以呀,只要基础的饼图,柱状图,折线图有就行,别太丑美观一点的。之前朋友说有java纯后台生成的图表,我网上了解了一下,有个jfreechart的,感觉可以试试.....

        5.jfreechart

    已经到这个时候了,没有退路了,硬着头皮试试呗,看了几篇博客,总结了一下,发现挺简单的,用的pom包

    <!--jfreechart-->
    <dependency>
        <groupId>jfree</groupId>
        <artifactId>jfreechart</artifactId>
        <version>1.0.13</version>
    </dependency>

    借鉴别人优化的图表样式

    package com.qxl.wordexport.util;
    
    import com.qxl.wordexport.entity.Serie;
    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.StandardChartTheme;
    import org.jfree.chart.axis.DateAxis;
    import org.jfree.chart.axis.DateTickUnit;
    import org.jfree.chart.axis.DateTickUnitType;
    import org.jfree.chart.axis.ValueAxis;
    import org.jfree.chart.block.BlockBorder;
    import org.jfree.chart.labels.*;
    import org.jfree.chart.plot.*;
    import org.jfree.chart.renderer.category.BarRenderer;
    import org.jfree.chart.renderer.category.LineAndShapeRenderer;
    import org.jfree.chart.renderer.category.StackedBarRenderer;
    import org.jfree.chart.renderer.category.StandardBarPainter;
    import org.jfree.chart.renderer.xy.StandardXYBarPainter;
    import org.jfree.chart.renderer.xy.XYBarRenderer;
    import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
    import org.jfree.data.category.DefaultCategoryDataset;
    import org.jfree.data.general.DefaultPieDataset;
    import org.jfree.data.time.Day;
    import org.jfree.data.time.TimeSeries;
    import org.jfree.ui.RectangleInsets;
    import org.jfree.ui.TextAnchor;
    
    import java.awt.*;
    import java.text.DecimalFormat;
    import java.text.NumberFormat;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Vector;
    
    /**
     * Jfreechart工具类
     * <p>
     * 解决中午乱码问题<br>
     * 用来创建类别图表数据集、创建饼图数据集、时间序列图数据集<br>
     * 用来对柱状图、折线图、饼图、堆积柱状图、时间序列图的样式进行渲染<br>
     * 设置X-Y坐标轴样式
     * <p>
     * 引自文章:https://www.liangzl.com/get-article-detail-26733.html
     *
     */
    
    public class JfreeChartStyle {
        private static String NO_DATA_MSG = "数据加载失败";
        private static Font FONT = new Font("宋体", Font.PLAIN, 12);
        public static Color[] CHART_COLORS = {
                new Color(31,129,188), new Color(92,92,97), new Color(144,237,125), new Color(255,188,117),
                new Color(153,158,255), new Color(255,117,153), new Color(253,236,109), new Color(128,133,232),
                new Color(158,90,102),new Color(255, 204, 102) };// 颜色
    
        static {
            setChartTheme();
        }
    
        public JfreeChartStyle() {
        }
    
        /**
         * 中文主题样式 解决乱码
         */
        public static void setChartTheme() {
            // 设置中文主题样式 解决乱码
            StandardChartTheme chartTheme = new StandardChartTheme("CN");
            // 设置标题字体
            chartTheme.setExtraLargeFont(FONT);
            // 设置图例的字体
            chartTheme.setRegularFont(FONT);
            // 设置轴向的字体
            chartTheme.setLargeFont(FONT);
            chartTheme.setSmallFont(FONT);
            chartTheme.setTitlePaint(new Color(51, 51, 51));
            chartTheme.setSubtitlePaint(new Color(85, 85, 85));
    
            chartTheme.setLegendBackgroundPaint(Color.WHITE);// 设置标注
            chartTheme.setLegendItemPaint(Color.BLACK);//
            chartTheme.setChartBackgroundPaint(Color.WHITE);
            // 绘制颜色绘制颜色.轮廓供应商
            // paintSequence,outlinePaintSequence,strokeSequence,outlineStrokeSequence,shapeSequence
    
            Paint[] OUTLINE_PAINT_SEQUENCE = new Paint[] { Color.WHITE };
            // 绘制器颜色源
            DefaultDrawingSupplier drawingSupplier = new DefaultDrawingSupplier(CHART_COLORS, CHART_COLORS, OUTLINE_PAINT_SEQUENCE,
                    DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE, DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
                    DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE);
            chartTheme.setDrawingSupplier(drawingSupplier);
    
            chartTheme.setPlotBackgroundPaint(Color.WHITE);// 绘制区域
            chartTheme.setPlotOutlinePaint(Color.WHITE);// 绘制区域外边框
            chartTheme.setLabelLinkPaint(new Color(8, 55, 114));// 链接标签颜色
            chartTheme.setLabelLinkStyle(PieLabelLinkStyle.CUBIC_CURVE);
    
            chartTheme.setAxisOffset(new RectangleInsets(5, 12, 5, 12));
            chartTheme.setDomainGridlinePaint(new Color(192, 208, 224));// X坐标轴垂直网格颜色
            chartTheme.setRangeGridlinePaint(new Color(192, 192, 192));// Y坐标轴水平网格颜色
    
            chartTheme.setBaselinePaint(Color.WHITE);
            chartTheme.setCrosshairPaint(Color.BLUE);// 不确定含义
            chartTheme.setAxisLabelPaint(new Color(51, 51, 51));// 坐标轴标题文字颜色
            chartTheme.setTickLabelPaint(new Color(67, 67, 72));// 刻度数字
            chartTheme.setBarPainter(new StandardBarPainter());// 设置柱状图渲染
            chartTheme.setXYBarPainter(new StandardXYBarPainter());// XYBar 渲染
    
            chartTheme.setItemLabelPaint(Color.black);
            chartTheme.setThermometerPaint(Color.white);// 温度计
    
            ChartFactory.setChartTheme(chartTheme);
        }
    
        /**
         * 必须设置文本抗锯齿
         */
        public static void setAntiAlias(JFreeChart chart) {
            chart.setTextAntiAlias(false);
    
        }
    
        /**
         * 设置图例无边框,默认黑色边框
         */
        public static void setLegendEmptyBorder(JFreeChart chart) {
            chart.getLegend().setFrame(new BlockBorder(Color.WHITE));
    
        }
    
        /**
         * 创建类别数据集合
         */
        public static DefaultCategoryDataset createDefaultCategoryDataset(Vector<Serie> series, String[] categories) {
            DefaultCategoryDataset dataset = new DefaultCategoryDataset();
    
            for (Serie serie : series) {
                String name = serie.getName();
                Vector<Object> data = serie.getData();
                if (data != null && categories != null && data.size() == categories.length) {
                    for (int index = 0; index < data.size(); index++) {
                        String value = data.get(index) == null ? "" : data.get(index).toString();
                        if (isPercent(value)) {
                            value = value.substring(0, value.length() - 1);
                        }
                        if (isNumber(value)) {
                            dataset.setValue(Double.parseDouble(value), name, categories[index]);
                        }
                    }
                }
    
            }
            return dataset;
    
        }
    
        /**
         * 创建饼图数据集合
         */
        public static DefaultPieDataset createDefaultPieDataset(String[] categories, Object[] datas) {
            DefaultPieDataset dataset = new DefaultPieDataset();
            for (int i = 0; i < categories.length && categories != null; i++) {
                String value = datas[i].toString();
                if (isPercent(value)) {
                    value = value.substring(0, value.length() - 1);
                }
                if (isNumber(value)) {
                    dataset.setValue(categories[i], Double.valueOf(value));
                }
            }
            return dataset;
    
        }
    
        /**
         * 创建时间序列数据
         *
         * @param category
         *            类别
         * @param dateValues
         *            日期-值 数组
         * @param xAxisTitle
         *            X坐标轴标题
         * @return
         */
        public static TimeSeries createTimeseries(String category, Vector<Object[]> dateValues) {
            TimeSeries timeseries = new TimeSeries(category);
    
            if (dateValues != null) {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                for (Object[] objects : dateValues) {
                    Date date = null;
                    try {
                        date = dateFormat.parse(objects[0].toString());
                    } catch (ParseException e) {
                    }
                    String sValue = objects[1].toString();
                    double dValue = 0;
                    if (date != null && isNumber(sValue)) {
                        dValue = Double.parseDouble(sValue);
                        timeseries.add(new Day(date), dValue);
                    }
                }
            }
    
            return timeseries;
        }
    
        /**
         * 设置 折线图样式
         *
         * @param plot
         * @param isShowDataLabels
         *            是否显示数据标签 默认不显示节点形状
         */
        public static void setLineRender(CategoryPlot plot, boolean isShowDataLabels) {
            setLineRender(plot, isShowDataLabels, false);
        }
    
        /**
         * 设置折线图样式
         *
         * @param plot
         * @param isShowDataLabels
         *            是否显示数据标签
         */
        public static void setLineRender(CategoryPlot plot, boolean isShowDataLabels, boolean isShapesVisible) {
            plot.setNoDataMessage(NO_DATA_MSG);
            plot.setInsets(new RectangleInsets(10, 10, 0, 10), false);
            LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
    
            renderer.setStroke(new BasicStroke(1.5F));
            if (isShowDataLabels) {
                renderer.setBaseItemLabelsVisible(true);
                renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator(StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING,
                        NumberFormat.getInstance()));
                renderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1, TextAnchor.BOTTOM_CENTER));// weizhi
            }
            renderer.setBaseShapesVisible(isShapesVisible);// 数据点绘制形状
            setXAixs(plot);
            setYAixs(plot);
    
        }
    
        /**
         * 设置时间序列图样式
         *
         * @param plot
         * @param isShowData
         *            是否显示数据
         * @param isShapesVisible
         *            是否显示数据节点形状
         */
        public static void setTimeSeriesRender(Plot plot, boolean isShowData, boolean isShapesVisible) {
    
            XYPlot xyplot = (XYPlot) plot;
            xyplot.setNoDataMessage(NO_DATA_MSG);
            xyplot.setInsets(new RectangleInsets(10, 10, 5, 10));
    
            XYLineAndShapeRenderer xyRenderer = (XYLineAndShapeRenderer) xyplot.getRenderer();
    
            xyRenderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
            xyRenderer.setBaseShapesVisible(false);
            if (isShowData) {
                xyRenderer.setBaseItemLabelsVisible(true);
                xyRenderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
                xyRenderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1, TextAnchor.BOTTOM_CENTER));// weizhi
            }
            xyRenderer.setBaseShapesVisible(isShapesVisible);// 数据点绘制形状
    
            DateAxis domainAxis = (DateAxis) xyplot.getDomainAxis();
            domainAxis.setAutoTickUnitSelection(false);
            DateTickUnit dateTickUnit = new DateTickUnit(DateTickUnitType.YEAR, 1, new SimpleDateFormat("yyyy-MM")); // 第二个参数是时间轴间距
            domainAxis.setTickUnit(dateTickUnit);
    
            StandardXYToolTipGenerator xyTooltipGenerator = new StandardXYToolTipGenerator("{1}:{2}", new SimpleDateFormat("yyyy-MM-dd"), new DecimalFormat("0"));
            xyRenderer.setBaseToolTipGenerator(xyTooltipGenerator);
    
            setXY_XAixs(xyplot);
            setXY_YAixs(xyplot);
    
        }
    
        /**
         * 设置时间序列图样式 -默认不显示数据节点形状
         *
         * @param plot
         * @param isShowData
         *            是否显示数据
         */
    
        public static void setTimeSeriesRender(Plot plot, boolean isShowData) {
            setTimeSeriesRender(plot, isShowData, false);
        }
    
        /**
         * 设置时间序列图渲染:但是存在一个问题:如果timeseries里面的日期是按照天组织, 那么柱子的宽度会非常小,和直线一样粗细
         *
         * @param plot
         * @param isShowDataLabels
         */
    
        public static void setTimeSeriesBarRender(Plot plot, boolean isShowDataLabels) {
    
            XYPlot xyplot = (XYPlot) plot;
            xyplot.setNoDataMessage(NO_DATA_MSG);
    
            XYBarRenderer xyRenderer = new XYBarRenderer(0.1D);
            xyRenderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
    
            if (isShowDataLabels) {
                xyRenderer.setBaseItemLabelsVisible(true);
                xyRenderer.setBaseItemLabelGenerator(new StandardXYItemLabelGenerator());
            }
    
            StandardXYToolTipGenerator xyTooltipGenerator = new StandardXYToolTipGenerator("{1}:{2}", new SimpleDateFormat("yyyy-MM-dd"), new DecimalFormat("0"));
            xyRenderer.setBaseToolTipGenerator(xyTooltipGenerator);
            setXY_XAixs(xyplot);
            setXY_YAixs(xyplot);
    
        }
    
        /**
         * 设置柱状图渲染
         *
         * @param plot
         * @param isShowDataLabels
         */
        public static void setBarRenderer(CategoryPlot plot, boolean isShowDataLabels) {
    
            plot.setNoDataMessage(NO_DATA_MSG);
            plot.setInsets(new RectangleInsets(10, 10, 5, 10));
            BarRenderer renderer = (BarRenderer) plot.getRenderer();
            renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            renderer.setMaximumBarWidth(0.075);// 设置柱子最大宽度
    
            if (isShowDataLabels) {
                renderer.setBaseItemLabelsVisible(true);
            }
    
            setXAixs(plot);
            setYAixs(plot);
        }
    
        /**
         * 设置堆积柱状图渲染
         *
         * @param plot
         */
    
        public static void setStackBarRender(CategoryPlot plot) {
            plot.setNoDataMessage(NO_DATA_MSG);
            plot.setInsets(new RectangleInsets(10, 10, 5, 10));
            StackedBarRenderer renderer = (StackedBarRenderer) plot.getRenderer();
            renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            plot.setRenderer(renderer);
            setXAixs(plot);
            setYAixs(plot);
        }
    
        /**
         * 设置类别图表(CategoryPlot) X坐标轴线条颜色和样式
         *
         * @param axis
         */
        public static void setXAixs(CategoryPlot plot) {
            Color lineColor = new Color(31, 121, 170);
            plot.getDomainAxis().setAxisLinePaint(lineColor);// X坐标轴颜色
            plot.getDomainAxis().setTickMarkPaint(lineColor);// X坐标轴标记|竖线颜色
    
        }
    
        /**
         * 设置类别图表(CategoryPlot) Y坐标轴线条颜色和样式 同时防止数据无法显示
         *
         * @param axis
         */
        public static void setYAixs(CategoryPlot plot) {
            Color lineColor = new Color(192, 208, 224);
            ValueAxis axis = plot.getRangeAxis();
            axis.setAxisLinePaint(lineColor);// Y坐标轴颜色
            axis.setTickMarkPaint(lineColor);// Y坐标轴标记|竖线颜色
            // 隐藏Y刻度
            axis.setAxisLineVisible(false);
            axis.setTickMarksVisible(false);
            // Y轴网格线条
            plot.setRangeGridlinePaint(new Color(192, 192, 192));
            plot.setRangeGridlineStroke(new BasicStroke(1));
    
            plot.getRangeAxis().setUpperMargin(0.1);// 设置顶部Y坐标轴间距,防止数据无法显示
            plot.getRangeAxis().setLowerMargin(0.1);// 设置底部Y坐标轴间距
    
        }
    
        /**
         * 设置XY图表(XYPlot) X坐标轴线条颜色和样式
         *
         * @param axis
         */
        public static void setXY_XAixs(XYPlot plot) {
            Color lineColor = new Color(31, 121, 170);
            plot.getDomainAxis().setAxisLinePaint(lineColor);// X坐标轴颜色
            plot.getDomainAxis().setTickMarkPaint(lineColor);// X坐标轴标记|竖线颜色
    
        }
    
        /**
         * 设置XY图表(XYPlot) Y坐标轴线条颜色和样式 同时防止数据无法显示
         *
         * @param axis
         */
        public static void setXY_YAixs(XYPlot plot) {
            Color lineColor = new Color(192, 208, 224);
            ValueAxis axis = plot.getRangeAxis();
            axis.setAxisLinePaint(lineColor);// X坐标轴颜色
            axis.setTickMarkPaint(lineColor);// X坐标轴标记|竖线颜色
            // 隐藏Y刻度
            axis.setAxisLineVisible(false);
            axis.setTickMarksVisible(false);
            // Y轴网格线条
            plot.setRangeGridlinePaint(new Color(192, 192, 192));
            plot.setRangeGridlineStroke(new BasicStroke(1));
            plot.setDomainGridlinesVisible(false);
    
            plot.getRangeAxis().setUpperMargin(0.12);// 设置顶部Y坐标轴间距,防止数据无法显示
            plot.getRangeAxis().setLowerMargin(0.12);// 设置底部Y坐标轴间距
    
        }
    
        /**
         * 设置饼状图渲染
         */
        public static void setPieRender(Plot plot) {
    
            plot.setNoDataMessage(NO_DATA_MSG);
            plot.setInsets(new RectangleInsets(10, 10, 5, 10));
            PiePlot piePlot = (PiePlot) plot;
            piePlot.setInsets(new RectangleInsets(0, 0, 0, 0));
            piePlot.setCircular(true);// 圆形
    
            // piePlot.setSimpleLabels(true);// 简单标签
            piePlot.setLabelGap(0.01);
            piePlot.setInteriorGap(0.05D);
            piePlot.setLegendItemShape(new Rectangle(10, 10));// 图例形状
            piePlot.setIgnoreNullValues(true);
            piePlot.setLabelBackgroundPaint(null);// 去掉背景色
            piePlot.setLabelShadowPaint(null);// 去掉阴影
            piePlot.setLabelOutlinePaint(null);// 去掉边框
            piePlot.setShadowPaint(null);
            // 0:category 1:value:2 :percentage
            piePlot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}:{2}"));// 显示标签数据
        }
    
        /**
         * 是不是一个%形式的百分比
         *
         * @param str
         * @return
         */
        public static boolean isPercent(String str) {
            return str != null ? str.endsWith("%") && isNumber(str.substring(0, str.length() - 1)) : false;
        }
    
        /**
         * 是不是一个数字
         *
         * @param str
         * @return
         */
        public static boolean isNumber(String str) {
            return str != null ? str.matches("^[-+]?(([0-9]+)((([.]{0})([0-9]*))|(([.]{1})([0-9]+))))$") : false;
        }
    
    }
    

    自己简单封装了一下饼图,柱状图和折线图的调用方法

    package com.qxl.wordexport.util;
    
    import com.qxl.wordexport.entity.Serie;
    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartUtilities;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.plot.CategoryPlot;
    import org.jfree.chart.plot.PlotOrientation;
    import org.jfree.data.category.CategoryDataset;
    import org.jfree.data.general.DefaultPieDataset;
    import sun.misc.BASE64Encoder;
    
    import java.awt.*;
    import java.io.*;
    import java.util.Date;
    import java.util.Locale;
    import java.util.Vector;
    
    
    /**
     * jfreechart生成工具类
     * 生成效果:在指定目录下生成png图片,生成图片base64码
     * 可生成类型:折线图,柱状图,饼图
     */
    public class JfreeChartUtil {
    
        /**
         * 图片存储位置可以写在配置文件中
         */
        private static String  CHART_IMG_FILE="E:/boot/charts/";
    
    
        /**
         * 把jfreechart生成的图片转化为base64字符串
         * @param type 判断是否统计图类型  (折线图,柱状图,饼图)
         * @param series 柱状(折线)图数据
         * @param categories 类别
         * @param data 饼图数据
         * @param tile 图表标题
         * @param categoryAxisLabel 柱状(折线)图底边信息
         * @param valueAxisLabel    柱状(折线)图左侧边信息
         * @return 返回base64图片编码
         */
        public static String getImageStr(String type, Vector<Serie> series, String[] categories, Object[] data, String tile, String categoryAxisLabel, String valueAxisLabel) throws IOException {
            JFreeChart jfreechart = null;
            if("折线图".equals(type)){
                jfreechart = createChart(series,categories,tile,categoryAxisLabel,valueAxisLabel);
            }
            if("柱状图".equals(type)){
                jfreechart = createBarChart(series,categories,tile,categoryAxisLabel,valueAxisLabel);
            }
            if("饼图".equals(type)){
                jfreechart =createPieChart(data,categories,tile);
            }
            BASE64Encoder BASE64 = new BASE64Encoder();
            ByteArrayOutputStream bas = new ByteArrayOutputStream();
            try {
                assert jfreechart != null;
                ChartUtilities.writeChartAsJPEG(bas, 1.0f, jfreechart, 400, 300, null);
                bas.flush();
                bas.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] byteArray = bas.toByteArray();
            try {
                InputStream is = new ByteArrayInputStream(byteArray);
                byteArray = new byte[is.available()];
                is.read(byteArray);
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return BASE64.encode(byteArray);
        }
    
    
    
        /**
         * jfreechart生成图片并存放在指定位置
         * @param type 判断是否统计图类型  (折线图,柱状图,饼图)
         * @param series 柱状(折线)图数据
         * @param categories 类别
         * @param data 饼图数据
         * @param tile 图表标题
         * @param categoryAxisLabel 柱状(折线)图底边信息
         * @param valueAxisLabel    柱状(折线)图左侧边信息
         */
        public static void createPng(String type, Vector<Serie> series, String[] categories, Object[] data, String tile, String categoryAxisLabel, String valueAxisLabel) {
            JFreeChart jfreechart = null;
            if("折线图".equals(type)){
                jfreechart = createChart(series,categories,tile,categoryAxisLabel,valueAxisLabel);
            }
            if("柱状图".equals(type)){
                jfreechart = createBarChart(series,categories,tile,categoryAxisLabel,valueAxisLabel);
            }
            if("饼图".equals(type)){
                jfreechart =createPieChart(data,categories,tile);
            }
            OutputStream os;
            String imgURl=CHART_IMG_FILE + (new Date()).getTime()+".png";
            try {
                os = new FileOutputStream(imgURl);
                assert jfreechart != null;
                ChartUtilities.writeChartAsPNG(os, jfreechart, 800, 400);
                os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 折线图
         */
        private static JFreeChart createChart(Vector<Serie> series, String[] categories,String tile,String categoryAxisLabel,String valueAxisLabel) {
            CategoryDataset dataset = JfreeChartStyle.createDefaultCategoryDataset(series,categories);
            //标题,x轴,y轴,数据集,图标方向,是否显示图例,是否生成工具,是否生成url
            JFreeChart line = ChartFactory.createLineChart("折线图", "时间", "销售额(百万)", dataset, PlotOrientation.VERTICAL, true,
                    true, false);
            line.setBackgroundPaint(new Color(255, 255, 255));
            //设置标题文字
            line.getTitle().setFont(new Font("黑体", Font.BOLD, 18));
            //设置底部图例字体
            line.getLegend().setItemFont(new Font("黑体", Font.BOLD, 12));
            CategoryPlot plot = line.getCategoryPlot();
            JfreeChartStyle.setLineRender(plot,true);
            JfreeChartStyle.setChartTheme();
            JfreeChartStyle.setAntiAlias(line);
            JfreeChartStyle.setLegendEmptyBorder(line);
            return line;
        }
    
    
        /**
         * 柱状图生成
         * @return 返回图表
         */
        private static JFreeChart createBarChart(Vector<Serie> series, String[] categories,String tile,String categoryAxisLabel,String valueAxisLabel){
            CategoryDataset dataset = JfreeChartStyle.createDefaultCategoryDataset(series,categories);
            //标题,x轴,y轴,数据集,图标方向,是否显示图例,是否生成工具,是否生成url
            JFreeChart barChart = ChartFactory.createBarChart(tile, categoryAxisLabel, valueAxisLabel, dataset, PlotOrientation.VERTICAL, true, true, false);
            barChart.setBackgroundPaint(new Color(255, 255, 255));
            //设置标题文字
            barChart.getTitle().setFont(new Font("黑体", Font.BOLD, 18));
            //设置底部图例字体
            barChart.getLegend().setItemFont(new Font("黑体", Font.BOLD, 12));
            CategoryPlot plot = barChart.getCategoryPlot();
            JfreeChartStyle.setBarRenderer(plot,true);
            JfreeChartStyle.setChartTheme();
            JfreeChartStyle.setAntiAlias(barChart);
            JfreeChartStyle.setLegendEmptyBorder(barChart);
            return barChart;
        }
    
        /**
         * 饼图
         */
        private static JFreeChart createPieChart(Object[] objects, String[] categories,String title){
            DefaultPieDataset dataset = JfreeChartStyle.createDefaultPieDataset(categories,objects);
            JFreeChart jFreeChart=ChartFactory.createPieChart(title, dataset,true, true,Locale.SIMPLIFIED_CHINESE);
            jFreeChart.setBackgroundPaint(new Color(255, 255, 255));
            //设置标题文字
            jFreeChart.getTitle().setFont(new Font("黑体", Font.BOLD, 18));
            //设置底部图例字体
            jFreeChart.getLegend().setItemFont(new Font("黑体", Font.BOLD, 12));
            JfreeChartStyle.setPieRender(jFreeChart.getPlot());
            return jFreeChart;
        }
    }
    

    数据实体类

    package com.qxl.wordexport.entity;
    import java.io.Serializable;
    import java.util.Vector;
    
    /**
     * 系列:名字和数据集合 构成一条曲线</br> 可以将serie看作一根线或者一根柱子:
     *
     * <p>
     * 参照JS图表来描述数据:</br> series: [{ name: 'Tokyo', data: [7.0, 6.9, 9.5, 14.5]
     * },</br> { name: 'New York', data: [-0.2, 0.8, 5.7, 11.3} ]</br>
     * </p>
     *
     */
    
    public class Serie implements Serializable {
        private static final long serialVersionUID = 1L;
        private String name;// 名字
        private Vector<Object> data;// 数据值
    
        public Serie() {
    
        }
    
        /**
         *
         * @param name
         *            名称(线条名称)
         * @param data
         *            数据(线条上的所有数据值)
         */
        public Serie(String name, Vector<Object> data) {
    
            this.name = name;
            this.data = data;
        }
    
        /**
         *
         * @param name
         *            名称(线条名称)
         * @param array
         *            数据(线条上的所有数据值)
         */
        public Serie(String name, Object[] array) {
            this.name = name;
            if (array != null) {
                data = new Vector<Object>(array.length);
                for (int i = 0; i < array.length; i++) {
                    data.add(array[i]);
                }
            }
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Vector<Object> getData() {
            return data;
        }
    
        public void setData(Vector<Object> data) {
            this.data = data;
        }
    
    }
    

    下面是我的测试方法:

        @Test
        public void test() throws IOException {
            Vector<Serie> list=new Vector<Serie>();
            //数据1
            Serie serie=new Serie();
            Vector<Object> vector=new Vector<>();
            serie.setName("苹果");
            vector.add("2");
            vector.add("8");
            vector.add("4");
            vector.add("6");
            vector.add("8");
            serie.setData(vector);
            list.add(serie);
            //数据2
            Serie serie1=new Serie();
            Vector<Object> vector1=new Vector<>();
            serie1.setName("香蕉");
            vector1.add("5");
            vector1.add("7");
            vector1.add("4");
            vector1.add("9");
            vector1.add("3");
            serie1.setData(vector1);
            list.add(serie1);
            //数据3
            Serie serie2=new Serie();
            Vector<Object> vector2=new Vector<>();
            serie2.setName("西瓜");
            vector2.add("1");
            vector2.add("3");
            vector2.add("9");
            vector2.add("8.5");
            vector2.add("7");
            serie2.setData(vector2);
            list.add(serie2);
            //类别
            String[] categories={"一月份","二月份","三月份","四月份","五月份"};
            //饼图数据
            Object[] objects={"10","20","50","10","20"};
            //生成本地图片
            JfreeChartEntity.createPng("柱状图", list, categories, null,"这是个柱状图","这是底边类别","这是侧边信息");
            JfreeChartEntity.createPng("折线图", list, categories, null,"这是个折线图","这是底边类别","这是侧边信息");
            JfreeChartEntity.createPng("饼图", null, categories, objects,"这是个饼图","这是底边类别","这是侧边信息");
            //生成base64编码
            String imgInfo=JfreeChartEntity.getImageStr("柱状图",list,categories,null,"这是个柱状图","这是底边类别","这是侧边信息");
            String imgInfo1=JfreeChartEntity.getImageStr("折线图",list,categories,null,"这是个折线图","这是底边类别","这是侧边信息");
            String imgInfo2=JfreeChartEntity.getImageStr("饼图", null, categories, objects,"这是个饼图","这是底边类别","这是侧边信息");
            System.out.println(imgInfo);
            System.out.println("===============================================");
            System.out.println(imgInfo1);
            System.out.println("===============================================");
            System.out.println(imgInfo2);
        }

    功能完成,只需要嵌入实际业务中即可

    • 总结

    这个功能难度不高,大多是因为自己粗心造成,但是功能圆满完成还是挺开心的,同时也给自己敲响了警钟,在不清楚实际开发和使用环境之前,不要贸然下手去做,不然会浪费大量的时间成本,不过我也学到了这么多前端的图表插件,也算是很好的收获了

     

    这是本人的第一篇博客,如有错误请及时帮我纠正,欢迎一起交流技术,QQ群:826953936,QQ3293403426,微信QXL777Flower

    展开全文
  • 数据可视化的爱好者Severino Ribecca,他在自己的网站上收录了 60 种可视化图表样式以及它们分别适用于什么样的场景,并且推荐了相应的制作工具。值得一看。点阵图点阵图表 (Dot Matrix Chart) 以点为单位显示离散...
  • .net生成word报表

    2016-08-08 14:00:33
    在系统里,直接引用该文件,可以进行word报表的制作,往里面添加 文字、统计图表等。这条、引用的COM组件版本 C:\Windows\assembly\GAC_MSIL\Microsoft.Office.Interop.Excel\14.0.0.0__71e9bce111e9429c\Microsoft....
  • 首先,要先准备好初始Word模板,一定要确保档能在Offce的Word中打开,因为Office是不兼容WPS的某些格式。 然后再另存为xml格式的文件,这里建议使用Word软件中的另存为xml方式,直接更改后缀名可能会乱码,确保没有...
  • 该接口可以导出两种内容形式的word文档,文档内包含有图表数据:统计表格以及数据分析的折线图、柱状图以及饼图。 由于word的导出内容,其格式及描述信息基本是固定的,只有数据和图表会动态变化,因此调研后决定...
  • emw.createWord(map, "统计表.ftl", fileName); try { response.setContentType("application/octet-stream;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder....
  • Tableau怎么制作专业图表 本文首发于博客冰山一树Sankey,去博客浏览效果更好。直接右上角搜索该标题即可 一. 统计表 1.1 不同种类的图表风格 商业周刊的图表风格 经济学人的图表风格 华尔街日报的图表风格 其他...
  • 先上几张图,感受下,什么叫信息图表,什么叫信息可视化。如果你在某个稍具规模的公司混,或者,你需要在某个特定场合展示你的数据。这种图就能大大的派上用场。它的好处显而易见:可以装逼很清晰的展示数据,化平庸...
  • 1、在word中插入一张柱状图表,会自动生成一个excel,用来填写数据,如下图所示: 根据自己的需求修改名称和数值,修改后会动态反映到word图表上,很直观,如下图所示: 这时都是以柱状图的形式出现,都是在...
  • 词云图是什么?相信很多小伙伴第一次听说这个词的时候会有这样的疑问。其实在日常生活中词云图随处可见,只是我们没有留意过而已。...下面就让我们一起来认识并学习一下怎么制作它吧。 01 什么是
  • thymeleaf制作表格的模板 1.后台 /** * @author cqh * @create 2022/5/18 15:42 */ @Controller @RequestMapping("/system/demo")//前台包地址前缀 public class demo extends BaseController { private String ...
  • WPS表格插入制作折线图表教程

    千次阅读 2020-03-20 10:28:35
    WPS表格插入制作折线图表教程 WPS表格如果单纯只是数据表,会不直观,通过图表可以把数据进行直观化显示。而今天读书屋OFFICE网陈飞老师要讲的就是如何通过WPS表格制作图表。 通过“折线图”为大家讲解WPS表格...
  • EPLAN电缆图表模板

    千次阅读 2021-01-16 06:51:16
    好文网为大家准备了关于EPLAN电缆图表模板范文,好文网里面收集了五十多篇关于好EPLAN电缆图表模板好文,希望可以帮助大家。更多关于EPLAN电缆图表模板内容请关注好文网篇一:Eplan电气图纸设计规范_终版V1.02015.好文...
  • 在文档制作excel表格的时候,为了让数据更能直观的展示进行对比和分析,我们需要一些图表来进行展示。而今天学无忧就教大家如何在excel中插入柱形图,并且同样在word绘制插入柱形图的方法。相对来说,在excel中插入...
  • word使用技巧

    2021-05-15 16:52:51
    1、Word表格自动填充在Word表格里选中要填入相同内容的单元格,单击“格式→项目符号和编号”,进入“编号”选项卡,选择任意一种样式,单击“自定义”按钮,在“自定义编号列表”窗口中“编号格式”栏内输入要填充...
  • 本篇文章主要介绍,如何使用Apache POI组件生成柱状图导出到word文档中,具体步骤看下文。 一、实现效果 Java使用POI技术生成柱状图导出到word文档中,最终生成的柱状图如下所示: 二、环境准备 编程语言:Java...
  • 简单工具Java生成Word

    2021-09-17 15:53:25
    最近有个生成Word报告的需求,把数据统计出来然后以Word的形式展示。在网上找了一些实现的技术,包括apache poi和FreeMarker,但两者对于生成word都有些许不够。apache poi提供Java程序对Microsoft Office格式档案读...
  • word精彩实例互动教程》...1、Word互动教程是一款简单、有趣、互动式的学习Office Word 2019的新工具。此应用将向您展示Word 2019的绝大部分功能点。 2、应用包含大量操作提示,指导您一步一步地实现Office Wo...
  • 转自:大数据分析和人工智能大家好,我是 Lemon可视化图表种类如此之多,什么场景下应该用什么图表展示,是一个让人头秃的难题。数据可视化的爱好者Severino Ribecca,他在自己...
  • 1.3表格制作表格制作对我来说没有什么难度,这是我们在上个学期的计算机基础中就已经学习过了,而且能够灵活应用,修饰的操作,使我以前没有接触过的知识。 我相信这一部分的内容在我今后的工作中是以会遇到的.5...
  • 导读:我们介绍过用matplotlib制作图表的一些tips,感兴趣的同学可以戳→纯干货:手把手教你用Python做数据可视化(附代码)。matplotlib是一个相当底层的工具。你可以从其基本组件中组装一个图表:数据显示(即绘图...
  • java后台导出word文档正文、表格、图片
  • 如何修缮图像瑕疵、污点 如何运用抠图技术以满足论文及幻灯片需求 照片、条带、图表的的排版 电泳条带胖瘦不一或者歪斜图片该如何处理 条带的灰度分析和测量IOD值 多图像的排版 图表制作中存在的问题 图表的修改和...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,769
精华内容 1,907
关键字:

word统计图表制作