使用EasyPoi完成復(fù)雜一對(duì)多excel表格導(dǎo)出功能全過(guò)程
業(yè)務(wù)需求
從一個(gè)簡(jiǎn)單的倉(cāng)庫(kù)業(yè)務(wù)說(shuō)起,倉(cāng)庫(kù)業(yè)務(wù),會(huì)有進(jìn)庫(kù)記錄,會(huì)有出庫(kù)記錄,會(huì)有庫(kù)存,客戶的需求就是需要一個(gè)庫(kù)存盤點(diǎn)單,盤點(diǎn)單通俗來(lái)講:將庫(kù)存中每個(gè)商品的出入庫(kù)記錄都統(tǒng)計(jì)出來(lái),看看每個(gè)商品出過(guò)多少貨物,入過(guò)多少貨物,本月庫(kù)存多少,上月庫(kù)存多少。
需求難點(diǎn)
一個(gè)貨物會(huì)出過(guò)多次貨物,入過(guò)多次貨物,導(dǎo)出的 excel 就要做成 一對(duì)多 格式的導(dǎo)出
簡(jiǎn)單舉例:
啤酒:入庫(kù)2次,出庫(kù)3次,最終體現(xiàn)在 excel 中效果如下圖:
通過(guò) EasyPoi 實(shí)現(xiàn)需求
EasyPoi 文檔地址:http://doc.wupaas.com/docs/easypoi/easypoi-1c0u4mo8p4ro8
SpringBoot 使用:
<dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-base</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-annotation</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-web</artifactId> <version>4.2.0</version> </dependency>
Gradle 使用:
implementation 'cn.afterturn:easypoi-base:4.2.0' implementation 'cn.afterturn:easypoi-annotation:4.2.0' implementation 'cn.afterturn:easypoi-web:4.2.0'
使用 EasyPoi 提供的注解,自定義導(dǎo)出類模板
import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.excel.annotation.ExcelCollection; import cn.afterturn.easypoi.excel.annotation.ExcelIgnore; import lombok.Getter; import lombok.Setter; import java.io.Serializable; import java.math.BigDecimal; import java.util.Date; import java.util.List; /** * 導(dǎo)出 excel 模板類 */ @Getter @Setter public class ExportTemplate implements Serializable { @Excel(name = "序號(hào)", needMerge = true, type = 10) private int index; @Excel(name = "商品名稱", needMerge = true, width = 30.0) private String goodName; @Excel(name = "商品單位", needMerge = true) private String goodUnit; @Excel(name = "上月庫(kù)存數(shù)量", needMerge = true, type = 10) private Integer lastMonthSurplusNum; @Excel(name = "本月庫(kù)存數(shù)量", needMerge = true, type = 10) private Integer thisMonthSurplusNum; @ExcelCollection(name = "本月入庫(kù)信息") private List<GoodInItem> goodInItems; @ExcelCollection(name = "本月出庫(kù)信息") private List<GoodOutItem> goodOutItems; @Excel(name = "備注", needMerge = true, width = 30.0) private String remark; /** * 入庫(kù)信息 */ @Getter @Setter public static class GoodInItem { @Excel(name = "入庫(kù)日期", exportFormat = "yyyy-MM-dd", width = 20.50) private Date purchaseDate; @Excel(name = "入庫(kù)號(hào)", width = 25.50) private String purchaseNum; @Excel(name = "入庫(kù)單價(jià)", type = 10) private BigDecimal unitPrice; @Excel(name = "入庫(kù)數(shù)量", type = 10) private Integer totalNum; } /** * 出庫(kù)信息 */ @Getter @Setter public static class GoodOutItem { @Excel(name = "出庫(kù)日期", exportFormat = "yyyy-MM-dd", width = 20.50) private Date outDate; @Excel(name = "出庫(kù)號(hào)", width = 25.50) private String sellNum; @Excel(name = "出庫(kù)數(shù)量", type = 10) private Integer totalNum; @Excel(name = "成本金額", type = 10) private BigDecimal priceIn; @Excel(name = "銷售金額", type = 10) private BigDecimal priceOut; } }
實(shí)體類中使用的注解作用解釋:
- 1.@Getter lombok 注解,用于給所有屬性提供 getter 方法
- 2.@Setter lombok 注解,用于給所有屬性提供 setter 方法
- 3.@Excel easypoi 注解,name 就等于導(dǎo)出 excel 的列名稱,width 就是寬度,type 就是這個(gè)屬性的類型,1表示文本,默認(rèn)也是文本,10就是數(shù)字,needMerge 表示是否縱向合并單元格,也就是上下列合并
- 4.@ExcelCollection easypoi 注解,name 就等于導(dǎo)出 excel 的列名稱,被此注解標(biāo)注的集合,就等于在其列下面創(chuàng)建對(duì)等數(shù)量的行,就類似于這種
最后模板弄好之后,就可以通過(guò)easypoi 的工具類來(lái)導(dǎo)出,easypoi 推薦的導(dǎo)出工具類如下:
這個(gè)方法的三個(gè)參數(shù)表示含義解釋:
ExportParams
:參數(shù)表示Excel 導(dǎo)出參數(shù)設(shè)置類,easypoi 自定義的類pojoClass
:你要導(dǎo)出的類模板dataSet
:數(shù)據(jù)集合
具體實(shí)現(xiàn)
@GetMapping(value = "export") public void export(HttpServletRequest req, HttpServletResponse resp) { List<ExportTemplate> exportData = new ArrayList(); // 步驟1:構(gòu)建要導(dǎo)出excel的數(shù)據(jù)集合 for (int i = 0; i < 5; i++) { ExportTemplate data = new ExportTemplate(); data.setIndex(i); data.setGoodName("測(cè)試商品"); data.setGoodUnit("瓶"); data.setLastMonthSurplusNum(5); // 上月庫(kù)存 data.setThisMonthSurplusNum(3); // 本月庫(kù)存 // ... 剩下的就是類似的加值 exportData.add(data); } try { // 步驟2:開始導(dǎo)出 excel ExportParams params = new ExportParams(); params.setTitle("庫(kù)存盤點(diǎn)單標(biāo)題"); params.setSheetName("庫(kù)存盤點(diǎn)單工作表名稱"); params.setType(ExcelType.XSSF); Workbook workbook = ExcelExportUtil.exportExcel(params, ExportTemplate.class, exportData); String nowStr = DateTimeFormatter.ofPattern(LocalDateTime.now()).format("yyyyMMddHHmm"); // 時(shí)間串 String fileName = nowStr + "_庫(kù)存盤點(diǎn)單"; // 文件名稱 String tempDir = "C:/Users/huxim/Downloads"; File filePath = new File(tempDir + File.separator); if (!filePath.exists()) filePath.mkdirs(); // 如果文件目錄不存在就創(chuàng)建這個(gè)目錄 FileOutputStream fos = new FileOutputStream(tempDir + File.separator + fileName); workbook.write(fos); fos.close(); resp.setContentType("application/octet-stream"); resp.setCharacterEncoding("utf-8"); response.addHeader("Content-disposition", "attachment; filename=" + this.makeDownloadFileName(req, fileName)); IOUtils.copy(new FileInputStream(tempFile), response.getOutputStream()); System.out.println("導(dǎo)出成功~~~"); } catch (Exception e) { throw new RuntimeException("導(dǎo)出 excel 失敗~~~"); } } /** * 判斷是否是 IE 瀏覽器 * 返回對(duì)應(yīng)的字符串格式 */ public static String makeDownloadFileName(HttpServletRequest request, String fileName) { String agent = request.getHeader("User-Agent"); byte[] bytes = fileName.getBytes(StandardCharsets.UTF_8); if (agent.contains("MSIE") || agent.contains("Trident") || agent.contains("Edge")) { // IE return new String(bytes, StandardCharsets.UTF_8); } else { return new String(bytes, StandardCharsets.ISO_8859_1); } }
導(dǎo)出成功后的excel 就類似于如下這種:
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring @Profile注解實(shí)現(xiàn)多環(huán)境配置
這篇文章主要介紹了Spring @Profile注解實(shí)現(xiàn)多環(huán)境配置,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04springboot項(xiàng)目防止XSS攻擊和sql注入方式
這篇文章主要介紹了springboot項(xiàng)目防止XSS攻擊和sql注入方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07mybatisPlus如何使用MetaObjectHandler對(duì)字段進(jìn)行更新
這篇文章主要介紹了mybatisPlus如何使用MetaObjectHandler對(duì)字段進(jìn)行更新問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04java數(shù)據(jù)結(jié)構(gòu)之樹基本概念解析及代碼示例
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)之樹基本概念解析及代碼示例,介紹了樹的定義,基本術(shù)語(yǔ),主要操作及實(shí)現(xiàn)等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可了解下。2017-11-11mybatis動(dòng)態(tài)sql之新增與更新方式
這篇文章主要介紹了mybatis動(dòng)態(tài)sql之新增與更新方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07SpringBoot整合JWT框架,解決Token跨域驗(yàn)證問(wèn)題
Json web token (JWT), 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn)((RFC 7519).定義了一種簡(jiǎn)潔的,自包含的方法用于通信雙方之間以JSON對(duì)象的形式安全的傳遞信息。2021-06-06@Accessors(chain = true)注解報(bào)錯(cuò)的解決方案
這篇文章主要介紹了@Accessors(chain = true)注解報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06