想要達(dá)到的效果
引入maven引用
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.2.1</version>
</dependency>
按照要求創(chuàng)建模版
備注 :
模板注意 用{} 來表示你要用的變量 如果本來就有"{","}" 特殊字符 用"\{","\}"代替
// {} 代表普通變量 {.} 代表是list的變量 {前綴.} 前綴可以區(qū)分不同的list
代碼部分 :
合并策略代碼 :
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import io.jsonwebtoken.lang.Collections;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.ArrayList;
import java.util.List;
// 自定義合并策略 該類繼承了AbstractMergeStrategy抽象合并策略,需要重寫merge()方法
public class CustomMergeStrategy extends AbstractMergeStrategy {
/**
* 分組,每幾行合并一次
*/
private List<Integer> exportFieldGroupCountList;
/**
* 目標(biāo)合并列index
*/
private Integer targetColumnIndex;
// 需要開始合并單元格的首行index
private Integer rowIndex;
// exportDataList為待合并目標(biāo)列的值
public CustomMergeStrategy(List<String> exportDataList, Integer targetColumnIndex) {
this.exportFieldGroupCountList = getGroupCountList(exportDataList);
this.targetColumnIndex = targetColumnIndex;
}
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
if (null == rowIndex) {
rowIndex = cell.getRowIndex();
}
// 僅從首行以及目標(biāo)列的單元格開始合并,忽略其他
if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == targetColumnIndex) {
mergeGroupColumn(sheet);
}
}
private void mergeGroupColumn(Sheet sheet) {
int rowCount = rowIndex;
for (Integer count : exportFieldGroupCountList) {
if(count == 1) {
rowCount += count;
continue ;
}
// 合并單元格
CellRangeAddress cellRangeAddress = new CellRangeAddress(rowCount, rowCount + count - 1, targetColumnIndex, targetColumnIndex);
sheet.addMergedRegionUnsafe(cellRangeAddress);
rowCount += count;
}
}
// 該方法將目標(biāo)列根據(jù)值是否相同連續(xù)可合并,存儲可合并的行數(shù)
private List<Integer> getGroupCountList(List<String> exportDataList){
if (Collections.isEmpty(exportDataList)) {
return new ArrayList<>();
}
List<Integer> groupCountList = new ArrayList<>();
int count = 1;
for (int i = 1; i < exportDataList.size(); i++) {
if (exportDataList.get(i).equals(exportDataList.get(i - 1))) {
count++;
} else {
groupCountList.add(count);
count = 1;
}
}
// 處理完最后一條后
groupCountList.add(count);
return groupCountList;
}
}
導(dǎo)出部分 :
@Test
public void complexFillTest() throws IOException {
//正式代碼時(shí) 改成 input或者 file 傳入
String templateFileName = "D:/模版.xls";
//改成導(dǎo)出的output或者其他方式寫出 也可
String fileName = "D:/下載的文件.xls";
// 方案1
try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).excelType(ExcelTypeEnum.XLS).build()) {
//數(shù)據(jù)準(zhǔn)備 改成自己的即可
InvoiceInfo invoiceInfo = invoiceInfoService.lambdaQuery()
.eq(InvoiceInfo::getId, 21)
.one();
List<FreightOrderResponse> freightOrderResponseList = new ArrayList<>();
ArrayList<Map<String, String>> dataList = new ArrayList<>();
for (int i = 0; i < freightOrderResponseList.size(); i++) {
FreightOrderResponse freightOrderResponse = freightOrderResponseList.get(0);
Map<String, String> map = new HashMap<>();
map.put("companyName",freightOrderResponse.getComName());
if (freightOrderResponseList.size() / 2 < i){
map.put("companyName",freightOrderResponse.getComName() + "1");
}
map.put("sendAddr",freightOrderResponse.getSendProvince());
map.put("arriveAddr",freightOrderResponse.getReceiveProvince());
map.put("goodsName",freightOrderResponse.getGoodsName());
map.put("practicalFee",freightOrderResponse.getOrderPrice().toString());
dataList.add(map);
}
WriteSheet writeSheet = EasyExcel.writerSheet()
// 合并的單元格 并且將需要合并的那一列數(shù)據(jù)傳入
.registerWriteHandler(new CustomMergeStrategy(dataList.stream().map(map -> map.get("companyName")).collect(Collectors.toList()), 0))
.build();
// 這里注意 入?yún)⒂昧薴orceNewRow 代表在寫入list的時(shí)候不管list下面有沒有空行 都會創(chuàng)建一行,然后下面的數(shù)據(jù)往后移動。默認(rèn) 是false,會直接使用下一行,如果沒有則創(chuàng)建。
// forceNewRow 如果設(shè)置了true,有個(gè)缺點(diǎn) 就是他會把所有的數(shù)據(jù)都放到內(nèi)存了,所以慎用
// 簡單的說 如果你的模板有l(wèi)ist,且list不是最后一行,下面還有數(shù)據(jù)需要填充 就必須設(shè)置 forceNewRow=true 但是這個(gè)就會把所有數(shù)據(jù)放到內(nèi)存 會很耗內(nèi)存
// 如果數(shù)據(jù)量大 list不是最后一行 參照下一個(gè)
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(dataList, fillConfig, writeSheet);
Map<String, Object> map = MapUtils.newHashMap();
BigDecimal reduce = freightOrderResponseList.stream().map(obj -> obj.getOrderPrice() != null ? obj.getOrderPrice() : BigDecimal.ZERO).reduce(BigDecimal.ZERO, BigDecimal::add);
map.put("practicalFee", reduce);
map.put("customName", invoiceInfo.getCustomName());
map.put("sellerComName", invoiceInfo.getSellerComName());
excelWriter.fill(map, writeSheet);
excelWriter.finish();
}
}
最終效果 :?
參考資料 :?
官方文檔 :?
填充Excel | Easy Excel文章來源:http://www.zghlxwxcb.cn/news/detail-847303.html
合并代碼參考 :?
https://www.cnblogs.com/monianxd/p/16359369.html文章來源地址http://www.zghlxwxcb.cn/news/detail-847303.html
到了這里,關(guān)于easyExcel 模版導(dǎo)出 中間數(shù)據(jù)縱向延伸,并且對指定列進(jìn)行合并的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!