POI导出复杂Excel表格

news2024/9/21 12:44:32

记录在遇到复杂统计报表业务时,无法使用Excel模板生成对应报表,则采用最原始poi方式进行创建生成

业务所需统计报表如下图

表格模板
麻烦所在各类型订单下方餐别为动态数据,废话不多说直接上代码

new CellRangeAddress(起始行号, 终止行号, 起始列号, 终止列号);// 单元格范围

具体实现代码如下:

import cn.hutool.core.collection.CollectionUtil; 
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;

import java.io.*; 
import java.util.Arrays;
import java.util.List; 

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>作者: AJie </p>
 * <p>日期: 2024-08-09 17:03</p>
 * <p>版本:1.0 </p>
 */
public class ExcelExportUtils {

    /**
     * 设置边框和居中
     * @param workbook
     */
    public static XSSFCellStyle setBorder(XSSFWorkbook workbook){
        XSSFCellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER_SELECTION);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        return style;
    }

    public static Workbook orderMealTypeSummaryExport(List<String> cashierMealTypes,List<String> preMealTypes){

        //excel文档对象
        XSSFWorkbook workbook = new XSSFWorkbook();
        //建立excel表单
        XSSFSheet sheet = workbook.createSheet("Sheet1");
        //设置边框和居中
        XSSFCellStyle style = setBorder(workbook);

        XSSFRow row0 = sheet.createRow(0); // Excel表格第一行
        XSSFRow row1 = sheet.createRow(1); // Excel表格第二行
        XSSFRow row2 = sheet.createRow(2); // Excel表格第三行

        // 组合表头第0行 --- 【编号、姓名、卡类、工号、部门】
        sheet.addMergedRegion(new CellRangeAddress(0, 2, 0, 0));
        XSSFCell titleCell00 = row0.createCell(0);
        titleCell00.setCellValue("编号");
        titleCell00.setCellStyle(style);
        XSSFCell titleCell00_1 = row1.createCell(0);
        titleCell00_1.setCellStyle(style);
        XSSFCell titleCell00_2 = row2.createCell(0);
        titleCell00_2.setCellStyle(style);

        sheet.addMergedRegion(new CellRangeAddress(0, 2, 1, 1));
        XSSFCell titleCell01 = row0.createCell(1);
        titleCell01.setCellValue("姓名");
        titleCell01.setCellStyle(style);
        XSSFCell titleCell01_1 = row1.createCell(1);
        titleCell01_1.setCellStyle(style);
        XSSFCell titleCell01_2 = row2.createCell(1);
        titleCell01_2.setCellStyle(style);

        sheet.addMergedRegion(new CellRangeAddress(0, 2, 2, 2));
        XSSFCell titleCell02 = row0.createCell(2);
        titleCell02.setCellValue("卡类");
        titleCell02.setCellStyle(style);
        XSSFCell titleCell02_1 = row1.createCell(2);
        titleCell02_1.setCellStyle(style);
        XSSFCell titleCell02_2 = row2.createCell(2);
        titleCell02_2.setCellStyle(style);

        sheet.addMergedRegion(new CellRangeAddress(0, 2, 3, 3));
        XSSFCell titleCell03 = row0.createCell(3);
        titleCell03.setCellValue("工号");
        titleCell03.setCellStyle(style);
        XSSFCell titleCell03_1 = row1.createCell(3);
        titleCell03_1.setCellStyle(style);
        XSSFCell titleCell03_2 = row2.createCell(3);
        titleCell03_2.setCellStyle(style);

        sheet.addMergedRegion(new CellRangeAddress(0, 2, 4, 4));
        XSSFCell titleCell04 = row0.createCell(4);
        titleCell04.setCellValue("部门");
        titleCell04.setCellStyle(style);
        XSSFCell titleCell04_1 = row1.createCell(4);
        titleCell04_1.setCellStyle(style);
        XSSFCell titleCell04_2 = row2.createCell(4);
        titleCell04_2.setCellStyle(style);

        /***组合表头第0行 --- 【编号、姓名、卡类、工号、部门】end**/

        // 收银/预定订单/合计表头 ------------------
        int row_0_start_index = 4; // 第一行开始位置【收银/预定名称开始位置】

        // 收银餐别不为空情况
        if(CollectionUtil.isNotEmpty(cashierMealTypes)){
            // 第一行结束位置【收银/预定名称开始位置】
            int row_0_end_index = cashierMealTypes.size()*3+row_0_start_index;
            sheet.addMergedRegion(new CellRangeAddress(0, 0, row_0_start_index+1, row_0_end_index));
            XSSFCell titleCell05 = row0.createCell(row_0_start_index+1);
            titleCell05.setCellValue("收银订单");
            titleCell05.setCellStyle(style);
            for(int i=row_0_start_index+2;i<=row_0_end_index;i++){
                XSSFCell titleCell05_1 = row0.createCell(i);
                titleCell05_1.setCellStyle(style);
            }

            /**
             * 生成对应【餐别】单元格
             */
            createMealTypeCall(row_0_start_index,cashierMealTypes,row1,row2,style,sheet);

            row_0_start_index = row_0_end_index;// 下一个单元格开始位置
        }

        // 预定餐别不为空情况
        if(CollectionUtil.isNotEmpty(preMealTypes)){
            // 第一行结束位置【收银/预定名称开始位置】
            int row_0_end_index = preMealTypes.size()*3 + row_0_start_index;
            sheet.addMergedRegion(new CellRangeAddress(0, 0, row_0_start_index+1, row_0_end_index));
            XSSFCell titleCell06 = row0.createCell(row_0_start_index+1);
            titleCell06.setCellValue("预订订单");
            titleCell06.setCellStyle(style);
            for(int i=row_0_start_index+2;i<=row_0_end_index ;i++){
                XSSFCell titleCell06_1 = row0.createCell(i);
                titleCell06_1.setCellStyle(style);
            }

            /**
             * 生成对应【餐别】单元格
             */
            createMealTypeCall(row_0_start_index,preMealTypes,row1,row2,style,sheet);

            row_0_start_index = row_0_end_index;// 下一个单元格开始位置
        }

        // 消费合计单元格
        if(CollectionUtil.isNotEmpty(cashierMealTypes) || CollectionUtil.isNotEmpty(preMealTypes) ){
            // 第一行结束位置【收银/预定名称开始位置】
            int row_0_end_index = 2 + row_0_start_index;
            sheet.addMergedRegion(new CellRangeAddress(1, 1, row_0_start_index+1, row_0_end_index));
            XSSFCell titleCell07 = row1.createCell(row_0_start_index+1);
            titleCell07.setCellValue("消费合计");
            titleCell07.setCellStyle(style);
            for(int i=row_0_start_index+2;i<=row_0_end_index ;i++){
                XSSFCell titleCell07_1 = row1.createCell(i);
                titleCell07_1.setCellStyle(style);
            }

            XSSFCell titleCell22 = row2.createCell(row_0_start_index+1);
            titleCell22.setCellValue("笔数");
            titleCell22.setCellStyle(style);
            XSSFCell titleCell24 = row2.createCell(row_0_end_index);
            titleCell24.setCellValue("金额");
            titleCell24.setCellStyle(style);
        }

        /*********excel表格头部内容设置end********/

        return workbook;
    }

    /**
     * 生成餐别单元格
     * @param row_0_start_index
     * @param mealTypeNames
     * @param row1
     * @param style
     */
    private static void createMealTypeCall(int row_0_start_index,List<String> mealTypeNames,XSSFRow row1,XSSFRow row2,XSSFCellStyle style, XSSFSheet sheet){
        int row_1_start_index = row_0_start_index+1; // 第一行餐别开始位置
        //  组合表头第1行 --- 预定/收银订单餐别【"早餐","午餐","下午茶","晚餐","夜宵"for(String a:mealTypeNames){
            //  第一行餐别结束位置
            int row_1_end_index = row_1_start_index+2;
            sheet.addMergedRegion(new CellRangeAddress(1, 1, row_1_start_index, row_1_end_index));
            XSSFCell titleCell021 = row1.createCell(row_1_start_index);
            titleCell021.setCellValue(a);
            titleCell021.setCellStyle(style);
            for(int i=row_1_start_index+1;i<=row_1_end_index;i++){
                XSSFCell titleCell13 = row1.createCell(i);
                titleCell13.setCellStyle(style);
            }

            String[] detailNames = {"笔数","消费标准","合计"};
            // 创建对应金额详细单元格【笔数、消费标准、合计】
            for(int i=row_1_start_index,j=0;i<=row_1_end_index;i++,j++){
                XSSFCell titleCell22 = row2.createCell(i);
                titleCell22.setCellValue(detailNames[j]);
                titleCell22.setCellStyle(style);
            }

            row_1_start_index = row_1_end_index+1; // 下一个餐别开始位置
        }
    }


    public static void main(String[] args) throws IOException {

        List<String> aMealType = Arrays.asList(new String[]{"晚餐"});
        List<String> bMealType = Arrays.asList(new String[]{"午餐","下午茶","晚餐"});

        Workbook wb = orderMealTypeSummaryExport(aMealType,bMealType);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        wb.write(bos);
        InputStream inputStream = new ByteArrayInputStream(bos.toByteArray());

        String outputPath = "D://b.xls";

        try {
            saveToFile(inputStream, outputPath);
            System.out.println("文件保存成功!");
        } catch (IOException e) {
            System.out.println("文件保存失败:" + e.getMessage());
        }
    }

    public static void saveToFile(InputStream inStream, String outputPath) throws IOException {
        try (OutputStream outStream = new FileOutputStream(outputPath)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, bytesRead);
            }
        }
    }

}

