当前位置: 首页 > news >正文

Java利用POI+JFreeChart 实现excel导出数据和图标(折线统计图)

依赖:
`
org.apache.poi
poi
5.2.3

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.3</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>4.1.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.xmlbeans</groupId>
        <artifactId>xmlbeans</artifactId>
        <version>5.1.1</version>
    </dependency>
    
    <!-- JFreeChart for Chart -->
    <dependency>
        <groupId>org.jfree</groupId>
        <artifactId>jfreechart</artifactId>
        <version>1.5.3</version>
    </dependency>`

2.代码 注意:JFreeChart 不支持中文,需要字体转换

 @Test
    public void test() throws Exception {

        // 查询每个月的用量
        Map<String, Double> monthlyUsage = new LinkedHashMap<>();
        //初始化monthlyUsage
        monthlyUsage.put("6月-1周", 148.00);
        monthlyUsage.put("6月-2周", 196.00);
        monthlyUsage.put("6月-3周", 223.00);
        monthlyUsage.put("6月-4周", 227.00 );
        monthlyUsage.put("7月-1周", 207.00);
        monthlyUsage.put("7月-2周", 201.00);
        monthlyUsage.put("7月-3周", 213.00);
        monthlyUsage.put("7月-4周", 139.00);
        monthlyUsage.put("8月-1周", 213.00 );
        monthlyUsage.put("8月-2周", 185.00 );


//
        Map<String, Double> monthlyUsage2 = new LinkedHashMap<>();
        //初始化monthlyUsage
        monthlyUsage2.put("6月-1周", 248.00);
        monthlyUsage2.put("6月-2周", 296.00);
        monthlyUsage2.put("6月-3周", 323.00);
        monthlyUsage2.put("6月-4周", 327.00);
        monthlyUsage2.put("7月-1周", 307.00);
        monthlyUsage2.put("7月-2周", 301.00);
        monthlyUsage2.put("7月-3周", 313.00);
        monthlyUsage2.put("7月-4周", 239.00);
        monthlyUsage2.put("8月-1周", 313.00 );
        monthlyUsage2.put("8月-2周", 285.00 );


        Map<String, Double> monthlyUsage3 = new LinkedHashMap<>();
        //初始化monthlyUsage
        monthlyUsage3.put("6月-1周", 396.00);
        monthlyUsage3.put("6月-2周", 492.00);
        monthlyUsage3.put("6月-3周", 546.00);
        monthlyUsage3.put("6月-4周", 554.00);
        monthlyUsage3.put("7月-1周", 514.00);
        monthlyUsage3.put("7月-2周", 502.00);
        monthlyUsage3.put("7月-3周", 526.00);
        monthlyUsage3.put("7月-4周", 378.00);
        monthlyUsage3.put("8月-1周", 526.00 );
        monthlyUsage3.put("8月-2周", 470.00 );


        DefaultCategoryDataset dataset2 = new DefaultCategoryDataset();
        for (Map.Entry<String, Double> entry : monthlyUsage3.entrySet()) {
            dataset2.addValue(entry.getValue(), "总量", entry.getKey());
        }
        // 创建折线图数据集
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        for (Map.Entry<String, Double> entry : monthlyUsage.entrySet()) {
            dataset.addValue(entry.getValue(), "FER", entry.getKey());
        }

        for (Map.Entry<String, Double> entry : monthlyUsage2.entrySet()) {
            dataset.addValue(entry.getValue(), "POCT", entry.getKey());
        }

        // 创建折线图
        JFreeChart chart = ChartFactory.createLineChart(
                "湖北妇幼保健院用量统计表", // 图表标题
                "时间",              // X轴标签
                "用量",               // Y轴标签
                dataset,               // 数据集
                PlotOrientation.VERTICAL, // 图表方向
                true,                  // 是否显示图例
                true,                  // 是否显示工具提示
                false                  // 是否显示URL
        );

// 创建折线图
        JFreeChart chart2 = ChartFactory.createLineChart(
                "湖北妇幼保健院总用量统计表", // 图表标题
                "时间",              // X轴标签
                "用量",               // Y轴标签
                dataset2,               // 数据集
                PlotOrientation.VERTICAL, // 图表方向
                true,                  // 是否显示图例
                true,                  // 是否显示工具提示
                false                  // 是否显示URL
        );
        // **正确设置字体**
        Font titleFont = new Font("宋体", Font.BOLD, 20);  // 不能直接实例化 Font,必须使用构造方法
        Font labelFont = new Font("宋体", Font.BOLD, 14 );
        chart.getTitle().setFont(titleFont);
        chart.getLegend().setItemFont(labelFont);

        chart2.getTitle().setFont(titleFont);
        chart2.getLegend().setItemFont(labelFont);
        // 获取图表的 Plot(绘图区域)
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        CategoryPlot plot2 = (CategoryPlot) chart2.getPlot();
        // 设置 X 轴字体
        CategoryAxis domainAxis = plot.getDomainAxis();
        CategoryAxis domainAxis2 = plot2.getDomainAxis();

        domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90); // 90度竖排
        domainAxis.setLabelFont(labelFont); // X 轴标签字体
        domainAxis.setTickLabelFont(labelFont); // X 轴刻度字体

        domainAxis2.setCategoryLabelPositions(CategoryLabelPositions.UP_90); // 90度竖排
        domainAxis2.setLabelFont(labelFont); // X 轴标签字体
        domainAxis2.setTickLabelFont(labelFont); // X 轴刻度字体
        // 设置 Y 轴字体
        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        NumberAxis rangeAxis2 = (NumberAxis) plot2.getRangeAxis();

        rangeAxis.setLabelFont(labelFont); // Y 轴标签字体
        rangeAxis.setTickLabelFont(labelFont); // Y 轴刻度字体
        rangeAxis.setTickUnit(new NumberTickUnit(50));
        chart.setBackgroundPaint(Color.WHITE); // 设置整个图表的背景颜色
        plot.setBackgroundPaint(new Color(255, 255, 255)); // 绘图区背景色(淡紫色)
        plot.setDomainGridlinePaint(Color.GRAY); // X 轴网格线颜色
        plot.setRangeGridlinePaint(Color.GRAY); // Y 轴网格线颜色


        rangeAxis2.setLabelFont(labelFont); // Y 轴标签字体
        rangeAxis2.setTickLabelFont(labelFont); // Y 轴刻度字体
        rangeAxis2.setTickUnit(new NumberTickUnit(50));
        chart2.setBackgroundPaint(Color.WHITE); // 设置整个图表的背景颜色
        plot2.setBackgroundPaint(new Color(255, 255, 255)); // 绘图区背景色(淡紫色)
        plot2.setDomainGridlinePaint(Color.GRAY); // X 轴网格线颜色
        plot2.setRangeGridlinePaint(Color.GRAY); // Y 轴网格线颜色

        // 获取图表渲染器
        LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
        renderer.setSeriesPaint(0, Color.BLUE); // 修改折线颜色(红色)
        renderer.setSeriesStroke(0, new BasicStroke(3.0f)); // 线条加粗
        renderer.setSeriesPaint(1, Color.RED);   // 第二条线 (HbA1c)
        renderer.setSeriesStroke(1, new BasicStroke(3.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL, 0, new float[]{10, 5}, 0)); // 红色虚线
        // 设置数据标签
        renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
        renderer.setDefaultItemLabelsVisible(true);

        // 获取图表渲染器
        LineAndShapeRenderer renderer2 = (LineAndShapeRenderer) plot2.getRenderer();
        renderer2.setSeriesPaint(0, Color.PINK); // 修改折线颜色(红色)
        renderer2.setSeriesStroke(0, new BasicStroke(3.0f)); // 线条加粗
        // 设置数据标签
        renderer2.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
        renderer2.setDefaultItemLabelsVisible(true);


        // 设置数据标签的位置
        ItemLabelPosition position = new ItemLabelPosition(
                ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER
        );
        renderer.setDefaultPositiveItemLabelPosition(position);

        // 设置数据标签的位置
        ItemLabelPosition position2 = new ItemLabelPosition(
                ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER
        );
        renderer2.setDefaultPositiveItemLabelPosition(position2);

        // 将图表保存为图片
        byte[] chartImageBytes = null;
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            ChartUtils.writeChartAsPNG(baos, chart, 800, 600);
            chartImageBytes = baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
