java技术:easyexcel同时导出多个excel到web(zip压缩文件)
菜鸟蹦迪 2024-07-26 09:33:01 阅读 85
目录
环境设置
一、表头设计:
1、利用列表
2、注解形式(推荐)
二、导出zip(可实现任意个excel文件)
三、单元格策略
只要相同的列就合并
合并判断
四、动态标题实现
五、整合(动态标题+单元格合并)
实体类举例
六、感兴趣可看(封装函数说明)
参考:
环境设置
<code><!-- 阿里开源easyexcel-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.0-beta2</version>
</dependency>
一、表头设计:
1、利用列表
private static List<List<String>> head() {
List<List<String>> list = new ArrayList<>();
List<String> head0 = new ArrayList<>();
head0.add("序号");
list.add(head0);
Map<String, List<String>> map = getHeader();
map.forEach((k, v) -> {
String deviceCategory = k;
List<String> ls = v;
ls.forEach(e -> {
List<String> head = new ArrayList<>();
head.add(deviceCategory);
head.add(e);
list.add(head);
});
• });
• List<String> head1 = new ArrayList<>();
• head1.add("备注");
• list.add(head1);
• List<String> head2 = new ArrayList<>();
• head2.add("埋深");
• list.add(head2);
• return list;
}
private static Map<String, List<String>> getHeader() {
Map<String, List<String>> map = new HashMap<>();
List<String> aList = new ArrayList<>();
List<String> sList = new ArrayList<>();
List<String> subList = new ArrayList<>();
String column1 = "X";
aList.add(column1);
String column2 = "Y";
aList.add(column2);
String column3 = "B";
sList.add(column3);
String column4 = "L";
sList.add(column4);
String subColumn = "其它";
subList.add(subColumn);
subList.add("小计3");
map.put("坐标", aList);
map.put("经纬度", sList);
return map;
}
2、注解形式(推荐)
@Data
@ApiModel("角色管理")
public class TSRoleVo extends ExcelModel {
@ExcelIgnore
@ApiModelProperty("id")
private String id;
•
• @ExcelProperty(value = {"角色表列表","导出人:${title}","角色名称"} , index = 0)
• @ApiModelProperty(value = "角色名称")
• @ColumnWidth(25)
• private String roleName;//角色名称
•
@ExcelProperty(value = {"角色表列表","导出人:${title}","角色编码"} , index = 1)
@ApiModelProperty(value = "角色编码")
@ColumnWidth(25)
private String roleCode;//角色编码
@ExcelProperty(value = {"角色表列表","导出人:${title}","部门权限组ID"} , index = 2)
@ApiModelProperty(value = "部门权限组ID")
@ColumnWidth(25)
private String departAgId;//组织机构ID 部门权限组ID
@Override
public boolean validation(Map<String, List<String>> validationArgs) {
return false;
}
}
ps:
宽:@ColumnWidth(25)
内容的高:@ContentRowHeight(10)
表头的高:@HeadRowHeight(20)
二、导出zip(可实现任意个excel文件)
对于每个excel拥有两个sheet且 每个sheet实体类数据不同
public class ReceiveTaskUtils {
public static void addFileToZip(File file, ZipOutputStream zos) throws IOException {
InputStream fileInputStream = new FileInputStream(file);
//zip中要放文件称为zipEntry
ZipEntry zipEntry = new ZipEntry(file.getName());
zos.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int len;
while ((len = fileInputStream.read(bytes)) != -1) {
//读的内容会自动放到zip条目中,因此zipentry再输出流读完需要关闭
zos.write(bytes, 0, len);
}
//要关闭这个 zos.closeEntry();
zos.closeEntry();
fileInputStream.close();
}
static void deleteFile(String path) {
File file = new File(path);
if (file.exists()) {
file.delete();
}
}
/**
* 获取Date的月份
*/
static int getMonth(Date Time) {
LocalDate localDate = Time.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
int month = localDate.getMonthValue();
return month;
}
private static String formatToDate(Date receiveCliDate) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy");
String formattedDate = dateFormat.format(receiveCliDate);
return formattedDate;
}
//写到本地{
public static void export(ReceiveExportVo result, HttpServletResponse response, String type) throws Exception {
//设置输出流格式
String name = (type.contains("已完成") ? "采购完成" : "领受任务");
Date cliTime = (type.contains("已完成") ? CompleteCliDate : ReceiveCliDate);
String month=String.valueOf(getMonth(cliTime));
response.setContentType("application/zip");
response.setCharacterEncoding("UTF-8");
String fileName = name + System.currentTimeMillis() + ".zip";
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
// 创建excel文件
String fileName1 = ".\\单一来源.xlsx";
//合并策略:
int[] mergeColumeIndex ={1,2,3,4,5,6,7,8,9,10,11,12};
//从第二行后开始合并
// 调用合并单元格工具类,此工具类是没有根据合并,数据相同就合并了
String titleDate=formatToDate(ReceiveCliDate);
ExcelMergeUtil excelFillCellMergeStrategy = new ExcelMergeUtil(2,mergeColumeIndex,titleDate,month);
//设置样式 标题和内容
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//设置头居中
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//设置 水平居中
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//设置 垂直居中
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 设置垂直居中
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
log.info("创建excel之前");
try (ExcelWriter excelWriter = EasyExcel.write(fileName1).build()) {
WriteSheet writeSheet1 = EasyExcel.writerSheet(month + "月单一来源进行中项目统计")
.registerWriteHandler(excelFillCellMergeStrategy)
.registerWriteHandler(horizontalCellStyleStrategy)
.head(SingReceiveExport1Vo.class).build();
List<SingReceiveExport1Vo> singReceiveExport1VoList = result.getSingReceiveExport1VoList();
excelWriter.write(singReceiveExport1VoList, writeSheet1);
WriteSheet writeSheet2 = EasyExcel.writerSheet(month + "月已安排审价项目统计")
.registerWriteHandler(horizontalCellStyleStrategy)
.registerWriteHandler(excelFillCellMergeStrategy)
.head(SingReceiveExport2Vo.class).build();
List<SingReceiveExport2Vo> singReceiveExport2VoList = result.getSingReceiveExport2VoList();
excelWriter.write(singReceiveExport2VoList, writeSheet2);
}
String fileName2 = ".\\竞争型.xlsx";
try (ExcelWriter excelWriter = EasyExcel.write(fileName2).build()) {
WriteSheet writeSheet3 = EasyExcel.writerSheet(month + "月正在进行中竞争性采购项目")
.registerWriteHandler(horizontalCellStyleStrategy)
.registerWriteHandler(excelFillCellMergeStrategy)
.head(CompeteReceiveExport1Vo.class).build();
List<CompeteReceiveExport1Vo> competeReceiveExport1VoList = result.getCompeteReceiveExport1VoList();
excelWriter.write(competeReceiveExport1VoList, writeSheet3);
WriteSheet writeSheet4 = EasyExcel.writerSheet(month + "月已开标项目")
.registerWriteHandler(excelFillCellMergeStrategy)
.registerWriteHandler(horizontalCellStyleStrategy)
.head(CompeteReceiveExport2Vo.class).build();
List<CompeteReceiveExport2Vo> competeReceiveExport2VoList = result.getCompeteReceiveExport2VoList();
excelWriter.write(competeReceiveExport2VoList, writeSheet4);
}
//压缩路径
// String zipFilePath =".\\"+".zip";
// 创建输出流
FileOutputStream fos = new FileOutputStream(fileName);
ZipOutputStream zos = new ZipOutputStream(fos);
// 压缩文件
File file1 = new File(fileName1);
File file2 = new File(fileName2);
addFileToZip(file1, zos);
addFileToZip(file2, zos);
zos.close();
fos.close();
//将压缩文件输入流传给response输出流
InputStream fileInputStream = new FileInputStream(fileName);
OutputStream outputStream = response.getOutputStream();
byte[] bytes = new byte[1024 * 8];
int len;
while((len=fileInputStream.read(bytes))!=-1) {
outputStream.write(bytes,0,len);
}
fileInputStream.close();
outputStream.close();
// 删除文件
deleteFile(fileName1);
deleteFile(fileName2);
deleteFile(fileName);
}
}
三、单元格策略
只要相同的列就合并(图片仅供参考)
<code>import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import lombok.Data;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
@Data
public class ExcelFillCellMergeStrategy implements CellWriteHandler {
private int[] mergeColumnIndex;
private int mergeRowIndex;
public ExcelFillCellMergeStrategy() {
}
public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
//当前行
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
• if (curRowIndex > mergeRowIndex) {
• for (int i = 0; i < mergeColumnIndex.length; i++) {
• if (curColIndex == mergeColumnIndex[i]) {
• mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
• break;
• }
• }
• }
}
/**
- 当前单元格向上合并
*
- @param writeSheetHolder
- @param cell 当前单元格
- @param curRowIndex 当前行
- @param curColIndex 当前列
*/
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
//获取当前行的第一列的数据和上一行的第一列数据,通过第一行数据是否相同进行合并
// Cell preCell_now = cell.getSheet().getRow(curRowIndex ).getCell(curColIndex);
// Object curData = preCell_now.getCellTypeEnum() == CellType.STRING ? preCell_now.getStringCellValue() : preCell_now.getNumericCellValue();
// Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex - 1);
// Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
//获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
• // 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
• //
• if (curData.equals(preData)) {
• Sheet sheet = writeSheetHolder.getSheet();
• List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
• boolean isMerged = false;
• for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
• CellRangeAddress cellRangeAddr = mergeRegions.get(i);
• // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
• if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
• sheet.removeMergedRegion(i);
• cellRangeAddr.setLastRow(curRowIndex);
• sheet.addMergedRegion(cellRangeAddr);
• isMerged = true;
• }
• }
• // 若上一个单元格未被合并,则新增合并单元
• if (!isMerged) {
• CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
• sheet.addMergedRegion(cellRangeAddress);
• }
• }
}
}
合并判断(图片仅供参考)
<code>package com.ph.rfwg.util;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
public class ExcelMergeUtil implements CellWriteHandler {
private int[] mergeColumnIndex;
private int mergeRowIndex;
public ExcelMergeUtil() {
}
public ExcelMergeUtil(int mergeRowIndex, int[] mergeColumnIndex) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
//当前行
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
if (curRowIndex > mergeRowIndex) {
for (int i = 0; i < mergeColumnIndex.length; i++) {
if (curColIndex == mergeColumnIndex[i]) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
}
/**
* 当前单元格向上合并
*
* @param writeSheetHolder
* @param cell 当前单元格
* @param curRowIndex 当前行
* @param curColIndex 当前列
*/
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
// 将当前单元格数据与上一个单元格数据比较
Boolean dataBool = preData.equals(curData);
//此处需要注意:因为我是按照工程名称确定是否需要合并的,所以获取每一行第二列数据和上一行第一列数据进行比较,如果相等合并,getCell里面的值,是工程名称所在列的下标
Boolean bool = cell.getRow().getCell(1).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(1).getStringCellValue());
if (dataBool && bool) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// 若上一个单元格未被合并,则新增合并单元
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
}
四、动态标题实现
public class CustomerTitleHandler implements CellWriteHandler {
private String title;
PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("${", "}");
public CustomerTitleHandler(String title) {
this.title = title;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
if (head!=null) {
//获取一个标题列表
List<String> headNameList = head.getHeadNameList();
if (CollectionUtils.isNotEmpty(headNameList)) {
Properties properties = new Properties();
//需要多个动态变量直接在后面加,properties相当于map会自动映射
properties.setProperty("title", title);
headNameList.set(0, placeholderHelper.replacePlaceholders(headNameList.get(0), properties));
}
}
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
}
五、整合(动态标题+单元格合并)
实体类举例
/**
*需求单位联系人/电话
*/
@ColumnWidth(25)
@ExcelProperty(value={"${titleDate}","需求单位联系人/电话"})
// @ExcelProperty(value={"","需求单位联系人/电话"})
private String demandUnitPeople;
/**
*单一来源承制单位
* plan
*/
@ColumnWidth(40)
@ExcelProperty(value={"单一来源正在进行中审价项目统计","单一来源承制单位"})
private String singleSourceProvider;
/**
*承制单位联系人及电话
*/
@ColumnWidth(40)
@ExcelProperty(value={"单一来源正在进行中审价项目统计","承制单位联系人及电话"})
private String manufacturerPhone;
package com.example.procurementmanagement.util;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.CellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.util.PropertyPlaceholderHelper;
import java.util.List;
import java.util.Properties;
/**
* author:lanjie
* 单元格合并策略
* describe:合并相同字段的列,但需要判断首列是否合并(条件合并)
* ps:可复用
*/
@Slf4j
public class ExcelMergeUtil implements CellWriteHandler {
//需要合并的列数组
private int[] mergeColumnIndex;
//合并起始行
private int mergeRowIndex;
private String titleDate;
private String titleMonth;
PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("${", "}");
public ExcelMergeUtil(int mergeRowIndex, int[] mergeColumnIndex,String titleDate,String titleMonth) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
this.titleDate=titleDate;
this.titleMonth=titleMonth;
}
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
List<String> headNameList = head.getHeadNameList();
if (CollectionUtils.isNotEmpty(headNameList)){
Properties properties = new Properties();
properties.setProperty("titleDate", titleDate);
properties.setProperty("titleMonth", titleMonth);
headNameList.set(0, placeholderHelper.replacePlaceholders(headNameList.get(0), properties));
log.info("headNameList:{}",headNameList);
}
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
log.info("定义单元格以后!");
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
//当前行
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
if (curRowIndex > mergeRowIndex) {
for (int i = 0; i < mergeColumnIndex.length; i++) {
if (curColIndex == mergeColumnIndex[i]) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
}
/**
* 当前单元格向上合并
*
* @param writeSheetHolder
* @param cell 当前单元格
* @param curRowIndex 当前行
* @param curColIndex 当前列
*/
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
// 将当前单元格数据与上一个单元格数据比较
Boolean dataBool = preData.equals(curData);
//此处需要注意:因为我是按照工程名称确定是否需要合并的,所以获取每一行第二列数据和上一行第一列数据进行比较,如果相等合并,getCell里面的值,是工程名称所在列的下标
Boolean bool = cell.getRow().getCell(1).getStringCellValue().equals(cell.getSheet().getRow(curRowIndex - 1).getCell(1).getStringCellValue());
if (dataBool && bool) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// 若上一个单元格未被合并,则新增合并单元
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
}
六、感兴趣可看(封装函数说明)
1、 PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("${", "}");
PropertyPlaceholderHelper
的构造函数接受两个参数,分别是前缀和后缀。在你的例子中,PropertyPlaceholderHelper("${", "}")
表示创建了一个 PropertyPlaceholderHelper
实例,用于识别以 "${" 开头、以 "}" 结尾的占位符。
2、properties.setProperty("title", title);
上述代码将在属性文件中设置一个名为 "title" 的键,并将变量 title
的值作为其对应的值。也就是说,title
变量的值将被保存在属性文件中,以后可以通过该键来获取它。
题中 headNameList.set(0, placeholderHelper.replacePlaceholders(headNameList.get(0), properties));
是将properties(相当于map)中的键和你设置的动态标题进行匹配映射,因此可以直接往里面加任意个
对于为什么这里是0,因为标题分多级标题,headNameList获取的是该单元格所在列的所有标题放在一个字符串数组中,因此一级标题的索引是0,当然如果是改其他标题,你只需要更换索引进行映射即可。
3、replacePlaceholders()
方法接受两个参数:
template
是包含占位符的原始字符串,即待替换的字符串。可以是 "点个赞吧${man}"其中man是动态标题
name
是要替换占位符 ${name}
的实际值。
String resolvedString = placeholderHelper.replacePlaceholders(template, name);
七、可选字段导出(补充,结果图没展示)
package com.example.procurementmanagement.util;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ExcelFillCellMergeStrategyChooseField implements CellWriteHandler {
private int[] mergeColumnIndex;
private int mergeRowIndex;
// 需要导出的列名集合
private Set<String> exportColumnNames;
public ExcelFillCellMergeStrategyChooseField() {
}
public ExcelFillCellMergeStrategyChooseField(int mergeRowIndex, int[] mergeColumnIndex,List<String> exportColumnNames) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
this.exportColumnNames = new HashSet<>(exportColumnNames);
}
private boolean isColumnExported(String colName) {
return exportColumnNames.contains(colName);
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
//当前行
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
// 获取当前列的列名
String colName = head.getHeadNameList().get(0);
// 如果当前列不在导出列名集合中,隐藏该列
if (!isColumnExported(colName)) {
cell.getSheet().setColumnHidden(curColIndex, true);
return;
}
if (curRowIndex > mergeRowIndex) {
for (int columnIndex : mergeColumnIndex) {
if (curColIndex == columnIndex) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
}
/**
* 当前单元格向上合并
*
* @param cell 当前单元格
* @param curRowIndex 当前行
* @param curColIndex 当前列
*/
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
//获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
// 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
// 比较 当前行第三列数据(项目编号) 与上一行是否相同 控制后续列与 第3列数据合并状态相同
Cell curCellCol3 = cell.getRow().getCell(0);
Object curCellCol3Data = new Object();
if (curCellCol3!=null){
curCellCol3Data = curCellCol3.getCellTypeEnum() == CellType.STRING ?
curCellCol3.getStringCellValue() : curCellCol3.getNumericCellValue();
}
Cell preCellCol3 = cell.getSheet().getRow(curRowIndex - 1).getCell(0);
Object preCellCol3Data = preCellCol3.getCellTypeEnum() == CellType.STRING ?
preCellCol3.getStringCellValue() : preCellCol3.getNumericCellValue();
if (curData.equals(preData)) {
// 第二列避开判断,第二列需要合并
// if (curColIndex==1){
// Sheet sheet = writeSheetHolder.getSheet();
// List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
// boolean isMerged = false;
// for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
// CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
// if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
// sheet.removeMergedRegion(i);
// cellRangeAddr.setLastRow(curRowIndex);
// sheet.addMergedRegion(cellRangeAddr);
// isMerged = true;
// }
// }
// // 若上一个单元格未被合并,则新增合并单元
// if (!isMerged) {
// CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
// sheet.addMergedRegion(cellRangeAddress);
// }
// }
if(curCellCol3Data.equals(preCellCol3Data)&&curCellCol3!=null){
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// 若上一个单元格未被合并,则新增合并单元
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
}
ps:改动部分
新增一个字段
private Set<String> exportColumnNames;//传入表头
public ExcelFillCellMergeStrategyChooseField(int mergeRowIndex, int[] mergeColumnIndex,List<String> exportColumnNames) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
this.exportColumnNames = new HashSet<>(exportColumnNames);
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
//当前行
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
// 获取当前列的列名
String colName = head.getHeadNameList().get(0);
// 如果当前列不在导出列名集合中,隐藏该列
if (!isColumnExported(colName)) {
cell.getSheet().setColumnHidden(curColIndex, true);
return;
}
if (curRowIndex > mergeRowIndex) {
for (int columnIndex : mergeColumnIndex) {
if (curColIndex == columnIndex) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
}
结果
本地
导出结果:
上传到web
excel结果:
参考:
表头设计参考
单元合并参考链接
导入推荐,感觉用起来不错
有问题可留言!
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。