Java使用poi导出excel折线图--以三温层车辆运输单据温度为例(含如何更改各标题大小)

maven依赖引入

<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>4.1.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>4.1.2</version>
		</dependency>

代码示例

/**
 * @author alin
 * @date 2024-06-03
 */
public class ExportChart {
    public static void main(String[] args) throws Exception {
        testCreateChart();
    }

    /**
     * 创建折线图
     *
     * @throws Exception
     */
    public static void testCreateChart() throws Exception {
        try (XSSFWorkbook wb = new XSSFWorkbook()) {
            String sheetName = "温度折线图";
            XSSFSheet sheet = wb.createSheet(sheetName);
            XSSFDrawing drawing = sheet.createDrawingPatriarch();
            // TODO 样式可以根据数据长度自行调整
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 2, 4, 30, 50);
            XSSFChart chart = drawing.createChart(anchor);
            // 折线图标题
            chart.setTitleText("单据: ****运输过程温度数据 车牌:豫P12345");
            // 标题是否覆盖图表
            chart.setTitleOverlay(false);
            // 设置图表标题字体大小
            setChartTitleFontSize(chart, 16);
            XDDFChartLegend legend = chart.getOrAddLegend();
            // 图例位置:上下左右
            legend.setPosition(LegendPosition.TOP_RIGHT);
            // 创建x轴
            XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            // X轴标题
            xAxis.setTitle("采集时间");
            // 设置X轴标题字体大小
            setAxisTitleFontSize(xAxis, 16);

            // 左侧标题, Y轴
            XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.TOP);
            yAxis.setTitle("温度");
            // 刻度
            yAxis.setMajorUnit(5);
            // 设置Y轴标题字体大小
            setAxisTitleFontSize(yAxis, 16);

            // 获取mock数据
            List<TemperatureModel> list = getResult();
            // x轴标题数据
            List<String> xTitleData = new ArrayList<>(list.size());
            // y轴数据
            List<Double> yData1 = new ArrayList<>(list.size());
            List<Double> yData2 = new ArrayList<>(list.size());
            List<Double> yData3 = new ArrayList<>(list.size());
            for (TemperatureModel layer : list) {
                xTitleData.add(layer.getGatherTime());
                yData1.add(layer.getTemperature() == null ? 0D : layer.getTemperature());
                yData2.add(layer.getTemperature2() == null ? 0D : layer.getTemperature2());
                yData3.add(layer.getTemperature3() == null ? 0D : layer.getTemperature3());
            }

            // 数据源
            XDDFDataSource<String> date = XDDFDataSourcesFactory.fromArray(xTitleData.toArray(new String[0]));
            XDDFNumericalDataSource<Double> one = XDDFDataSourcesFactory.fromArray(yData1.toArray(new Double[0]));
            XDDFNumericalDataSource<Double> two = XDDFDataSourcesFactory.fromArray(yData2.toArray(new Double[0]));
            XDDFNumericalDataSource<Double> three = XDDFDataSourcesFactory.fromArray(yData3.toArray(new Double[0]));

