All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.xiao1wang.wordapp.renderpolicy.ChartRenderPolicy Maven / Gradle / Ivy

package com.github.xiao1wang.wordapp.renderpolicy;

import com.deepoove.poi.policy.AbstractRenderPolicy;
import com.deepoove.poi.render.RenderContext;
import com.deepoove.poi.xwpf.NiceXWPFDocument;
import com.github.xiao1wang.wordapp.renderData.ChartRenderData;
import com.github.xiao1wang.wordapp.renderData.ChartType;
import com.github.xiao1wang.wordapp.renderData.ChartTypeData;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTAreaChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTAreaSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTAxDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDoughnutChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTLineChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTLineSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumData;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumDataSource;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumRef;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTNumVal;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieSer;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTSerTx;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTStrData;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTStrRef;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTStrVal;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTUnsignedInt;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * TODO: 图表插件
 */
public class ChartRenderPolicy extends AbstractRenderPolicy {

    private final static Logger LOGGER = LoggerFactory.getLogger(ChartRenderPolicy.class);
    private final static String sheetName = "Sheet1";
    private final static Pattern chartIdPattern = Pattern.compile("r:id=\"(.+?)\"");

    @Override
    protected boolean validate(ChartRenderData data) {
        return true;
    }

    @Override
    protected void afterRender(RenderContext context) {
        clearPlaceholder(context, false);
    }

