目录
前言
在使用若依框架进行前后端分离开发的过程中,经常需要处理Excel导出的功能。其中一项常见需求是根据表格的内容创建不同的工作表,以此来满足实际的业务需求。
实现效果
思路
- 初始化工作簿:使用 SXSSFWorkbook 创建一个新的工作簿实例,并指定缓存区大小为 500,以优化处理大量数据时的内存使用。
- 创建单个工作表:创建单个工作表,并通过参数传递名称以方便识别。
- 设置单元格样式:创建单元格时,不仅要写入数据,还要设置单元格样式(如表头样式),并且可以设定数据验证规则。
- 导出多页签Excel文件:为了实现多页签的Excel文件导出,遍历一个包含多个待导出数据集的列表。针对每个数据集,创建一个新工作表并设置名称。创建第一行作为列头,并使用 setCellValue 方法填充列头名称。若导出类型为导出模式,则填充实际的数据行,并根据需要添加统计行。
- 数据填充:对于每一个需要导出的对象,在 Excel 中创建或获取一行,并遍历所有需导出的字段。通过反射访问对象的私有属性,并将这些属性值写入相应的单元格中。
实现
1. 创建Excel数据传输对象
/**
* 封装导出 Excel 所需的基本信息,如文件名、标题、数据集以及数据类。
*/
public class ExcelExp {
// Sheet的名称
private String fileName;
// Sheet里的标题
private String[] handers;
// Sheet里的数据集
private List dataset;
// 数据类,用于反映数据的类型
private Class clazz;
/**
* 构造函数,初始化ExcelExp对象
*
* @param fileName 文件名
* @param dataset 数据集
* @param clazz 数据类,用于反映数据的类型
*/
public ExcelExp(String fileName, List dataset, Class clazz) {
this.fileName = fileName;
this.dataset = dataset;
this.clazz = clazz;
}
// 获取文件名
public String getFileName() {
return fileName;
}
// 设置文件名
public void setFileName(String fileName) {
this.fileName = fileName;
}
// 获取标题
public String[] getHanders() {
return handers;
}
// 设置标题
public void setHanders(String[] handers) {
this.handers = handers;
}
// 获取数据集
public List getDataset() {
return dataset;
}
// 设置数据集
public void setDataset(List dataset) {
this.dataset = dataset;
}
// 获取数据类
public Class getClazz() {
return clazz;
}
// 设置数据类
public void setClazz(Class clazz) {
this.clazz = clazz;
}
}
2. 扩展Excel工具类
2.1 创建工作薄实例
public class ExcelUtil<T> {
// ...其他属性...
/**
* 创建一个SXSSFWorkbook工作薄实例,用于后续的Excel文档操作
* 指定缓存区大小为500,以优化内存使用,适用于处理大量数据
*/
public void createWorkBook() {
this.wb = new SXSSFWorkbook(500);
}
// ...其他方法...
}
2.2 创建一个包含多个工作表的工作表组
public class ExcelUtil<T> {
// ...其他方法...
/**
* 创建一个包含多个工作表的工作表组
*
* @param index 指定要创建的工作表在工作簿中的索引位置
*
* 说明:
* 1. 该方法主要用于在Excel工作簿中创建一个新的工作表,并非创建多个工作表,方法命名可能略有误导。
* 2. 方法中设置了工作表的名称,名称通过sheetName参数传递,此处应确保sheetName在调用前已定义且有效。
* 3. 创建样式的方法createStyles在此处被调用,说明在创建工作表后,需要立即应用一系列预定义的样式。
* 4. 通过调用wb.setSheetName方法设置工作表名称,表明工作表创建后需要立即进行命名,以方便后续识别和管理。
*/
public void createSheetManySheet(int index) {
// 创建一个新的工作表
this.sheet = wb.createSheet();
// 创建样式
this.styles = createStyles(wb);
// 设置工作表的名称
wb.setSheetName(index, sheetName);
}
// ...其他方法...
}
2.3 创建单元格并设置列头信息
public class ExcelUtil<T> {
// ...其他方法...
/**
* 创建单元格并写入列信息
* 该方法用于在指定行中创建一个单元格,写入列的名称,并设置相应的样式和数据验证
*
* @param attr Excel属性,这里用于指定要写入的列名
* @param row 要创建单元格的行
* @param column 要创建的单元格的列索引
* @return 创建并设置完毕的单元格对象
*/
public Cell createCell(Excel attr, Row row, int column) {
// 创建列
Cell cell = row.createCell(column);
// 写入列信息
cell.setCellValue(attr.name());
// 设置数据验证
setDataValidation(attr, row, column);
// 设置表头样式
cell.setCellStyle(styles.get("header"));
return cell;
}
// ...其他方法...
}
2.4 实现多页签Excel文件导出功能
public class ExcelUtil<T> {
// ...其他方法...
/**
* 导出多页签Excel文件
*
* @param response 用于设置响应头和输出流
* @param list 包含多个Excel导出对象的列表,每个对象对应Excel的一个页签
* @throws IOException 当文件写入或关闭时发生IO异常
*/
public void exportExcelManySheet(HttpServletResponse response, List<ExcelExp> list) throws IOException {
// 设置HTTP响应的Content-Type,表明返回的是Excel文件
response.setContentType("application/vnd.ms-excel");
// 设置字符编码为UTF-8,确保文件名中的中文字符不被乱码
response.setCharacterEncoding("utf-8");
try {
// 初始化工作簿
createWorkBook();
// 遍历每个Excel导出对象,为每个对象创建一个页签
for (int index = 0; index < list.size(); index++) {
// 设置当前处理的类和初始化导出信息
this.clazz = list.get(index).getClazz();
this.init(list.get(index).getDataset(), list.get(index).getFileName(), Type.EXPORT);
createSheetManySheet(index);
// 创建第一行,用于写入列头
Row row = sheet.createRow(0);
int column = 0;
// 写入各个字段的列头名称
for (Object[] os : fields) {
Excel excel = (Excel) os[1];
this.createCell(excel, row, column++);
}
// 根据类型填充Excel数据并添加统计行
if (Type.EXPORT.equals(type)) {
fillExcelData(index, row);
addStatisticsRow();
}
}
// 将工作簿内容写入HTTP响应的输出流中,实现文件下载
wb.write(response.getOutputStream());
} catch (IOException e) {
// 记录并输出异常信息
log.error("导出Excel异常{}", e.getMessage());
} finally {
// 关闭工作簿和输出流,释放资源
if (wb != null) {
try {
wb.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (response.getOutputStream() != null) {
try {
response.getOutputStream().close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
// ...其他方法...
}
2.5 数据填充与单元格生成
public class ExcelUtil<T> {
// ...其他方法...
/**
* 根据提供的索引和行对象,向Excel中填充数据
*
* @param index 索引位置,用于定位数据
* @param row 行对象,代表Excel中的一行数据
*/
public void fillExcelData(int index, Row row) {
// 遍历集合list中的每个元素,即每个导出对象
for (int i = 0; i < list.size(); i++) {
// 在Excel中创建或获取当前行
row = sheet.createRow(i + 1);
// 得到导出对象
T vo = (T) list.get(i);
// 初始化列索引
int column = 0;
// 遍历需要导出的字段
for (Object[] os : fields) {
// 获取字段和其对应的Excel注解信息
Field field = (Field) os[0];
Excel excel = (Excel) os[1];
// 设置实体类私有属性可访问
field.setAccessible(true);
// 将当前字段的数据添加到Excel的单元格中
this.addCell(excel, row, vo, field, column++);
}
}
}
// ...其他方法...
}
使用示例
@PreAuthorize("@ss.hasPermi('product:data:export')")
@Log(title = "产品数据", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, ProductData productData) {
// 查询产品数据列表
List<ProductData> list1 = productDataService.selectProductDataList(productData);
List<ProductData> list2 = productDataService.selectProductDataList(productData);
// 创建Excel工作表
ExcelExp e1 = new ExcelExp("sheet1", list1, ProductData.class);
ExcelExp e2 = new ExcelExp("sheet2", list2, ProductData.class);
List<ExcelExp> sheet = new ArrayList<>();
sheet.add(e1);
sheet.add(e2);
ExcelUtilManySheet<List<ExcelExp>> utilManySheet = new ExcelUtilManySheet<>(sheet);
try {
utilManySheet.exportExcelManySheet(response, sheet);
} catch (IOException e) {
e.printStackTrace();
}
}
通过以上步骤,就可以在若依框架中实现Excel导出多工作表了。希望这篇文章能帮助你更顺利地完成项目需求!