Java基于POI动态合并单元格

news2024/11/18 7:51:56

Java使用poi导出excel

  • 前言
    • 1.Excel和POI对象对应关系:
    • 2.POI创建Excel的步骤
  • 一、引入依赖
  • 二、示例
    • 1.准备数据
    • 2.创建Excel工作簿对象
    • 3.给excel创建表头
    • 4.填充数据
    • 5.浏览器访问下载excel
    • 6.完整代码


前言

有个需求需要后端将数据导出为excel。并且excel中需要合并单元格。于是在网上找到了poi这个包。

首先要根据数据或者excel模板构建出表头。然后将表头和数据想办法进行关联进行循环添加。

效果图:
在这里插入图片描述

1.Excel和POI对象对应关系:

Excel结构POI对象
excel 的文档对象HSSFWorkbook
excel 的表单(sheet)HSSFSheet
excel 的行HSSFRow
excel 的格子单元HSSFCell

2.POI创建Excel的步骤

  1. 生成文档对象HSSHWorkbook。
  2. 通过HSSFWorkbook生成表单HSSFSheet。
  3. 通过HSSFSheet生成行HSSFRow
  4. 通过HSSFRow生成单元格HSSFCell。

一、引入依赖

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

二、示例

1.准备数据

 String[] masterHead = {"学号","姓名","专业"};
 String[] childHead = {"课程名称","上课地点","任课教师","上课时间"};
 List<String[]> childList = new ArrayList<>();
 childList.add(new String[]{"Java程序设计","1号楼302","雷老师","2022/8/30 15:53:49"});
 childList.add(new String[]{"数据结构","1号楼305","雷老师","2022/8/30 9:18:28"});
 List<String[]> childList1 = new ArrayList<>();
 childList1.add(new String[]{"计算机网络","2号楼301","方老师","2022/8/30 15:53:49"});
 List<Map<String,List<String[]>>> masterList = new ArrayList<>();
 Map<String,List<String[]>> map = new HashMap();
 map.put("20210211-张晓-计算机与科学",childList);
 map.put("20210211-张2-计算机与科学",childList);
 map.put("20210212-于丽-电子信息工程",childList1);
 masterList.add(map);

2.创建Excel工作簿对象

 //创建Excel工作薄对象
 HSSFWorkbook workbook=new HSSFWorkbook();
 //创建Excel工作表对象
 HSSFSheet sheet = workbook.createSheet("wj");
 //设置单元格居中
 HSSFCellStyle cellStyle = workbook.createCellStyle();
 cellStyle.setAlignment(HorizontalAlignment.CENTER);
 //设置边框
 cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
 cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
 cellStyle.setBorderTop(BorderStyle.THIN);//上边框
 cellStyle.setBorderRight(BorderStyle.THIN);//右边框

3.给excel创建表头

然后根据需求一行行来给工作表格填充数据,首先是复杂表头,第一行是主表和子表,主表和子表的是合并列,根据主子表头的长度来确定,合并的列数;第二行是表头,根据主子表头的数组来填充。

 //创建行的单元格,从0开始
        HSSFRow row = sheet.createRow(0);
        //创建统计单元格
        HSSFCell masterCell=row.createCell(0);
        //赋值
        masterCell.setCellValue("主表");
        masterCell.setCellStyle(cellStyle);
        //合并列
        CellRangeAddress region=new CellRangeAddress(0, 0, 0, masterHead.length-1);
        sheet.addMergedRegion(region);

        //创建详情单元格  从统计单元格的后一格开始创建
        HSSFCell childCell = row.createCell(masterHead.length);
        //赋值
        childCell.setCellValue("子表");
        childCell.setCellStyle(cellStyle);
        //合并列
        region=new CellRangeAddress(0, 0, masterHead.length, masterHead.length+childHead.length-1);
        sheet.addMergedRegion(region);


        //表头 从1开始
        HSSFRow titleRow = sheet.createRow(1);
        //主表头
        for (int i = 0; i < masterHead.length ; i++) {
            HSSFCell msCell = titleRow.createCell(i);
            msCell.setCellStyle(cellStyle);
            msCell.setCellValue(masterHead[i]);
        }
        //子表头
        for (int i = 0; i < childHead.length; i++) {
            HSSFCell chcell = titleRow.createCell(masterHead.length+i);
            chcell.setCellStyle(cellStyle);
            chcell.setCellValue(childHead[i]);
        }