            // 创建折线图
            XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, xAxis, yAxis);

            // 折线1
            XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(date, one);
            // 折线标题
            series1.setTitle("温度1(℃)", null);
            // 折线是否平滑
            series1.setSmooth(true);
            // 折线节点样式
            series1.setMarkerStyle(MarkerStyle.CIRCLE);

            // 折线2
            XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(date, two);
            series2.setTitle("温度2(℃)", null);
            series2.setSmooth(true);
            series2.setMarkerStyle(MarkerStyle.CIRCLE);
            chart.plot(data);

            // 折线3
            XDDFLineChartData.Series series3 = (XDDFLineChartData.Series) data.addSeries(date, three);
            series3.setTitle("温度3(℃)", null);
            series3.setSmooth(true);
            series3.setMarkerStyle(MarkerStyle.CIRCLE);
            chart.plot(data);

            // 输出文件到指定路径
            try (FileOutputStream fileOut = new FileOutputStream("d:/豫P12345运输温度折线图.xlsx")) {
                wb.write(fileOut);
                wb.close();
            }
        }
    }

    /**
     * 模拟数据
     *
     * @return
     */
    public static List<TemperatureModel> getResult() {
        List<TemperatureModel> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            ExportChart.TemperatureModel temperatureModel = new ExportChart.TemperatureModel();
            temperatureModel.setGatherTime("2024-06-03 10:" + String.format("%02d", i * 2) + ":00");
            temperatureModel.setTemperature(i % 2 == 0 ? -RandomUtils.nextDouble(0, 30) : RandomUtils.nextDouble(0, 30));
            temperatureModel.setTemperature2(RandomUtils.nextDouble(0, 30));
            temperatureModel.setTemperature3(i % 2 == 0 ? -RandomUtils.nextDouble(0, 30) : RandomUtils.nextDouble(0, 30));
            list.add(temperatureModel);
        }
        return list;
    }


    /**
     * 设置图表标题字体大小
     * 无法直接设置图表标题字体大小, 可以使用底层的XML对象来实现
     *
     * @param chart
     * @param fontSize
     */
    private static void setChartTitleFontSize(XSSFChart chart, double fontSize) {
        CTChart ctChart = chart.getCTChart();
        if (ctChart.isSetTitle()) {
            CTTitle title = ctChart.getTitle();
            if (title.isSetTx()) {
                CTTextBody rich = title.getTx().getRich();
                CTTextParagraph para = rich.getPArray(0);
                CTTextCharacterProperties rPr = para.getRArray(0).getRPr();
                // 字号大小 fontSize * 100 = fontSize pt
                rPr.setSz((int) (fontSize * 100));
                //rPr.setB(true); // 加粗
                //rPr.setI(true); // 斜体
            }
        }
    }

    /**
     * 设置X轴标题字体大小
     * 无法直接设置X轴标题字体大小, 可以通过反射获取到CTCatAx对象, 然后设置字体大小
     *
     * @param axis
     * @param fontSize
     */
    private static void setAxisTitleFontSize(XDDFCategoryAxis axis, double fontSize) {
        try {
            Field ctCatAx1 = XDDFCategoryAxis.class.getDeclaredField("ctCatAx");
            ctCatAx1.setAccessible(true);
            CTCatAx ctCatAx = (CTCatAx) ctCatAx1.get(axis);
            if (ctCatAx.isSetTitle()) {
                CTTitle title = ctCatAx.getTitle();
                if (title.isSetTx()) {
                    CTTextBody rich = title.getTx().getRich();
                    if (rich != null && rich.sizeOfPArray() > 0) {
                        CTTextParagraph para = rich.getPArray(0);
                        if (para.sizeOfRArray() > 0) {
                            CTTextCharacterProperties rPr = para.getRArray(0).getRPr();
                            if (rPr == null) {
                                rPr = para.getRArray(0).addNewRPr();
                            }
                            rPr.setSz((int) (fontSize * 100));
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置Y轴标题字体大小
     * 无法直接设置Y轴标题字体大小, 可以通过反射获取到CTValAx对象, 然后设置字体大小
     *
     * @param axis
     * @param fontSize
     */
    private static void setAxisTitleFontSize(XDDFValueAxis axis, double fontSize) {
        try {
            Field ctValAx1 = XDDFValueAxis.class.getDeclaredField("ctValAx");
            ctValAx1.setAccessible(true);
            CTValAx ctValAx = (CTValAx) ctValAx1.get(axis);
            if (ctValAx.isSetTitle()) {
                CTTitle title = ctValAx.getTitle();
                if (title.isSetTx()) {
                    CTTextBody rich = title.getTx().getRich();
                    if (rich != null && rich.sizeOfPArray() > 0) {
                        CTTextParagraph para = rich.getPArray(0);
                        if (para.sizeOfRArray() > 0) {
                            CTTextCharacterProperties rPr = para.getRArray(0).getRPr();
                            if (rPr == null) {
                                rPr = para.getRArray(0).addNewRPr();
                            }
                            rPr.setSz((int) (fontSize * 100));
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Data
    public static class TemperatureModel {

        /**
         * 采集时间
         */
        private String gatherTime;

        /**
         * 温度1
         */
        private Double temperature;

        /**
         * 温度2
         */
        private Double temperature2;

        /**
         * 温度3
         */
        private Double temperature3;

    }

}

导出效果图

热门相关:隋唐君子演义   脑洞大爆炸   春秋我为王   极品仙师   黄金渔村