需要导出的报表的模板
处理数据及格式(行列合并、sheet页重命名)
public class ExportDailyReportService {
@Autowired
private Environment env;
public String exportDailyReport(List<DailyReportExportVo> dataList, String dateStr){
File savePath = new File(env.getProperty("excel.path"));
String number = DateUtils.formatDate(new Date(), "HHmmss");
String fileName = new StringBuilder("xxx数据日报月报").append(dateStr).append("-"+number).append(ExcelTypeEnum.XLSX.getValue()).toString();
long startTime = System.currentTimeMillis();
ExcelWriter excelWriter = null;
try {
if(!savePath.exists()){
savePath.mkdir();
}
File file = new File(savePath,fileName);
excelWriter = EasyExcel.write(file)
.registerWriteHandler(new MergeSameRowsStrategy(2,new int[]{2}))
.registerWriteHandler(new TotalMergeStrategy(dataList.size()))
.registerWriteHandler(new UpdateSheetNameStrategy())
.withTemplate(Thread.currentThread().getContextClassLoader().getResourceAsStream("templates/excel/export/DailyReportExport.xlsx")).build();
WriteSheet writeSheet = EasyExcel.writerSheet(0, dateStr.concat("日报数据")).build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
//最后一行数据需要从第二列进行合并
DailyReportExportVo dailyReportExportVo = dataList.get(dataList.size()-1);
dailyReportExportVo.setArea(dailyReportExportVo.getYqMerchantName());
Map<String, Object> map =new HashMap<>();
map.put("exportDate",dateStr);
excelWriter.fill(dataList,fillConfig,writeSheet);
excelWriter.fill(map,writeSheet);
return env.getProperty("excel.url") + fileName;
}finally{
excelWriter.finish();
log.info("export {} excel use {}ms",fileName,System.currentTimeMillis() - startTime);
}
}
class UpdateSheetNameStrategy extends AbstractSheetWriteHandler {
public UpdateSheetNameStrategy() {
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
super.afterSheetCreate(writeWorkbookHolder, writeSheetHolder);
writeWorkbookHolder.getWorkbook().setSheetName(writeSheetHolder.getSheetNo(), writeSheetHolder.getSheetName());
}
}
class MergeSameRowsStrategy implements CellWriteHandler {
private int[] mergeColumnIndex;
private int mergeRowIndex;
public MergeSameRowsStrategy() {
}
public MergeSameRowsStrategy(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 sheet保持对象
* @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();
// 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
if (curData.equals(preData)) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergedRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergedRegions.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);
}
}
}
}
class TotalMergeStrategy extends AbstractMergeStrategy {
private final int size;
public TotalMergeStrategy(int size) {
this.size = size;
}
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
// 由于每个单元格 都会调用该方法,为了避免重复合并异常,只在应合并的行、列执行即可
// 最后一行 需要开始合并的列开始合并
if (cell.getRowIndex()==size+1 && cell.getColumnIndex() == 1) {
sheet.addMergedRegionUnsafe(new CellRangeAddress(cell.getRowIndex(), cell.getRowIndex(), cell.getColumnIndex(), cell.getColumnIndex() + 4));
}
}
}
}
导出结果
例2:
package cn.com.glsx.dj.smartcarlife.service.smartcarlife;
import cn.com.glsx.dj.smartcarlife.dto.PurchaseOrderExportPageDTO;
import cn.com.glsx.dj.smartcarlife.model.PurchaseOrderGoods;
import cn.com.glsx.dj.smartcarlife.vo.excel.PurchaseOrderExportVo;
import cn.com.glsx.framework.core.util.DateUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.handler.AbstractSheetWriteHandler;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.*;
@Service
@Slf4j
public class ExportPurchaseOrderService {
@Autowired
private Environment env;
public String exportPurchaseOrder(List<PurchaseOrderExportPageDTO> dataList) {
File savePath = new File(env.getProperty("gop.excel.tem.path"));
String number = DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");
String fileName = new StringBuilder("采购订单").append("-" + number).append(ExcelTypeEnum.XLSX.getValue()).toString();
long startTime = System.currentTimeMillis();
ExcelWriter excelWriter = null;
try {
if (!savePath.exists()) {
savePath.mkdir();
}
File file = new File(savePath, fileName);
List<CellRangeAddress> addressList = new ArrayList<>();
List<PurchaseOrderExportVo> exportVoList = new ArrayList<>();
for (int i = 0; i < dataList.size(); i++) {
PurchaseOrderExportPageDTO dto = dataList.get(i);
if (i < 1) {
addressList.add(new CellRangeAddress(1, dto.getGoodsList().size(), 0, 0));
} else {
int firstRow = addressList.get(i - 1).getLastRow() + 1;
int lastRow = addressList.get(i - 1).getLastRow() + dto.getGoodsList().size();
addressList.add(new CellRangeAddress(firstRow, lastRow, 0, 0));
}
for (PurchaseOrderGoods goods : dto.getGoodsList()) {
PurchaseOrderExportVo vo = new PurchaseOrderExportVo();
BeanUtils.copyProperties(dto, vo);
BeanUtils.copyProperties(goods, vo);
exportVoList.add(vo);
}
}
excelWriter = EasyExcel.write(file)
.registerWriteHandler(new UpdateSheetNameStrategy())
.registerWriteHandler(new MergeRowsAndConvertedStrategy(1, new int[]{8, 11}, addressList))
.withTemplate(Thread.currentThread().getContextClassLoader().getResourceAsStream("templates/excel/export/采购订单导出.xlsx")).build();
WriteSheet writeSheet = EasyExcel.writerSheet(0, "采购订单").build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(exportVoList, fillConfig, writeSheet);
return env.getProperty("gop.excel.tem.url") + fileName;
} finally {
excelWriter.finish();
log.info("export {} excel use {}ms", fileName, System.currentTimeMillis() - startTime);
}
}
class UpdateSheetNameStrategy extends AbstractSheetWriteHandler {
public UpdateSheetNameStrategy() {
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
super.afterSheetCreate(writeWorkbookHolder, writeSheetHolder);
writeWorkbookHolder.getWorkbook().setSheetName(writeSheetHolder.getSheetNo(), writeSheetHolder.getSheetName());
}
}
// class MergeStrategy extends AbstractMergeStrategy {
//
// //合并开始行
//
// private Integer startRow = 0;
//
//
// //list表格所有的合并列集合
//
// private List<CellRangeAddress> addressList = null;
//
// public MergeStrategy() {
// }
//
// public MergeStrategy(int startRow, List<CellRangeAddress> addressList) {
// this.startRow = startRow;
// this.addressList = addressList;
// }
//
// @Override
// protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
// //由于每个单元格 都会调用该方法,为了避免重复合并异常,只在应合并的行、列执行即可
// //在这里判断从哪一行开始调用合并的方法
// int colIndex = cell.getColumnIndex();
// if (cell.getRowIndex() > this.startRow && colIndex >= 0 && colIndex < 12) {
if (relativeRowIndex == null || relativeRowIndex == 0) {
return;
}
// mergeRow(sheet, cell);
// }
//
// }
//
// protected void mergeRow(Sheet sheet, Cell cell) {
// int rowIndex = cell.getRowIndex();
sheet = cell.getSheet();
// int colIndex = cell.getColumnIndex();
// List<CellRangeAddress> list = this.addressList;
// for (int i = 0; i < list.size(); i++) {
// CellRangeAddress cellRangeAddress = list.get(i);
// if (cellRangeAddress.containsRow(rowIndex)) {
// //合并单元格区域只有一个单元格时,不合并
// if (cellRangeAddress.getLastRow() == cellRangeAddress.getFirstRow()) {
// return;
// }
// CellRangeAddress cra = new CellRangeAddress(cellRangeAddress.getFirstRow(), cellRangeAddress.getLastRow(), colIndex, colIndex);
log.info("{},{},{},{}",cellRangeAddress.getFirstRow(),cellRangeAddress.getLastRow(),colIndex,colIndex);
// List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
// if (mergedRegions.contains(cra)) {
// return;
// }
// sheet.addMergedRegion(cra);
// return;
// }
// }
//
// }
//
// }
class MergeRowsAndConvertedStrategy implements CellWriteHandler {
private int[] mergeColumnIndex;
private int startRow;
private List<CellRangeAddress> addressList;
public MergeRowsAndConvertedStrategy() {
}
public MergeRowsAndConvertedStrategy(int startRow, int[] mergeColumnIndex, List<CellRangeAddress> addressList) {
this.startRow = startRow;
this.mergeColumnIndex = mergeColumnIndex;
this.addressList = addressList;
}
@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) {
}
@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 >= startRow) {
for (int i = 0; i < mergeColumnIndex.length; i++) {
if (curColIndex == mergeColumnIndex[i]) {
dataConverted(cell, curColIndex);
break;
}
}
}
//行合并
if (curRowIndex > this.startRow && curColIndex >= 0 && curColIndex < 12) {
// if (relativeRowIndex == null || relativeRowIndex == 0) {
// return;
// }
Sheet sheet = writeSheetHolder.getSheet();
mergeRow(sheet, cell, curRowIndex, curColIndex);
}
}
private void mergeRow(Sheet sheet, Cell cell, int curRowIndex, int curColIndex) {
List<CellRangeAddress> list = this.addressList;
for (int i = 0; i < list.size(); i++) {
CellRangeAddress cellRangeAddress = list.get(i);
if (cellRangeAddress.containsRow(curRowIndex)) {
//合并单元格区域只有一个单元格时,不合并
if (cellRangeAddress.getLastRow() == cellRangeAddress.getFirstRow()) {
return;
}
CellRangeAddress cra = new CellRangeAddress(cellRangeAddress.getFirstRow(), cellRangeAddress.getLastRow(), curColIndex, curColIndex);
// log.info("{},{},{},{}",cellRangeAddress.getFirstRow(),cellRangeAddress.getLastRow(),colIndex,colIndex);
List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
if (mergedRegions.contains(cra)) {
return;
}
sheet.addMergedRegion(cra);
return;
}
}
}
private void dataConverted(Cell cell, int curColIndex) {
if (curColIndex == 8) {
double numericCellValue = cell.getNumericCellValue();
switch ((int) numericCellValue) {
case 1:
cell.setCellValue("未发货");
break;
case 2:
cell.setCellValue("已发货");
break;
}
} else if (curColIndex == 11) {
double numericCellValue = cell.getNumericCellValue();
switch ((int) numericCellValue) {
case 1:
cell.setCellValue("待审核");
break;
case 2:
cell.setCellValue("已审核");
break;
case 3:
cell.setCellValue("已取消");
break;
}
}
}
}
}
结果
例二的另一种做法
一对多的场景:一条订单对应多个商品
模板
导出类
package cn.com.glsx.dj.smartcarlife.vo.excel;
import cn.com.glsx.dj.smartcarlife.dto.purchase.PurchaseOrderGoodsExportDTO;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.Data;
import org.oreframework.commons.office.easyexcel.annotation.ExcelMergeRow;
import org.oreframework.commons.office.easyexcel.annotation.ExcelValueReplace;
import org.oreframework.commons.office.easyexcel.converter.ReplaceByteToStringConvert;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Data
public class PurchaseOrderExportVo implements Serializable{
private static final long serialVersionUID = 4223969010443009963L;
@ExcelMergeRow(columIndex = 0)
private Integer index;
/**
* 订单编号
*/
@ExcelMergeRow(columIndex = 1)
private String orderCode;
/**
* 订单总价
*/
@ExcelMergeRow(columIndex = 2)
private BigDecimal totalPrice;
/**
* 下单时间
*/
@ExcelMergeRow(columIndex = 3)
@DateTimeFormat(value="yyyy-MM-dd HH:mm:ss")
private Date orderTime;
/**
* 下单门店商户名称
*/
@ExcelMergeRow(columIndex = 4)
private String merchantName;
/**
* 收件人
*/
@ExcelMergeRow(columIndex = 5)
private String contactName;
/**
* 收件人电话
*/
@ExcelMergeRow(columIndex = 6)
private String contactPhone;
/**
* 收件人地址
*/
@ExcelMergeRow(columIndex = 7)
private String contactAddress;
/**
* 发货状态(1:未发货,2全部发货,3部分发货)
*/
@ExcelMergeRow(columIndex = 8)
@ExcelProperty(converter = ReplaceByteToStringConvert.class)
@ExcelValueReplace(replace={"未发货_1","已发货_2","部分发货_3"})
private Byte deliveryStatus;
/**
* 采购类型
*/
@ExcelMergeRow(columIndex = 9)
@ExcelProperty(converter = ReplaceByteToStringConvert.class)
@ExcelValueReplace(replace={"商城采购_1","自采入库_2"})
private Byte purchaseType;
/**
* 入库状态(1.未入库,2.全部入库,3部分入库)
*/
@ExcelMergeRow(columIndex = 10)
@ExcelProperty(converter = ReplaceByteToStringConvert.class)
@ExcelValueReplace(replace={"未入库_1","全部入库_2","部分入库_3"})
private Byte putStatus;
/**
* 订单状态(1.待审核,2.已审核,3.已取消,4.已驳回)
*/
@ExcelMergeRow(columIndex = 11)
@ExcelProperty(converter = ReplaceByteToStringConvert.class)
@ExcelValueReplace(replace={"运营审核_1","商务审核_2","已取消_3","已驳回_4","已审核_5"})
private Byte status;
private List<PurchaseOrderGoodsExportDTO> goodsList;
}