    @Override
    public void doRender(RenderContext context) throws Exception {
        try {
            ChartRenderData chartRenderData = context.getData();
            // 如果当前对象不存在,就将图表清空
            // 动态数据
            String title = chartRenderData==null?null:chartRenderData.getTitle();
            String[] titleArr = chartRenderData==null?null:chartRenderData.getColArr();
            List list = chartRenderData==null?null:chartRenderData.getRowList();
            List chartList = chartRenderData==null?null:chartRenderData.getChartList();

            /*
            基本思路,就是先编写chart模板,然后替换模板中的图形
            替换分为两步,一个是替换excel中的内容,一个是替换图形的值
             */
            // 得到当前设置填充图表对象所在word的执行位置
            XWPFRun run = context.getRun();
            // 得到图表所在的段落
            XWPFParagraph xwpfParagraph = (XWPFParagraph) run.getParent();
            // 获取图表所在的xml数据,找到图表对应的id值
            String chartId = null;
            String graphicXml = xwpfParagraph.getRuns().get(0).getCTR().getDrawingArray(0).getInlineArray(0).getGraphic().xmlText();
            Matcher matcher = chartIdPattern.matcher(graphicXml);
            if(graphicXml.indexOf("chart") != -1 && matcher.find()) {
                chartId = matcher.group(1);
            }
            if(StringUtils.isNotBlank(chartId)) {
                // 基于文档的对照关系,找到图表对应的对象
                NiceXWPFDocument document = (NiceXWPFDocument) run.getParent().getDocument();
                POIXMLDocumentPart documentPart = document.getRelationById(chartId);
                if(documentPart != null) {
                    XWPFChart chart = (XWPFChart) documentPart;
                    CTChart ctChart = chart.getCTChart();

                    // 如果有标题,就需要设置标题
                    CTTitle ctTitle = ctChart.getTitle();
                    if(title != null && ctTitle.getTx() != null) {
                        CTTextParagraph ctTextParagraph = ctTitle.getTx().getRich().getPArray(0);
                        List rList = ctTextParagraph.getRList();
                        if(rList != null && rList.size() > 0) {
                            rList.get(0).setT(title);
                            // 将额外的标题删除掉
                            int length = rList.size();
                            for(int i=1;i partList = chart.getRelations();
                    if(partList != null && partList.size() > 0) {
                        for(POIXMLDocumentPart xlsPart : partList) {
                            String contentType = xlsPart.getPackagePart().getContentType();
                            if("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(contentType)) {
                                OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream();
                                try {
                                    workbook.write(xlsOut);
                                    xlsOut.close();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                } finally {
                                    if (workbook != null) {
                                        try {
                                            workbook.close();
                                        } catch (IOException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // 基于传递的参数,得到对应图表的信息
                    CTPlotArea plotArea = ctChart.getPlotArea();

                    //先清空改plotArea下的所有图表数据
                    //clearChart(plotArea);

                    if(chartRenderData == null) {
                        // 针对数据为null的情况,应该将图表删除掉,还未实现
                    }
                    if(chartList != null && chartList.size() > 0) {
                        for(ChartTypeData chartTypeData : chartList) {
                            ChartType chartType = chartTypeData.getChartType();
                            // 得到每种类型图表的具体数据
                            if(list != null && list.size() > 0 && chartTypeData.getStartPosition() != null && chartTypeData.getEndPosition() != null) {
                                int size = list.get(0).length;
                                if(chartTypeData.getEndPosition() < size) {
                                    // 需要保留第一个图例的样式
                                    XmlObject chartXml = null;
                                    for(int i=chartTypeData.getStartPosition(); i<=chartTypeData.getEndPosition(); i++) {
                                        CTSerTx serTx = null;
                                        CTAxDataSource catDataSource = null;
                                        CTNumDataSource valDataSource = null;
                                        // 创建一个新的系列,并添加该系列的idx,同时得到对应的变量数据
                                        switch (chartType) {
                                            case BAR:
                                                CTBarChart barChart = plotArea.getBarChartArray(0);
                                                if(chartXml == null) {
                                                    chartXml = barChart.getSerArray(0).copy();
                                                    barChart.setSerArray(null);
                                                }
                                                CTBarSer ctBarSer = barChart.addNewSer();
                                                ctBarSer.set(chartXml);
                                                CTUnsignedInt barIdx = ctBarSer.getIdx();
                                                barIdx.setVal(i-1);
                                                ctBarSer.setIdx(barIdx);
                                                serTx = ctBarSer.getTx();
                                                catDataSource = ctBarSer.getCat();
                                                valDataSource = ctBarSer.getVal();
                                                break;
                                            case LINE:
                                                CTLineChart lineChart = plotArea.getLineChartArray(0);
                                                if(chartXml == null) {
                                                    chartXml = lineChart.getSerArray(0).copy();
                                                    lineChart.setSerArray(null);
                                                }
                                                CTLineSer ctLineSer = lineChart.addNewSer();
                                                ctLineSer.set(chartXml);
                                                CTUnsignedInt lineIdx = ctLineSer.getIdx();
                                                lineIdx.setVal(i-1);
                                                ctLineSer.setIdx(lineIdx);
                                                serTx = ctLineSer.getTx();
                                                catDataSource = ctLineSer.getCat();
                                                valDataSource = ctLineSer.getVal();
                                                break;
                                            case PIE:
                                                CTPieChart pieChart = plotArea.getPieChartArray(0);
                                                if(chartXml == null) {
                                                    chartXml = pieChart.getSerArray(0).copy();
                                                    pieChart.setSerArray(null);
                                                }
                                                CTPieSer ctPieSer = pieChart.addNewSer();
                                                ctPieSer.set(chartXml);
                                                CTUnsignedInt pieIdx = ctPieSer.getIdx();
                                                pieIdx.setVal(i-1);
                                                ctPieSer.setIdx(pieIdx);
                                                serTx = ctPieSer.getTx();
                                                catDataSource = ctPieSer.getCat();
                                                valDataSource = ctPieSer.getVal();
                                                break;
                                            case AREA:
                                                CTAreaChart areaChart = plotArea.getAreaChartArray(0);
                                                if(chartXml == null) {
                                                    chartXml = areaChart.getSerArray(0).copy();
                                                    areaChart.setSerArray(null);
                                                }
                                                CTAreaSer ctAreaSer = areaChart.addNewSer();
                                                ctAreaSer.set(chartXml);
                                                CTUnsignedInt areaIdx = ctAreaSer.getIdx();
                                                areaIdx.setVal(i-1);
                                                ctAreaSer.setIdx(areaIdx);
                                                serTx = ctAreaSer.getTx();
                                                catDataSource = ctAreaSer.getCat();
                                                valDataSource = ctAreaSer.getVal();
                                                break;
                                            case DOUGHNUT:
                                                CTDoughnutChart doughnutChart = plotArea.getDoughnutChartArray(0);
                                                if(chartXml == null) {
                                                    chartXml = doughnutChart.getSerArray(0).copy();
                                                    doughnutChart.setSerArray(null);
                                                }
                                                CTPieSer ctDoughnutSer = doughnutChart.addNewSer();
                                                ctDoughnutSer.set(chartXml);
                                                CTUnsignedInt doughnutIdx = ctDoughnutSer.getIdx();
                                                doughnutIdx.setVal(i-1);
                                                ctDoughnutSer.setIdx(doughnutIdx);
                                                serTx = ctDoughnutSer.getTx();
                                                catDataSource = ctDoughnutSer.getCat();
                                                valDataSource = ctDoughnutSer.getVal();
                                                break;
                                        }
                                        // 添加该系列的名称
                                        if(serTx != null) {
                                            CTStrRef txStrRef = serTx.getStrRef();
                                            if(titleArr != null && i < titleArr.length) {
                                                String txRange = new CellRangeAddress(0, 0, i, i).formatAsString(sheetName, true);
                                                txStrRef.setF(txRange);
                                                CTStrData txData = txStrRef.getStrCache();
                                                CTUnsignedInt txPtCount = txData.getPtCount();
                                                txPtCount.setVal(1);
                                                txData.setPtArray(null);
                                                CTStrVal txPt = txData.addNewPt();
                                                txPt.setV(titleArr[i]);
                                                txPt.setIdx(0);
                                            } else {
                                                serTx.setStrRef(null);
                                            }
                                        }


                                        int firstRow = titleArr!=null?1:0;
                                        int lastRow = titleArr!=null?list.size():list.size()-1;
                                        // 添加该系列下的种类对应x轴的数据范围
                                        if(catDataSource != null) {
                                            CTStrRef catStrRef = catDataSource.getStrRef();
                                            CTNumRef catNumRef = catDataSource.getNumRef();
                                            if(catNumRef != null) {
                                                catDataSource.set(null);
                                                //catNumRef.set(null);
                                                catStrRef = catDataSource.addNewStrRef();
                                                this.createStrRef(catStrRef,firstRow,lastRow,list,0);

                                                /*catNumRef = catDataSource.getNumRef();
                                                this.setNumRef(catNumRef,firstRow,lastRow,list,0);*/
                                            } else if(catStrRef != null) {
                                                catStrRef = catDataSource.getStrRef();
                                                this.setStrRef(catStrRef,firstRow,lastRow,list,0);
                                            }
                                        }

                                        // 添加该系列下的种类对应y轴的数据范围
                                        if(valDataSource != null) {
                                            CTNumRef valNumRef = valDataSource.getNumRef();
                                            this.setNumRef(valNumRef,firstRow,lastRow,list,i);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } else {
                LOGGER.info("未找到序号为{}的图表,请核对模板中的序号", chartId);
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.info("填充的数据格式不符合要求,异常信息为{}", e.getMessage());
        }
    }

    /**
     * 生成图表中格式数据为字符串的
     * @param catStrRef
     * @param firstRow
     * @param lastRow
     * @param list
     */
    private void createStrRef(CTStrRef catStrRef, int firstRow, int lastRow, List list, int index) {
        String catRange = new CellRangeAddress(firstRow, lastRow, index, index).formatAsString(sheetName, true);
        catStrRef.setF(catRange);
        CTStrData catStrData = catStrRef.addNewStrCache();
        CTUnsignedInt catPtCount = catStrData.addNewPtCount();
        catPtCount.setVal(list.size());
        // 开始设置该系列下种类对应的名称
        catStrData.setPtArray(null);
        for(int j=0; j list, int index) {
        String catRange = new CellRangeAddress(firstRow, lastRow, index, index).formatAsString(sheetName, true);
        catStrRef.setF(catRange);
        CTStrData catStrData = catStrRef.getStrCache();
        CTUnsignedInt catPtCount = catStrData.getPtCount();
        catPtCount.setVal(list.size());
        // 开始设置该系列下种类对应的名称
        catStrData.setPtArray(null);
        for(int j=0; j list, int index) {
        String valRange = new CellRangeAddress(firstRow, lastRow, index, index).formatAsString(sheetName, true);
        valNumRef.setF(valRange);
        CTNumData valNumData = valNumRef.getNumCache();
        CTUnsignedInt valPtCount = valNumData.getPtCount();
        valPtCount.setVal(list.size());
        // 开始设置该系列下种类对应的值
        valNumData.setPtArray(null);
        for(int j=0; j barList = plotArea.getBarChartList();
        if(barList != null && barList.size() > 0) {
            for(CTBarChart chart : barList) {
                chart.setSerArray(null);
            }
        }
        List lineList = plotArea.getLineChartList();
        if(lineList != null && lineList.size() > 0) {
            for(CTLineChart chart : lineList) {
                chart.setSerArray(null);
            }
        }
        List pieList = plotArea.getPieChartList();
        if(pieList != null && pieList.size() > 0) {
            for(CTPieChart chart : pieList) {
                chart.setSerArray(null);
            }
        }
        List areaList = plotArea.getAreaChartList();
        if(areaList != null && areaList.size() > 0) {
            for(CTAreaChart chart : areaList) {
                chart.setSerArray(null);
            }
        }
        List doughuntList = plotArea.getDoughnutChartList();
        if(doughuntList != null && doughuntList.size() > 0) {
            for(CTDoughnutChart chart : doughuntList) {
                chart.setSerArray(null);
            }
        }
    }

    /**
     * 生成excel数据
     * @param list
     * @param title
     * @return  XSSFWorkbook
     */
    public static XSSFWorkbook excelList(List list, String[] title){
        //工作区
        XSSFWorkbook wb = new XSSFWorkbook();
        //创建第一个sheet
        XSSFSheet sheet= wb.createSheet(sheetName);
        int startRow = 0;
        //生成第一行
        XSSFRow row = null;
        if(title != null && title.length > 0) {
            row = sheet.createRow(startRow++);
            for(int i=0; i 0) {
            int size = list.get(0).length;
            for(int i=0;i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy