记录在遇到复杂统计报表业务时,无法使用Excel模板生成对应报表,则采用最原始poi方式进行创建生成
业务所需统计报表如下图
麻烦所在各类型订单下方餐别为动态数据,废话不多说直接上代码
new CellRangeAddress(起始行号, 终止行号, 起始列号, 终止列号);// 单元格范围
具体实现代码如下:
import cn.hutool.core.collection.CollectionUtil;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import java.io.*;
import java.util.Arrays;
import java.util.List;
/**
* <p>Title: </p>
* <p>Description: </p>
* <p>作者: AJie </p>
* <p>日期: 2024-08-09 17:03</p>
* <p>版本:1.0 </p>
*/
public class ExcelExportUtils {
/**
* 设置边框和居中
* @param workbook
*/
public static XSSFCellStyle setBorder(XSSFWorkbook workbook){
XSSFCellStyle style = workbook.createCellStyle();
style.setAlignment(HorizontalAlignment.CENTER_SELECTION);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setBorderBottom(BorderStyle.THIN);
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setBorderTop(BorderStyle.THIN);
return style;
}
public static Workbook orderMealTypeSummaryExport(List<String> cashierMealTypes,List<String> preMealTypes){
//excel文档对象
XSSFWorkbook workbook = new XSSFWorkbook();
//建立excel表单
XSSFSheet sheet = workbook.createSheet("Sheet1");
//设置边框和居中
XSSFCellStyle style = setBorder(workbook);
XSSFRow row0 = sheet.createRow(0); // Excel表格第一行
XSSFRow row1 = sheet.createRow(1); // Excel表格第二行
XSSFRow row2 = sheet.createRow(2); // Excel表格第三行
// 组合表头第0行 --- 【编号、姓名、卡类、工号、部门】
sheet.addMergedRegion(new CellRangeAddress(0, 2, 0, 0));
XSSFCell titleCell00 = row0.createCell(0);
titleCell00.setCellValue("编号");
titleCell00.setCellStyle(style);
XSSFCell titleCell00_1 = row1.createCell(0);
titleCell00_1.setCellStyle(style);
XSSFCell titleCell00_2 = row2.createCell(0);
titleCell00_2.setCellStyle(style);
sheet.addMergedRegion(new CellRangeAddress(0, 2, 1, 1));
XSSFCell titleCell01 = row0.createCell(1);
titleCell01.setCellValue("姓名");
titleCell01.setCellStyle(style);
XSSFCell titleCell01_1 = row1.createCell(1);
titleCell01_1.setCellStyle(style);
XSSFCell titleCell01_2 = row2.createCell(1);
titleCell01_2.setCellStyle(style);
sheet.addMergedRegion(new CellRangeAddress(0, 2, 2, 2));
XSSFCell titleCell02 = row0.createCell(2);
titleCell02.setCellValue("卡类");
titleCell02.setCellStyle(style);
XSSFCell titleCell02_1 = row1.createCell(2);
titleCell02_1.setCellStyle(style);
XSSFCell titleCell02_2 = row2.createCell(2);
titleCell02_2.setCellStyle(style);
sheet.addMergedRegion(new CellRangeAddress(0, 2, 3, 3));
XSSFCell titleCell03 = row0.createCell(3);
titleCell03.setCellValue("工号");
titleCell03.setCellStyle(style);
XSSFCell titleCell03_1 = row1.createCell(3);
titleCell03_1.setCellStyle(style);
XSSFCell titleCell03_2 = row2.createCell(3);
titleCell03_2.setCellStyle(style);
sheet.addMergedRegion(new CellRangeAddress(0, 2, 4, 4));
XSSFCell titleCell04 = row0.createCell(4);
titleCell04.setCellValue("部门");
titleCell04.setCellStyle(style);
XSSFCell titleCell04_1 = row1.createCell(4);
titleCell04_1.setCellStyle(style);
XSSFCell titleCell04_2 = row2.createCell(4);
titleCell04_2.setCellStyle(style);
/***组合表头第0行 --- 【编号、姓名、卡类、工号、部门】end**/
// 收银/预定订单/合计表头 ------------------
int row_0_start_index = 4; // 第一行开始位置【收银/预定名称开始位置】
// 收银餐别不为空情况
if(CollectionUtil.isNotEmpty(cashierMealTypes)){
// 第一行结束位置【收银/预定名称开始位置】
int row_0_end_index = cashierMealTypes.size()*3+row_0_start_index;
sheet.addMergedRegion(new CellRangeAddress(0, 0, row_0_start_index+1, row_0_end_index));
XSSFCell titleCell05 = row0.createCell(row_0_start_index+1);
titleCell05.setCellValue("收银订单");
titleCell05.setCellStyle(style);
for(int i=row_0_start_index+2;i<=row_0_end_index;i++){
XSSFCell titleCell05_1 = row0.createCell(i);
titleCell05_1.setCellStyle(style);
}
/**
* 生成对应【餐别】单元格
*/
createMealTypeCall(row_0_start_index,cashierMealTypes,row1,row2,style,sheet);
row_0_start_index = row_0_end_index;// 下一个单元格开始位置
}
// 预定餐别不为空情况
if(CollectionUtil.isNotEmpty(preMealTypes)){
// 第一行结束位置【收银/预定名称开始位置】
int row_0_end_index = preMealTypes.size()*3 + row_0_start_index;
sheet.addMergedRegion(new CellRangeAddress(0, 0, row_0_start_index+1, row_0_end_index));
XSSFCell titleCell06 = row0.createCell(row_0_start_index+1);
titleCell06.setCellValue("预订订单");
titleCell06.setCellStyle(style);
for(int i=row_0_start_index+2;i<=row_0_end_index ;i++){
XSSFCell titleCell06_1 = row0.createCell(i);
titleCell06_1.setCellStyle(style);
}
/**
* 生成对应【餐别】单元格
*/
createMealTypeCall(row_0_start_index,preMealTypes,row1,row2,style,sheet);
row_0_start_index = row_0_end_index;// 下一个单元格开始位置
}
// 消费合计单元格
if(CollectionUtil.isNotEmpty(cashierMealTypes) || CollectionUtil.isNotEmpty(preMealTypes) ){
// 第一行结束位置【收银/预定名称开始位置】
int row_0_end_index = 2 + row_0_start_index;
sheet.addMergedRegion(new CellRangeAddress(1, 1, row_0_start_index+1, row_0_end_index));
XSSFCell titleCell07 = row1.createCell(row_0_start_index+1);
titleCell07.setCellValue("消费合计");
titleCell07.setCellStyle(style);
for(int i=row_0_start_index+2;i<=row_0_end_index ;i++){
XSSFCell titleCell07_1 = row1.createCell(i);
titleCell07_1.setCellStyle(style);
}
XSSFCell titleCell22 = row2.createCell(row_0_start_index+1);
titleCell22.setCellValue("笔数");
titleCell22.setCellStyle(style);
XSSFCell titleCell24 = row2.createCell(row_0_end_index);
titleCell24.setCellValue("金额");
titleCell24.setCellStyle(style);
}
/*********excel表格头部内容设置end********/
return workbook;
}
/**
* 生成餐别单元格
* @param row_0_start_index
* @param mealTypeNames
* @param row1
* @param style
*/
private static void createMealTypeCall(int row_0_start_index,List<String> mealTypeNames,XSSFRow row1,XSSFRow row2,XSSFCellStyle style, XSSFSheet sheet){
int row_1_start_index = row_0_start_index+1; // 第一行餐别开始位置
// 组合表头第1行 --- 预定/收银订单餐别【"早餐","午餐","下午茶","晚餐","夜宵"】
for(String a:mealTypeNames){
// 第一行餐别结束位置
int row_1_end_index = row_1_start_index+2;
sheet.addMergedRegion(new CellRangeAddress(1, 1, row_1_start_index, row_1_end_index));
XSSFCell titleCell021 = row1.createCell(row_1_start_index);
titleCell021.setCellValue(a);
titleCell021.setCellStyle(style);
for(int i=row_1_start_index+1;i<=row_1_end_index;i++){
XSSFCell titleCell13 = row1.createCell(i);
titleCell13.setCellStyle(style);
}
String[] detailNames = {"笔数","消费标准","合计"};
// 创建对应金额详细单元格【笔数、消费标准、合计】
for(int i=row_1_start_index,j=0;i<=row_1_end_index;i++,j++){
XSSFCell titleCell22 = row2.createCell(i);
titleCell22.setCellValue(detailNames[j]);
titleCell22.setCellStyle(style);
}
row_1_start_index = row_1_end_index+1; // 下一个餐别开始位置
}
}
public static void main(String[] args) throws IOException {
List<String> aMealType = Arrays.asList(new String[]{"晚餐"});
List<String> bMealType = Arrays.asList(new String[]{"午餐","下午茶","晚餐"});
Workbook wb = orderMealTypeSummaryExport(aMealType,bMealType);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
wb.write(bos);
InputStream inputStream = new ByteArrayInputStream(bos.toByteArray());
String outputPath = "D://b.xls";
try {
saveToFile(inputStream, outputPath);
System.out.println("文件保存成功!");
} catch (IOException e) {
System.out.println("文件保存失败:" + e.getMessage());
}
}
public static void saveToFile(InputStream inStream, String outputPath) throws IOException {
try (OutputStream outStream = new FileOutputStream(outputPath)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
}
}
}
这里使用easypoi,导出工具调用poi原生jar,不涉及easypoi,可单独导入poi-4.1.1.jar,也可使用下面easypoi
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.4.0</version>
</dependency>
工具类导出Excel效果如下图:
详细案例可下载