poi를 기반으로 테이블을 동적으로 병합
- 먼저 효과도를 보시면
왼쪽이 메인 테이블 데이터, 오른쪽이 서브 테이블 데이터로 필요에 따라 수정하시면 됩니다 아래 코드를 보겠습니다.
- 종속성 소개
<!--poi-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
</dependency>
- PoiExcel 클래스 만들기
먼저 데이터를 구성합니다. 테이블에 따라 메인 테이블과 서브 테이블이 연관되어 있으므로 메인 테이블과 서브 테이블의 데이터를 맵 컬렉션에 저장하고 메인 테이블의 값을 맵의 키로 사용합니다. , 값은 하위 테이블의 목록 모음에 해당합니다. 다음 코드를 참조할 수 있습니다.
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]);
}
이렇게 1행과 2행의 헤더를 채운 다음 해당 데이터를 채운다.메인 테이블이 먼저 채워진다.메인 테이블의 값을 구분하기 위해 "-"를 사용하므로 사용한다. a string 배열로 잘라낸 다음 메인 테이블 데이터와 해당 서브 테이블 데이터를 가져옵니다. 그런 다음 세 번째부터 시작하여 행을 만들고 메인 테이블에 데이터를 채웁니다. 채울 때 하위 테이블 목록의 크기를 판단해야 합니다. 1보다 크면 병합해야 합니다. 채운 후 기본 테이블은 하위 테이블을 채워야 합니다. 하위 테이블은 병합할 필요가 없으며 한 줄씩 채우면 됩니다. 코드는 다음과 같습니다.
//填充数据
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();
}
}
그런 다음 컨트롤러 계층의 코드:
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);
}
}
종속성을 가져온 후 코드를 복사하여 직접 사용할 수 있습니다.
작성이유: 인터넷에서 동적으로 cell을 병합하는 예를 많이 봤는데 다 이해가 안되네요. 불분명한 것은 댓글을 환영합니다. 메시지 또는 개인 메시지를 남겨주세요.