这里使用easypoi,导出工具调用poi原生jar,不涉及easypoi,可单独导入poi-4.1.1.jar,也可使用下面easypoi

			<dependency>
                <groupId>cn.afterturn</groupId>
                <artifactId>easypoi-base</artifactId>
                <version>4.4.0</version>
            </dependency>

            <dependency>
                <groupId>cn.afterturn</groupId>
                <artifactId>easypoi-web</artifactId>
                <version>4.4.0</version>
            </dependency>

            <dependency>
                <groupId>cn.afterturn</groupId>
                <artifactId>easypoi-annotation</artifactId>
                <version>4.4.0</version>
            </dependency>

工具类导出Excel效果如下图:
导出效果
详细案例可下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1995381.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android Studio 设置打开layout.xml文件的默认视图split

Android Studio 设置打开layout.xml文件的默认视图 Android Studio 设置打开layout.xml文件的默认视图 androd studio 在使用的时候打开我们自己的布局文件默认展示的视图为Design,我们想要编辑的时候还有手动切换成splite 视图或者Code视图&#xff0c;不上很方便&#xff0c…

CA证书和openssl介绍

文章目录 一、加密和算法常见的安全攻击加密算法和协议对称加密非对称加密算法 二、CA和证书中间人攻击CA和证书安全协议SSL/TLS协议介绍HTTPS 三、opensslopenssl介绍使用openssl实现对称加密使用openssl命令生成加密密码生成随机密码建立私有CA证书申请颁发建立私有CA实际例子…

