Java基于POI动态合并单元格

article/2025/11/3 9:27:58

基于poi动态合并表格

-首先看下效果图
在这里插入图片描述
左边为主表数据,右边为子表数据,可以根据自己的需求进行修改,下面来看下代码。

  • 引入依赖
		<!--poi--><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.0</version></dependency>
  • 创建一个PoiExcel类

先构造数据,根据表格,主子表是有相关联的,所以将主子表数据存入一个map集合中,主表的值作为map的key,value对应子表的list集合,可参考下面代码:

        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("20210212-于丽-电子信息工程",childList1);masterList.add(map);

然后创建一个Excel工作薄对象

 		//创建Excel工作薄对象HSSFWorkbook workbook=new HSSFWorkbook();//创建Excel工作表对象HSSFSheet sheet = workbook.createSheet("wj");//设置单元格居中HSSFCellStyle cellStyle = workbook.createCellStyle();cellStyle.setAlignment(HorizontalAlignment.CENTER);

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

		//创建行的单元格,从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]);}

这样就将第一行和第二行的表头填充上了,然后再填充对应的数据,先填充的是主表,主表的值我是用“-”来进行分隔的,所以用字符串进行切割成数组,然后拿到主表数据和对应的子表数据,工作簿的前2行都是表头,所以填充数据是从第三行开始,所以行下标为2,然后从第三行开始创建行,填充主表的数据,填充时要判断下子表的list的大小,大于一才需要进行合并,填充完主表后再填充子表,子表不需要合并,就一行行填充,代码如下:

        //填充数据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]);}}}}

其中最重要的一句代码就是:

new CellRangeAddress(int firstRow, int lastRow, int firstCol, int lastCol)