4.填充数据

    //填充数据
        int lastRowIndex = 2; //记录最后行位置
        for (Map<String,List<String[]>> m : masterList){
            for (String key : m.keySet()){
                String[] ms = key.split("-");
                List<String[]> chlist = m.get(key);
                HSSFRow valueRow = sheet.createRow(lastRowIndex);
                for (int i = 0; i < ms.length ; i++) {
                    HSSFCell mscell = valueRow.createCell(i);
                    mscell.setCellStyle(cellStyle);
                    mscell.setCellValue(ms[i]);
                    if (chlist.size()>1){ //子表数量大于1才进行 行合并
                        region=new CellRangeAddress(lastRowIndex, lastRowIndex+chlist.size()-1, i, i);
                        sheet.addMergedRegion(region);
                    }
                }
                for (int i = 0; i < chlist.size(); i++) {
                    String[] chstrs = chlist.get(i);
                    HSSFRow chRow;
                    if (i == 0){ //避免重复创建 覆盖主表数据
                        chRow = valueRow;
                    }else {
                        chRow  = sheet.createRow(lastRowIndex);
                    }
                    lastRowIndex++;
                    for (int j = 0; j < chstrs.length; j++) {
                        HSSFCell chcell = chRow.createCell(ms.length+j);
                        chcell.setCellStyle(cellStyle);
                        chcell.setCellValue(chstrs[j]);
                    }
                }
            }
        }

5.浏览器访问下载excel

        //设置下载头部文件信息
        response.setContentType("application/octet-stream; charset=utf-8");//以流的形式对文件进行下载
        response.setHeader("Content-Disposition", "attachment;filename="  + URLEncoder.encode("demo.xls", "UTF-8"));
        workbook.write(response.getOutputStream());
        response.getOutputStream().close();

6.完整代码

 @GetMapping("/")
    public void exportExcel(HttpServletResponse response) throws IOException {
        String[] masterHead = {"学号","姓名","专业"};
        String[] childHead = {"课程名称","上课地点","任课教师","上课时间"};
        List<String[]> childList = new ArrayList<>();
        childList.add(new String[]{"Java程序设计","1号楼302","雷老师","2022/8/30 15:53:49"});
        childList.add(new String[]{"数据结构","1号楼305","雷老师","2022/8/30 9:18:28"});
        List<String[]> childList1 = new ArrayList<>();
        childList1.add(new String[]{"计算机网络","2号楼301","方老师","2022/8/30 15:53:49"});
        List<Map<String,List<String[]>>> masterList = new ArrayList<>();
        Map<String,List<String[]>> map = new HashMap();
        map.put("20210211-张晓-计算机与科学",childList);
        map.put("20210211-张2-计算机与科学",childList);
        map.put("20210212-于丽-电子信息工程",childList1);
        masterList.add(map);


        //创建Excel工作薄对象
        HSSFWorkbook workbook=new HSSFWorkbook();
        //创建Excel工作表对象
        HSSFSheet sheet = workbook.createSheet("wj");
        //设置单元格居中
        HSSFCellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
        cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
        cellStyle.setBorderTop(BorderStyle.THIN);//上边框
        cellStyle.setBorderRight(BorderStyle.THIN);//右边框
        //创建行的单元格,从0开始
        HSSFRow row = sheet.createRow(0);
        //创建统计单元格
        HSSFCell masterCell=row.createCell(0);
        //赋值
        masterCell.setCellValue("主表");
        masterCell.setCellStyle(cellStyle);
        //合并列
        CellRangeAddress region=new CellRangeAddress(0, 0, 0, masterHead.length-1);
        sheet.addMergedRegion(region);

        //创建详情单元格  从统计单元格的后一格开始创建
        HSSFCell childCell = row.createCell(masterHead.length);
        //赋值
        childCell.setCellValue("子表");
        childCell.setCellStyle(cellStyle);
        //合并列
        region=new CellRangeAddress(0, 0, masterHead.length, masterHead.length+childHead.length-1);
        sheet.addMergedRegion(region);


        //表头 从1开始
        HSSFRow titleRow = sheet.createRow(1);
        //主表头
        for (int i = 0; i < masterHead.length ; i++) {
            HSSFCell msCell = titleRow.createCell(i);
            msCell.setCellStyle(cellStyle);
            msCell.setCellValue(masterHead[i]);
        }
        //子表头
        for (int i = 0; i < childHead.length; i++) {
            HSSFCell chcell = titleRow.createCell(masterHead.length+i);
            chcell.setCellStyle(cellStyle);
            chcell.setCellValue(childHead[i]);
        }

        //填充数据
        int lastRowIndex = 2; //记录最后行位置
        for (Map<String,List<String[]>> m : masterList){
            for (String key : m.keySet()){
                String[] ms = key.split("-");
                List<String[]> chlist = m.get(key);
                HSSFRow valueRow = sheet.createRow(lastRowIndex);
                for (int i = 0; i < ms.length ; i++) {
                    HSSFCell mscell = valueRow.createCell(i);
                    mscell.setCellStyle(cellStyle);
                    mscell.setCellValue(ms[i]);
                    if (chlist.size()>1){ //子表数量大于1才进行 行合并
                        region=new CellRangeAddress(lastRowIndex, lastRowIndex+chlist.size()-1, i, i);
                        sheet.addMergedRegion(region);
                    }
                }
                for (int i = 0; i < chlist.size(); i++) {
                    String[] chstrs = chlist.get(i);
                    HSSFRow chRow;
                    if (i == 0){ //避免重复创建 覆盖主表数据
                        chRow = valueRow;
                    }else {
                        chRow  = sheet.createRow(lastRowIndex);
                    }
                    lastRowIndex++;
                    for (int j = 0; j < chstrs.length; j++) {
                        HSSFCell chcell = chRow.createCell(ms.length+j);
                        chcell.setCellStyle(cellStyle);
                        chcell.setCellValue(chstrs[j]);
                    }
                }
            }
        }


  //设置下载头部文件信息
        response.setContentType("application/octet-stream; charset=utf-8");//以流的形式对文件进行下载
        response.setHeader("Content-Disposition", "attachment;filename="  + URLEncoder.encode("demo.xls", "UTF-8"));
        workbook.write(response.getOutputStream());
        response.getOutputStream().close();

    }

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

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