Java-数据库基本概念

数据库DataBase 定义: 保存一组数据的仓库就是数据库 例 BirdBoot项目中&#xff0c;我们为了保存一组用户信息&#xff0c;创建了一个目录users。里面用若干个文件保存每一个用户信息 此时users目录就可以称为是一个数据库 只不过对于这些数据的维护操作&#xff0c;要么…

【最多可以参加的会议数目】python刷题记录

R4-贪心篇 结束时间升序排列优先队列 class Solution:def maxEvents(self, events: List[List[int]]) -> int:dictdefaultdict(list)for i,val in enumerate(events):dict[val[0]].append(val[1])#优先队列&#xff08;小根堆&#xff09;h[]ret0for i in range(1,100001)…

C语言求平方和倒数

文章目录 1. 代码实现float类型数据double类型数据使用 double 类型的调整 2. 魔数与位级别操作浮点数表示位级别魔数操作 3. 牛顿迭代4. 复杂代码具体解释具体解释&#xff1a;目的&#xff1a;举例&#xff1a; 5.感谢 平方和倒数 广泛用于计算机图形学中&#xff0c;尤其是在…

Qt实现类似淘宝商品展示看板功能简版

前一篇文章的简化版本只有浏览功能&#xff0c;前一篇文章链接如下&#xff1a; Qt实现类似淘宝商品看板的界面&#xff0c;带有循环翻页以及点击某页跳转的功能 效果如下&#xff1a; 代码留给有需要的人。 #ifndef ModelDashboardGroup_h__ #define ModelDashboardGroup_…

DC-DC PCB 布线参考

在DC-DC芯片的应用设计中&#xff0c;PCB布板是否合理对于芯片能否表现出其最优性能有着至关重要的影响。不合理的PCB布板会造成芯片性能变差如线性度下降&#xff08;包括输入线性度以及输出线性度&#xff09;、带载能力下降、工作不稳定、EMI辐射增加、输出噪声增加等&#…

容量 动效 仪表盘 Canvas 2D API

容量动效 <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Canvas 内部圆形波浪</title><…

【区块链+乡村振兴】基于区块链的农权抵押贷款平台 | FISCO BCOS应用案例

当前两权抵押贷款业务逐渐活跃&#xff0c;但因参与两权抵押的相关方独立运营各自的管理系统&#xff0c;办理农权抵押贷款业务时&#xff0c; 存在多方信息不对称、业务办理过程繁琐、低效等问题&#xff0c;且不利于相关部门对农权抵押情况进行监督管理。具体表现在&#xff…