这句代码就是合并单元格,参数1:起始行 参数2:终止行 参数3:起始列 参数4:终止列

  • 最后看下PoiExcel类的完整代码

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;/*** @author huao* @Date 2022/8/31 13:50* @description:*/
public class PoiExcel {public static void excelport(HttpServletResponse response) throws Exception {//数据来源 通过参数传入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("20210212-于丽-电子信息工程",childList1);masterList.add(map);//创建Excel工作薄对象HSSFWorkbook workbook=new HSSFWorkbook();//创建Excel工作表对象HSSFSheet sheet = workbook.createSheet("wj");//设置单元格居中HSSFCellStyle cellStyle = workbook.createCellStyle();cellStyle.setAlignment(HorizontalAlignment.CENTER);//创建行的单元格,从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]);}}}}String fileName = URLEncoder.encode("POIExcel下载测试","UTF-8");response.setContentType("application/octet-stream;charset=UTF-8");response.setHeader("Content-Disposition","attachment;filename="+fileName+".xls");OutputStream os = response.getOutputStream();workbook.write(os);os.flush();os.close();workbook.close();}
}

然后controller层的代码:

import com.example.demo.utils.PoiExcel;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;/*** @author huao* @Date 2022/8/31 13:56* @description:*/
@RestController
@RequestMapping("/demo")
public class DemoWeb {@RequestMapping("/download")public void download(HttpServletResponse response) throws Exception {PoiExcel.excelport(response);}
}

导入依赖后代码复制过去可直接使用。

写作原因:看着网上很多动态合并单元格的例子,但是都看不懂,可能是我太菜了,所以自己撸了一个,这个代码量算是很少了吧,如果有什么不清楚的欢迎评论区留言或者私信我。


http://chatgpt.dhexx.cn/article/hSWiaScd.shtml

相关文章

poi 读取excel合并单元格两种方式

说明: excel合并是用选择的两个或更多单元格创建一个单元格的过程。合并单元格时&#xff0c;如果有多个选择的单元格包含数据&#xff0c;则将保留左上角或右上角(取决于当前的视图方向)单元格中的数据&#xff0c;并删除其余的所有数据。 操作方法&#xff1a; 1 首先创建三…

POI 合并单元格

1. 合并单元格概述 合并单元格CellRangeAddress就是将几个相邻的单元格合并为一个单元格&#xff0c;即使没有创建过行和单元格&#xff0c;也 可以创建合并单元格&#xff0c;因为单元格信息是单独存储的 /*** Creates new cell range. base 0* * param firstRow Index of fi…

Java使用POI操作Excel合并单元格

友情链接&#xff1a;Spring Data JPA 动态查询 普通查询 友情链接&#xff1a;利用POI实现动态复杂多级表头 前言 合并单元格语法&#xff1a; 开始行、结束行、开始列、结束列 对应代码&#xff1a;new CellRangeAddress(startRowIndex, rowIndex - 1, i, i); 合并代码…

css动画(旋转)

css动画&#xff08;旋转&#xff09; &#xff08;作者&#xff1a;张米&#xff0c;撰写时间&#xff1a;2019年2月4号&#xff09; 旋转函数rotate(n)通过指定的角度参数使元素围绕原点旋转。n是角度参数&#xff0c;用于设置参数的大小&#xff0c;参数单位是deg。参数为正…

CSS - 元素旋转动画(360度转圈)

效果图 代码 keyframes rotate {0%{-webkit-transform:rotate(0deg);}25%{-webkit-transform:rotate(90deg);}50%{-webkit-transform:rotate(180deg);}75%{-webkit-transform:rotate(270deg);}100%{-webkit-transform:rotate(360deg);} }使用 /* turn : 定义的动画名称1s : 动…

CSS——正方体360°旋转动画 效果

先看效果&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" c…

css3动画—旋转

css3动画旋转&#xff0c;内圆顺时针旋转&#xff0c;外圆逆时针旋转 1、html <img src"img/about-img07.png" class"circle01 circle-pst"> <img src"img/about-img06.png" class"circle02 circle-pst">2、css .circle…

CSS - 音乐盒 360° 无限循环旋转动画(元素转圈)

前言 由于 Gif 图片过小的问题&#xff0c;显得很不流畅&#xff0c;真实情况下很流畅&#xff0c;放心。 实现一个 360 无限循环旋转的动画&#xff0c;如下图所示&#xff1a; 示例代码 注意&#xff1a;通过 animation 复合属性&#xff0c;可控制动画旋转速度及其他参数。…

css旋转动画定义中心,css动画(transition/transform/animation)

在开发中&#xff0c;一个好的用户操作界面&#xff0c;总会夹杂着一些动画。css用对少的代码&#xff0c;来给用户最佳的体验感&#xff0c;下面我总结了一些css动画属性的使用方法及用例代码供大家参考&#xff0c;在不对的地方&#xff0c;希望大佬直接拍砖评论。 1 transit…

利用css3实现立体旋转动画效果

css3实行一个转动的六边形 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>body,html {width: 100%;height: 100%;}body {perspective: 1000px;}.container {/* 给容器设置一个高宽 */width: 3…

CSS实现旋转风车

CSS实现旋转风车 使用css实现旋转风车主要是运用border和css动画来实现的&#xff0c;效果图如下&#xff1a; 一、制作风车 首先观察风车是由8个相等形状大小的三角形旋转组成的&#xff0c;可以发现都是围绕一个中心点旋转组成的&#xff0c;所以我们可以先用border画出一…

CSS的动画效果-旋转

开发工具与关键技术&#xff1a;css 撰写时间&#xff1a;2020/7/7 这是简陋的小风车 当我们将鼠标移入到该区域式这个小风车就会旋转起来 这是这个小风车的代码 Html&#xff1a; Css&#xff1a; 本人只是个新手&#xff0c;只是将风车放置Ul标签内&#xff0c;设置ul标签的…

Css动画效果旋转图片

这次给大家讲解一个有趣的css动画效果哈&#xff0c;那就是旋转图片成一朵花型。 第一步依旧是把img标签敲出来然后把图片放上去。 2.然后开始敲打css样式和效果&#xff0c;先给个class设置一下样式加个定位&#xff0c;因为动画效果需要个定 位才能有效果显示出来。…

旋转的css动画效果

需要补习动画属性的可以查看这个文章 效果图 css旋转代码 .image {width: 250px;height: 250px;border-radius: 50%;//定义动画名,持续时间,动画状态,以及持续运行animation: rotate 15s infinite linear;//控制暂停和播放animation-play-state: play;}keyframes rotate {form…

CSS3 旋转动画

效果图 用到图片&#xff1a; 实现&#xff1a; <body><div class"wrap"><image class"figure" src"./staitc/images/figure.png" /><imageclass"circle circle-inner"src"./staitc/images/circle-in…

纯css图片自动旋转动画

css能否实现图片自动旋转动画呢&#xff1f;答案当然是肯定的&#xff0c; 首先看下效果&#xff1a; HTML代码 <img src"https://gimg2.baidu.com/image_search/srchttp%3A%2F%2Fimg.yipic.cn%2Fthumb%2Fda6639c9%2F814ac8bc%2Ff0e92a5b%2Fedda1715%2Fbig_da6639c9…

动画css ---无限旋转

前言&#xff1a; 接口返回数据&#xff0c;处理数据后&#xff0c;需要根据状态显示对应的图片 如果是状态为运行中&#xff0c;图片对应的icon图片需要沿中心点旋转起来&#xff08;加一个带有旋转的class类&#xff09; 图片素材 <!DOCTYPE html> <html lang"…

CSS——动画{旋转按钮}

前面我们一直在学习样式&#xff0c;学习布局&#xff0c;什么浮动啊&#xff0c;定位呀&#xff0c;还有弹性盒子&#xff0c;那么今天我们来看一点不一样的——动画&#xff01; 文章目录 前言一、动画是什么&#xff1f;二、动画的属性 1.过渡2.实际应用和代码演示总结 前言…

css实现加载旋转动画

先看效果&#xff1a; 完整代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&q…

CSS基础学习——动画

一、CSS3 2D变形&#xff08;利用Transfrom方法&#xff09; 1、rotate&#xff08;angle&#xff09; 元素顺时针旋转给定的角度。允许负值&#xff0c;元素将逆时针旋转。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8…