// 将图表保存为图片
        byte[] chartImageBytes2 = null;
        try (ByteArrayOutputStream baos2 = new ByteArrayOutputStream()) {
            ChartUtils.writeChartAsPNG(baos2, chart2, 800, 600);
            chartImageBytes2 = baos2.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 将数据写入Excel并插入图表
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("湖北妇幼保健院用量统计表");
            CellStyle headerStyle = workbook.createCellStyle();
            headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); // 设置前景色为黑色
            headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 填充模式

            // 创建表头
            Row titleRow = sheet.createRow(0);

            Cell titleCell = titleRow.createCell(0);
            titleCell.setCellValue("湖北妇幼保健院");
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));
            CellStyle titleStyle = workbook.createCellStyle();
            titleStyle.setAlignment(HorizontalAlignment.CENTER);
            titleCell.setCellStyle(titleStyle);

            Row headerRow = sheet.createRow(1);
            headerRow.createCell(0).setCellStyle(headerStyle);
            headerRow.getCell(0).setCellValue("时间");
            headerRow.createCell(1).setCellStyle(headerStyle);
            headerRow.getCell(1).setCellValue("项目");
            headerRow.createCell(2).setCellStyle(headerStyle);
            headerRow.getCell(2).setCellValue("类型");
            headerRow.createCell(3).setCellStyle(headerStyle);
            headerRow.getCell(3).setCellValue("用量");


            // 填充数据
            int rowNum = 2;
            for (Map.Entry<String, Double> entry : monthlyUsage.entrySet()) {
                Row row = sheet.createRow(rowNum++);
                row.createCell(0).setCellValue(entry.getKey());
                row.createCell(1).setCellValue("FER");
                row.createCell(2).setCellValue("样本");
                row.createCell(3).setCellValue(entry.getValue());
            }
            int rowNum2 = 40;
            for (Map.Entry<String, Double> entry : monthlyUsage2.entrySet()) {
                Row row = sheet.createRow(rowNum2++);
                row.createCell(0).setCellValue(entry.getKey());
                row.createCell(1).setCellValue("POCT");
                row.createCell(2).setCellValue("样本");
                row.createCell(3).setCellValue(entry.getValue());
            }
            int rowNum3 = 80;
            for (Map.Entry<String, Double> entry : monthlyUsage3.entrySet()) {
                Row row = sheet.createRow(rowNum3++);
                row.createCell(0).setCellValue(entry.getKey());
                row.createCell(1).setCellValue("总计");
                row.createCell(2).setCellValue("样本");
                row.createCell(3).setCellValue(entry.getValue());
            }
            XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch();

            // 插入图表到Excel
            if (chartImageBytes != null) {
                int pictureIdx = workbook.addPicture(chartImageBytes, Workbook.PICTURE_TYPE_PNG);

                XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 5, 0, 12, 26 );
                drawing.createPicture(anchor, pictureIdx);
            }
            // 插入图表到Excel
            if (chartImageBytes2 != null) {
                int pictureIdx = workbook.addPicture(chartImageBytes2, Workbook.PICTURE_TYPE_PNG);

                XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 12, 0, 19, 26 );
                drawing.createPicture(anchor, pictureIdx);
            }
            // 写入Excel文件
            try (FileOutputStream fileOut = new FileOutputStream("E:/湖北妇幼保健院用量统计表.xlsx")) {
                workbook.write(fileOut);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

相关文章:

  • Kafka Snappy 压缩异常分析与解决方案
  • C++编译汇编八股总结
  • redis的典型应用 --缓存
  • Spring Boot 与 MyBatis Plus 整合 KWDB 实现 JDBC 数据访问
  • Bitcoin Thunderbolt 内测通道开启,加速比特币交易新时代
  • C++ 语法之数组指针
  • MyBatis 面试专题
  • ruoyi-vue部署linux(war包方式)
  • 鸿蒙app 中 web app和h5的通信
  • 麒麟操作系统安装人大金仓数据库
  • 解释下Cumulative Layout Shift (CLS)以及如何优化?
  • 数据库:一文掌握 Oracle 的各种指令(Oracle指令备忘)
  • 唯品会商品详情页架构设计与实现:高并发场景下的技术实践‌
  • 以mysql 为例,增删改查语法及其他高级特性
  • 3.21-1自动化框架
  • 3.3V升5V2A升压转换,WD1016可兼容SD6271
  • 文件相关函数的总结与记忆
  • 简洁、实用、无插件和更安全为特点的WordPress主题
  • 《南京日报》专题报道 | 耘瞳科技“工业之眼”加码“中国智造”
  • Billu_b0x靶机攻略
  • 沃尔玛上财季净利下滑12%:关税带来成本压力,新财季价格涨幅将高于去年
  • 阿里上财年营收增6%,蒋凡:会积极投资,把更多淘宝用户转变成即时零售用户
  • 昔日千亿房企祥生集团约2.03亿元债权被拍卖,起拍价8000万元
  • 钕铁硼永磁材料龙头瞄准人形机器人,正海磁材:已向下游客户完成小批量供货
  • 魔都眼|锦江乐园摩天轮“换代”开拆,新摩天轮暂定118米
  • 外交部:国际社会广泛理解和支持中方不同意台参加世卫大会的决定