相关文章

linux安装java1.8

前言 安装java1.8是为了适配pyspark&#xff0c; 出现错误&#xff1a;pyspark.sql.utils.IllegalArgumentException: Unsupported class file major version 55\56\57\60 通过“java -version”看一下java版本&#xff0c;发现版本是java11&#xff0c;应该安装1.8才对 1、…

GaussDB工作级开发者认证—第二章GaussDB数据库应用程序开发指引

一. 驱动概述 GaussDB客户端接入认证&#xff0c;GaussDB支持以下三种认证方式&#xff1a;基于主机的认证口令认证SSL加密 二. JDBC接口介绍 1. JDBC概述 Java数据库连接&#xff08;JDBC&#xff09;是Java标准&#xff0c;它提供了从Java连接到关系数 据库的接口&#x…

C++智能指针shared_ptr详解

智能指针shared_ptr详解 一、简介二、底层原理2.1、引用计数2.2、shared_ptr的构造和析构2.3、shared_ptr的共享和拷贝2.4、循环引用问题 三、shared_ptr的使用3.1、创建一个shared_ptr3.2、共享一个shared_ptr3.3、使用删除器3.4、解除关联 四、使用示例总结 一、简介 C智能指…

软件测试拿了几个20K offer,分享一波面经

1、你的测试职业发展是什么?  测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自己&#xff0c;不…

MySQL笔记-函数,约束

本文标签 : 数据库函数 约束 目录 一、函数 1.字符串函数. 2.数值函数. 3.日期函数. 4.流程函数 二、约束 1.概述 2.约束演示 3.外键约束 1.概念 : 2. 实现: 3.删除/更新行为: 三、总结 一、函数 1.字符串函数. 实现: -- 函数演示 ---- 语法: select 函数(参数);-- …

跨域和网关通俗小白理解

跨域 跨域就是协议域名端口不同的服务器不能互相请求&#xff0c;企业级解决办法一般是通过Nginx反向代理实现 我们服务&#xff0c;线上都是通过S3服务器的Nginx反向代理解决跨域问题&#xff0c;因为Nginx和服务端沟通属于服务器之间的问题&#xff0c;不像浏览器有同源策略…

哇塞,炫云的智能优化太厉害啦!渲染费用竟然大幅降低了!

你有没有遇到过因为设置参数错误而导致云渲染费用突然飙升的情况呢&#xff1f;或者不知道自己设置的参数是否过高&#xff1f;现在&#xff0c;这些问题都可以轻松解决了&#xff0c;因为炫云的渲染质量功能非常智能和人性化。根据不同用户需求&#xff0c;它将参数优化分为五…

二进制部署nacos、docker部署nacos、k8s部署nacos、helm部署nacos

目录 前言Nacos支持三种部署模式官方文档二进制部署nacos&#xff08;单机模式&#xff09;安装jdk创建数据库及用户名下载安装包并解压导入nacos的表结构修改配置文件&#xff0c;启动nacos&#xff0c;登录nacos 二进制部署nacos&#xff08;cluster模式&#xff09;安装jdk&…

干货 | 什么是高频电解电容,它有普通电解电容有什么区别?