《数据资产管理核心技术与应用》相关分享章节

【图书推荐】《数据资产管理核心技术与应用》-CSDN博客 图书《数据资产管理核心技术与应用》介绍-CSDN博客 本文用于快速了解数据资产管理的概念及其技术范围。 数据资产通常是指那些可以通过分析来揭示价值、支持企业决策制定、优化企业流程、预测行业的未来趋势或产生更大…

dhcp+checkkickstar的实验理解

文章目录 实验介绍使用的服务介绍PXE服务dhcp服务Kickstart 服务tftp服务 第一部分&#xff08;基础部分&#xff09;代码展示注意点第一点![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/13c0f4aabb664655a4dd285dd8e5527a.png)第二点 结果展示 第二部分&#xff08…

元岳食堂采购供应链系统-智慧食堂数据化解决方案

随着社会的发展和科技的进步&#xff0c;在数字化浪潮的推动下&#xff0c;智慧食堂供应链系统逐渐成为食堂管理的重要工具。在此背景下&#xff0c;元岳食堂采购供应链系统应运而生&#xff0c;该系统通过其独特的数字化和自动化功能&#xff0c;能够对食堂的采购、储存、配送…

重庆市合川区第二届网络安全“钓鱼城“杯部分题解

MISC 下载文件后&#xff0c;进行分析 往下划看见smb 最开始以为是通过smb协议下载的文件 找半天没发现&#xff0c;往前翻了翻&#xff0c;看见了flag 存储为原始数据 通过上述分析发现开头是pk&#xff0c;保存为zip压缩包 发现需要密码 感觉是伪加密 使用工具一把梭 再…

免费的GA/T1400视图库平台Easy1400软件又迭代出新版本了!

自从年初发布了这款免费的GA1400视图库平台&#xff08;https://blog.csdn.net/xiejiashu/article/details/135050381&#xff09;&#xff0c;本来就是想做一做能给大家差不多能用就行了&#xff0c;没成想总是忍不住要改一改、优化优化&#xff0c;于是又经过了几个月的优化&…

合宙Air201定位模组,千万不要忘记设置这个......

最近一个杭州的客户&#xff0c;使用合宙的 Air201——4G资产定位模组&#xff0c;做室内wifi定位&#xff0c;发现在同一园区不同楼栋内定位结果相同&#xff0c;找到我们希望做问题排查。 排查过程记录在这里了&#xff0c;如果你也有类似问题&#xff0c;希望可以帮助到你~ …

Pinterest:从 Druid 到 StarRocks,实现 6 倍成本效益比提升

导读&#xff1a; 开源无国界&#xff0c;StarRocks 自开源以来&#xff0c;近3年的时间里已在全球数据技术领域崭露头角。我们欣喜地发现&#xff0c;越来越多的海外用户正在使用并积极推广着 StarRocks。为了促进知识共享&#xff0c;StarRocks中文社区将精选优秀文章与大家共…

华为手机平板开启下方提示条(横条)

打开设置&#xff0c;系统与更新&#xff0c;系统导航方式&#xff0c;手势导航&#xff0c;更多设置&#xff0c;显示提示条。 该功能部分机型不支持&#xff0c;我的MatePad SE支持&#xff08;别买&#xff0c;割韭菜&#xff09;

有自增变量作为循环条件的循环边界的理解

while (i < 100) 先判断后增加 当次i值用于判断&#xff0c;范围1~99&#xff0c; 递增后的i值为当次循环值&#xff0c;即循环内的i值&#xff0c;范围2~100 当 i 9 时&#xff0c;小于 100&#xff0c;进入循环体。在进入循环体之前&#xff0c;i 递增为 10。10满足i…

面试笔记--(正在整理版)

面试常见: Jvm&#xff0c;高并发&#xff0c;多线程&#xff0c;数据库&#xff0c;redis&#xff0c;框架 多线程 1.线程和进程是什么?如何保证线程安全性? 进程线程&#xff08;一&#xff09;——基础知识&#xff0c;什么是进程&#xff1f;什么是线程&#xff1f;_…

手机卡换了上网的ip会改变吗

在数字化时代&#xff0c;互联网已成为我们日常生活不可或缺的一部分。无论是工作、学习还是娱乐&#xff0c;我们都离不开网络的支持。而每当涉及到网络连接&#xff0c;IP地址这一概念便显得尤为重要。IP地址不仅是设备在网络中的唯一标识&#xff0c;还关系到我们的网络体验…