前面我們介紹了 SpringBoot 中使用 JeecgBoot 的 Autopoi 匯出 Excel,其實 Autopoi 的底層也是 EasyPoi,對于 Excel 的匯入/匯出也是非常方便的,那 EasyPoi 也是基于 POI 的,如果對這方面想要深究的,可以先看看原生 POI 的匯入/匯出方式,你會回來選擇 EasyPoi 的
一、簡介
EasyPoi 功能如同名字 easy,主打的功能就是容易,讓一個沒見接觸過poi的人員就可以方便的寫出 Excel 匯出,Excel 模板匯出,Excel 匯入,Word 模板匯出,通過簡單的注解和模板語言(熟悉的運算式語法),完成以前復雜的寫法
如果想了解 JeecgBoot 的 Autopoi,可以參考我的另一篇博客,SpringBoot 中使用 JeecgBoot 的 Autopoi 匯出 Excel
https://blog.csdn.net/qq_40065776/article/details/107824221
二、引入 EasyPoi
EasyPoi 在 SpringBoot 中也是做了很好的封裝,讓我們能夠在 SpringBoot 快速地使用 EasyPoi 進行開發
<!-- easypoi -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.2.0</version>
</dependency>
我們只需要引入這一個依賴即可,這是對 SpringBoot 做了很好的支持
三、原始碼解讀
1、@Excel 原始碼解讀
通過查閱原始碼,我們不難從 cn.afterturn.easypoi.excel.annotation.Excel 注解中發現
/**
* Copyright 2013-2015 JueYue (qrb.jueyue@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.afterturn.easypoi.excel.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Excel 匯出基本注釋
* @author JueYue
* 2014年6月20日 下午10:25:12
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel {
/**
* 匯出時,對應資料庫的欄位 主要是用戶區分每個欄位, 不能有annocation重名的 匯出時的列名
* 匯出排序跟定義了annotation的欄位的順序有關 可以使用a_id,b_id來確實是否使用
*/
public String name();
/**
* 展示到第幾個可以使用a_id,b_id來確定不同排序
*/
public String orderNum() default "0";
/**
* 值得替換 匯出是{a_id,b_id} 匯入反過來,所以只用寫一個
*/
public String[] replace() default {};
/**
* 字典名稱
*/
public String dict() default "";
}
以上是 @Excel 注解的代碼片段,我們可以看出該注解中支持兩種字典替換方式
- 1、replace,該方式支持直接寫入注解引數中,如:
@Excel(name = "性別", width = 15, replace = "男_1,女_2")
@TableField("sex")
private Integer sex;
我們用 1 表示 男性,2 表示 女性,這樣我們在匯出的時候,就能夠自動替換掉資料中的魔法值,但是這樣我們往往要在注解引數中寫入過多的代碼,而且我們的字典往往是動態變化的,這樣的局限性太大
- 2、dict,字典方式,傳入字典引數中,如:
@Excel(name = "性別", width = 15, dict = "sex")
@TableField("sex")
private Integer sex;
這里我們只傳入的字典的 key,這樣我們在查詢出資料的時候,寫入 Excel 檔案時,在進行動態替換,即可替換掉資料中的魔法值,增加資料的可讀性
2、IExcelDictHandler 原始碼解讀
上一步,我們已經知道了在 EasyPoi 中是支持自定義字典查詢匯出的,那么我們該如何實作它呢?通過閱讀 cn.afterturn.easypoi.handler.inter.IExcelDictHandler 介面中的代碼,代碼如下:
package cn.afterturn.easypoi.handler.inter;
import java.util.List;
import java.util.Map;
/**
* @author jueyue on 18-2-2.
* @version 3.0.4
*/
public interface IExcelDictHandler {
/**
* 回傳字典所有值
* key: dictKey
* value: dictValue
* @param dict 字典Key
* @return
*/
default public List<Map> getList(String dict) {
return null;
}
/**
* 從值翻譯到名稱
*
* @param dict 字典Key
* @param obj 物件
* @param name 屬性名稱
* @param value 屬性值
* @return
*/
public String toName(String dict, Object obj, String name, Object value);
/**
* 從名稱翻譯到值
*
* @param dict 字典Key
* @param obj 物件
* @param name 屬性名稱
* @param value 屬性值
* @return
*/
public String toValue(String dict, Object obj, String name, Object value);
}
介面中提供了三個方法:
- 1、getList,通過字典 key 查詢該 key 下的所有字典資料,例如:sex 下的 {“1”:“男”, “2”:“女”}
- 2、toName,字典的翻譯功能,從值翻譯到名稱,例如:sex: 1 --> “男”,一般匯出的時候使用
- 3、toValue,與 toName 相反,從名稱翻譯到值,例如:sex: “男” --> 1,一般匯入的時候使用
既然我們知道在 EasyPoi 中提供了字典翻譯的介面,那我們只需要提供一個實作類,重寫介面中的方法即可,IExcelDictHandlerImpl.java 實作 IExcelDictHandler 介面,代碼如下:
package com.zyxx.common.excel;
import cn.afterturn.easypoi.handler.inter.IExcelDictHandler;
import com.zyxx.sys.service.SysDictDetailService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* 支持字典引數設定
* 舉例: @Excel(name = "性別", width = 15, dicCode = "sex")
* 1、匯出的時候會根據字典配置,把值1,2翻譯成:男、女;
* 2、匯入的時候,會把男、女翻譯成1,2存進資料庫;
*
* @Author lizhou
*/
@Slf4j
@Component
public class IExcelDictHandlerImpl implements IExcelDictHandler {
@Autowired
private SysDictDetailMapper testSysDictDetailMapper;
private static SysDictDetailMapper sysDictDetailMapper;
@PostConstruct
public void init() {
sysDictDetailMapper = this.testSysDictDetailMapper;
}
/**
* 從值翻譯到名稱
*
* @param dict 字典Key
* @param obj 物件
* @param name 屬性名稱
* @param value 屬性值
* @return
*/
@Override
public String toName(String dict, Object obj, String name, Object value) {
return sysDictDetailMapper.getTextByDictAndValue(dict, String.valueOf(value));
}
/**
* 從名稱翻譯到值
*
* @param dict 字典Key
* @param obj 物件
* @param name 屬性名稱
* @param value 屬性值
* @return
*/
@Override
public String toValue(String dict, Object obj, String name, Object value) {
return null;
}
}
- 1、這里我們匯出,只使用了 toName(從值翻譯到名稱)這個方法,所以,只寫了一個方法
- 2、我們需要使用 @Component 注解將它加載到 Spring 容器中
- 3、@PostConstruct 該注解被用來修飾一個非靜態的 void() 方法,被 @PostConstruct 修飾的方法會在服務器加載 Servlet 的時候運行,并且只會被服務器執行一次,PostConstruct 在建構式之后執行,init() 方法之前執行
四、開始匯出
1、定義物體類
package com.zyxx.sys.entity;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.zyxx.common.annotation.Dict;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 用戶資訊表
* </p>
*
* @author lizhou
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("sys_user_info")
@ApiModel(value = "SysUserInfo物件", description = "用戶資訊表")
public class SysUserInfo extends Model<SysUserInfo> {
@ApiModelProperty(value = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Excel(name = "姓名", width = 15)
@ApiModelProperty(value = "姓名")
@TableField("name")
private String name;
@Excel(name = "電話", width = 15)
@ApiModelProperty(value = "電話")
@TableField("phone")
private String phone;
@Excel(name = "性別", width = 15, dict = "sex")
@TableField("sex")
@Dict(dictCode = "user_sex")
private Integer sex;
@Excel(name = "狀態", width = 15, dict = "status")
@TableField("status")
private Integer status;
}
@Excel 注解解釋如下:
- name,表頭名稱
- width,列寬
- dict,字典 key
2、匯出 API 介面
controller 層提供匯出 API
@ApiOperation(value = "匯出用戶資訊", notes = "匯出用戶資訊")
@GetMapping(value = "/export")
public void exportXls(HttpServletResponse response) {
// 查詢資料
List<SysUserInfo> list = sysUserInfoService.list(1, Integer.MAX_VALUE);
// 匯出資料,資料,資料型別,檔案名稱,表名,回應物件
ExportExcelUtil.exportExcel(list, SysUserInfo.class, "用戶資訊表", "用戶資訊統計", response);
}
3、匯出工具類
/**
* 匯出excel
*
* @param list 資料集合
* @param pojoClass 資料型別
* @param fileName 檔案名稱
* @param title 表明
* @param response 回應物件
*/
public static void exportExcel(List<?> list, Class<?> pojoClass, String fileName, String title, HttpServletResponse response) {
ExportParams exportParams = new ExportParams(title, null);
// 自定義字典查詢規則
exportParams.setDictHandler(new IExcelDictHandlerImpl());
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
if (workbook != null) {
try {
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
workbook.write(response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
}
exportParams.setDictHandler(new IExcelDictHandlerImpl());,我們傳入了自定義的字典查詢規則
五、測驗匯出
我們調取匯出資料的 API 介面,即可匯出檔案,匯出效果如下:


六、總結
可以看出,自定義字典查詢匯出方式,其實和 JeecgBoot 的 Autopoi 方式都大同小異,后面是發現了 JeecgBoot 的 Autopoi 和 hutool 的讀取檔案 ExcelReader 有沖突,放棄了 JeecgBoot 的 Autopoi,EasyPoi 確實是一款強大的 Excel 操作產品!!!
如您在閱讀中發現不足,歡迎留言!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/206187.html
標籤:其他