高频电解电容是一种常见的电容器&#xff0c;它在高频电路中发挥着重要的作用。与普通电解电容不同&#xff0c;高频电解电容能够更好地适应高频电路的需求&#xff0c;具有更高的频率响应和更低的ESR&#xff08;等效串联电阻&#xff09;。 电解电容重要性&#xff1a;电解电…

射频功率放大器在超声换能器声场特性校准中的应用

实验名称&#xff1a;基于水听器法的超声换能器声场特性校准技术的研究 研究方向&#xff1a;超声换能器 测试目的&#xff1a; 超声无损检测是无损检测领域重要的技术之一&#xff0c;而换能器作为超声检测中的关键部件&#xff0c;广泛应用于工业检测和医用超声成像领域。其性…

opencv配置安装

opencv配置安装 1、安装方式 https://blog.csdn.net/qq_45022687/article/details/120241068 根据这个网址的配置进行安装 2、解编译 mutex/thread等 似乎因为mingw的问题,#include 等直接引入线程无法直接引用&#xff0c;这导致了原有代码中直接使用mutex/thread的部分需要…

关于ARM核心板、一体板、底板的知识分享

嵌入式处理器模组&#xff0c;又称嵌入式核心板&#xff0c;或为CPU模组/核心板/SOM&#xff08;System on Module)&#xff0c;它是包含处理系统的核心电子部件的子电路板&#xff0c;集成了主芯片、存储器&#xff08;eMMC/Nand Flash)、运行内存&#xff08;DDR&#xff09;…

太神奇了,1984 年的电脑也能跑 Chat-GPT

新加坡的逆向计算爱好者 Yeo Kheng Meng 发布了一个 “doschgpt” ChatGPT 客户端&#xff0c;这个客户端适用于上世纪八十年代的 MS-DOS 系统。 目前这个 DOS 系统的 ChatGPT 客户端已成功在 1984 年的 IBM 5155 便携式 PC 上运行&#xff0c;这台机子配备 4.77Mhz 主频的 In…

孤儿僵尸守护进程基本概念与使用

文章目录 前言孤儿进程僵尸进程守护进程总结 前言 孤儿进程、僵尸进程和守护进程是操作系统中的概念&#xff0c;它们分别表示不同的进程状态和特性。孤儿进程和僵尸进程了解了解(都是为守护进程做铺垫)&#xff0c;但是对于守护进程大家还是可以好好学习学习&#xff0c;相信…

人民满意手机银行服务白皮书——服务分析篇

易观&#xff1a;商业银行积极践行“金融为民”&#xff0c;坚持“以用户为中心”的发展理念&#xff0c;从全客群、全服务、全渠道推动金融服务触达广大人民群众。其中&#xff0c;手机银行作为服务及经营主阵地&#xff0c;是人民群众获取金融服务的超级入口及服务平台。 “以…

【超算/先进计算学习】日报2

目录 今日已完成任务列表遇到的问题及解决方案任务完成详细笔记编辑器Vim程序开发步骤文件编辑器 Vim 快速入门任务练习 编译器 GCC程序编译流程编译器 gcc 的简易使用gcc 编译链接命令规则及常用编译选项 工程构建工具 Makemake 命令与makefile文件的规则和逻辑makefile 文件编…

数据库ER图详解

ER图也成ERD&#xff08;Entity Relationship Diagram&#xff09;,目前对于ER图的表示有两种方式&#xff1a; 一种是Chens notation&#xff0c;1976年Peter Chen首次提出了Entity Relationship Modeling&#xff08;实体关系建模&#xff09;概念。 另一种是Crow’s foot no…

【UITableViewCell的重用 Objective-C语言】

一、UITableViewCell有哪些属性,怎么看, 1.可以按住command键,点开这个UITableView,看到如下界面: 这个时候,文字比较大,你可能看起来不是很清楚,这个时候,可以点击左上角的xcode,选择Preference, 让它变小一些, 文字变小,变成12以后,这些属性,是不是对的很齐啊…

Postcat IDEA 插件,最全的使用教程

Postcat 插件不会入侵到代码内部&#xff0c;无需添加任何jar包依赖&#xff0c;这个真的很香&#xff01; 下面说一说&#xff0c;这个插件如何使用&#xff0c;是时候展现真正的技术了~ 如何安装配置&#xff1f; IDEA 版本需大于 IntelliJ IDEA 2022.03 在 IDEA “设置-插件…

JSon使用

官方文档 JSon在线文档&#xff1a;https://www.w3school.com.cn/js/js_json_intro.asp Ajax在线文档&#xff1a;https://www.w3school.com.cn/js/js_ajax_intro.asp Json介绍 Json快速入门 <!DOCTYPE html> <html lang"en"> <head><meta c…