Java SpringBoot使用easyExcel,瀏覽器下載
目錄
簡單title向下補充表格
like this

創建一個data類(CargoRightsExcelData),定義每一列需要導出的字段
package com.zmy.agency.cargo.data;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
@Data
public class CargoRightsExcelData {
// 列寬
@ColumnWidth(24)
// 列的標題
@ExcelProperty({" "})
// 字段數據
private String category;
@ColumnWidth(18)
@ExcelProperty({"在途", "立方數"})
private Double onWayQuantity;
。。。。。。
@ColumnWidth(18)
@ExcelProperty({"合計", "立方米"})
private Double sumQuantity;
@ColumnWidth(18)
@ExcelProperty({"合計", "金額"})
private Double sumAmount;
}
路由層
/**
* Controller文件
* excel導出
*/
// 正常應該用GET請求,我這里需要傳的是一個對象,所以用了POST請求
@PostMapping(value = "/excel")
public void statisticsExcel(HttpServletResponse response, @RequestBody CargoRightsStatisticsDto cargoRightsDto) throws UnsupportedEncodingException {
if (cargoRightsDto.getCargoRights() != null || cargoRightsDto.getCargoRights().length > 0) {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 這里URLEncoder.encode可以防止中文亂碼 當然和easyexcel沒有關系
String fileName = URLEncoder.encode(DateUtil.getCurrentDateTimeStr() + "貨權統計表", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xls");
// 填充數據
marketPriceService.exportExcel(response, cargoRightsDto);
}
}
服務impl層
@Override
public JsonResult exportExcel(HttpServletResponse response, CargoRightsStatisticsDto cargoRights) {
JsonResult result = new JsonResult();
result.setCode(200);
try {
// 拿到需要導出的數據,根據自己的業務邏輯自行編寫
List<Map<String, Object>> datas = cargoStatisticsWhole(cargoRights);
// 初始化前面定義的data類為一個數組
List<CargoRightsExcelData> cargoRightsExcelDataList = new ArrayList<>();
// 開始填充data
for (Map<String, Object> data: datas) {
CargoRightsExcelData cargoRightsExcelData = new CargoRightsExcelData();
String keyName = data.get("name") == null ? "未定義" : (String) data.get("name");
String name = " ".repeat((int) data.get("deep")) + keyName;
cargoRightsExcelData.setCategory(name);
cargoRightsExcelData.setOnWayQuantity((Double) data.get("on_way_quantity"));
cargoRightsExcelData.setOnWayAmount((Double) data.get("on_way_amount"));
cargoRightsExcelData.setStockQuantity((Double) data.get("stock_quantity"));
cargoRightsExcelData.setStockAmount((Double) data.get("stock_amount"));
cargoRightsExcelData.setSumQuantity((Double) data.get("sum_quantity"));
cargoRightsExcelData.setSumAmount((Double) data.get("sum_amount"));
cargoRightsExcelDataList.add(cargoRightsExcelData);
// 寫入easyExcel流,在這一步,其實表格就已經生成了
EasyExcel.write(
response.getOutputStream(),
CargoRightsExcelData.class
).sheet("貨權統計").doWrite(cargoRightsExcelDataList);
return result;
} catch (IOException e) {
result.setCode(406);
result.setMessage(e.getMessage());
return result;
}
}
復雜的模板填充
這也是我特別想記錄的
首先,我也是參考別的代碼在做
查閱到這一片時,EasyExcel模板填充踩坑, 給我留下的印象就是導出輔助data類,不能用駝峰法
查閱到這一片時,easyExcel使用模板填充式的導出,我照着寫了一下
比較有意思的一點就是,兩篇,我都只看見了map數據,沒有看到初始化輔助data那一行代碼(我沒注意看,所以我的代碼沒用到輔助data類,但是,我是寫完了,生效了,才發現沒用上的,哈啊哈)
所以我的完成過程如下
先准備一個excel導出模板

行數據要用x.字段命名
路由層
/**
* Controller文件
* 導出出入庫單據的表格
*/
@GetMapping(value = "/out-in-excel/{id}")
public JsonResult outInExcel(@PathVariable("id") String id, HttpServletResponse response) throws IOException {
if (StringUtils.isBlank(id)){
return JsonResult.error("ID未找到!");
}
OrderRecord order = orderRecordService.getById(id);
if (order == null) {
return JsonResult.error("ID未找到!");
}
String fileName;
if ("inStock".equals(order.getType())) {
fileName = "入庫通知單_" + DateUtil.getCurrentDateTimeStr();
} else if ("outStock".equals(order.getType())) {
fileName = "出庫通知單_" + DateUtil.getCurrentDateTimeStr();
} else {
return JsonResult.error("錯誤的數據類型");
}
// 定義文件流
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String excelFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
// excelFileName: 文件名
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + excelFileName + ".xls");
OutputStream outputStream = response.getOutputStream();
// 將id和outputStream文件流傳入服務層
JsonResult result = orderRecordService.outInExcelById(id, outputStream);
return result;
}
服務層impl
@Override
public JsonResult outInExcelById(String id, OutputStream outputStream) {
// 定義在報錯情況下返回的內容
JsonResult result = new JsonResult();
result.setCode(200);
// 拿到需要導出的數據,根據你的業務需求自行處理
OrderRecord order = baseMapper.selectById(id);
try {
// 定位模板文件的base位置
String basePath = PathKit.getWebRootPath() + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator;
// 定位模板文件的最終位置
String templateName;
Map<String, Object> data = new HashMap<>();
if ("inStock".equals(order.getType())) {
templateName = basePath + "templates/in_order_template.xls";
} else if ("outStock".equals(order.getType())) {
templateName = basePath + "templates/out_order_template.xls";
} else {
return JsonResult.error("錯誤的數據類型");
}
// outputStream文件流寫入EasyExcel,使用withTemplate方法調用模板(參數就是模板文件的路徑)
ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(templateName).build();
// 創建一個頁簽
WriteSheet writeSheet = EasyExcel.writerSheet().build();
// 寫入數據,這里就是只會出現一次的數據
data.put("local_date", order.getOrderDate().toString());
data.put("code", order.getCode());
data.put("custody_display", order.getCustodyDisplay());
data.put("storehouse_display", order.getStorehouseDisplay());
data.put("stockist_display", order.getStockistDisplay());
data.put("pick_up_display", order.getPickUpDisplay());
// 這里定義一個自動填充需要遍歷的表格類| NewRow(Boolean.TRUE) 自動換行
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
/**
* 這里比較有意思的 就是,因為第一篇博客的影響,我給表格的字段使用的都是下划線的形式,但是我的數據都是駝峰的形式
* 導致我的數據寫不進去,這時我才意識到我寫的輔助data類沒有到用到,但是我並不想研究怎么用,我就死馬當做活馬醫,
* 試一下我直接在模板里面改成駝峰命名看能不能生效,於是乎,it`s work!
*/
// 設置自動遍歷填充,a的取值內容為order.getOrderRecordLines(),這是一個O2M字段的數據
excelWriter.fill(new FillWrapper("a", order.getOrderRecordLines()), fillConfig, writeSheet);
// 將data的數據完整填充進excelWriter
excelWriter.fill(data, writeSheet);
// 關閉文件流
excelWriter.finish();
return result;
} catch (Exception e) {
return JsonResult.error(e.toString());
}
}
結論
成功了!

回過頭我真的很好奇我沒有用到輔助data類,就又倒回去查看前面的博客
這一片是定義一個不變的map數據,一個是需要便利的數據結合我的代碼可以得出結論
可變的遍歷數據,如果模板的取值和我的數據一致,可以不用定義輔助data類,Nice!
似乎,我能這樣寫,還得益於,我的模型定義,外鍵關聯我都會再定義一個顯示字段的緣故。
like this:
/**
* 存貨方
*/
private String stockistId;
/**
* 存貨方Display
*/
@TableField(exist = false)
private String stockistDisplay;
/**
* 指定倉庫
*/
private String storehouseId;
/**
* 指定倉庫Display
*/
@TableField(exist = false)
private String storehouseDisplay;
還有一個弊端:如果你取出來的數據還需要處理,要么你再在數據層定義一個字段,要么就只能老老實實寫輔助data類,先給data輔助,再將data賦值給excelWriter

