自定義註解 - 實體轉Excel
一、環境準備
由於平時工作中,經常會有這種,將某個列表的數據導出成excel的需求。此功能就屬於比較通用的功能了,於是呢,爲了避免重複代碼,就設計了此種方式進行實現。
博主這裏創建的 springboot 2.2.1.RELEASE
項目。使用的 jdk1.8
+ poi 3.16
, 另外日誌用到了 lombok 1.18.10
。
1、JDK安裝配置
參考我的另外一篇博客:
鏈接: JDK安裝配置-swotXu.
2、MAVEN安裝配置
參考我的另外一篇博客:
鏈接: MAVEN安裝配置-swotXu.
3、POM依賴引入
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.16</version>
</dependency>
二、代碼演示
先來看看怎麼使用。大家如果覺得使用比較方便有趣,咱們再看看怎麼實現的。
這裏使用的幾個封裝類簡單介紹下:
- ExcelParse2SheetAdapte 對象
實體數據解析與ExcelSheet
的適配器,用於將實體數據集 轉換爲ExcelSheet
對象
提供ExcelSheet getExcelSheet(String title, boolean hasOrderNum)
方法獲取對象。 - ExcelSheet 對象
承載excel映射的對象,封裝了對於POI相關操作,用於生成excel。 - ExcelHandle 對象
工具類,用於將ExcelSheet
對象輸出生成具體的excel文件。
支持生成到具體磁盤目錄、輸出到指定流、web端直接輸出下載三種方式。 - HandleTimer 對象
HandleTimer.runTime() 是用來統計方法耗時的一個工具類
詳細信息可參考我的另外一篇文章:
鏈接: JDK1.8 - lamda 接口耗時統計-swotXu.
import com.swotxu.verifyideas.common.algorithm.timer.HandleTimer;
import com.swotxu.verifyideas.demo02.pojo.PeopleEntity;
import com.swotxu.verifyideas.demo02.utils.ExcelHandle;
import com.swotxu.verifyideas.demo02.utils.ExcelParse2SheetAdapte;
import com.swotxu.verifyideas.demo02.utils.ExcelSheet;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
/**
* @Classname: springboot-parent
* @Date: 2019/12/16 0016 13:48
* @Author: swotXu
*/
public class TestMain {
/**
* 生成測試數據 list
* @return
*/
public static List<PeopleEntity> getTestDataList(){
List<PeopleEntity> dataList = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
PeopleEntity entity = new PeopleEntity();
entity.setIdCard(UUID.randomUUID().toString());
entity.setName("name" + i);
entity.setAge(random.nextInt(100));
entity.setSex(random.nextBoolean()? "男" : "女");
dataList.add(entity);
}
return dataList;
}
public static void execute(){
// 獲取測試數據
List<PeopleEntity> dataList1 = getTestDataList();
// 根據實體數據,獲取excelSheet的適配器
ExcelParse2SheetAdapte<PeopleEntity> sheetAdapte1 = new ExcelParse2SheetAdapte(dataList1, PeopleEntity.class);
// 通過適配器拿到 excelSheet 對象,設置標題,開啓序號列
ExcelSheet sheet1 = sheetAdapte1.getExcelSheet("測試table1", ExcelSheet.USE_ORDER_NUMBER);
// 獲取測試數據
List<PeopleEntity> dataList2 = getTestDataList();
// 根據實體數據,獲取excelSheet的適配器
ExcelParse2SheetAdapte<PeopleEntity> sheetAdapte2 = new ExcelParse2SheetAdapte(dataList2, PeopleEntity.class);
// 通過適配器拿到 excelSheet 對象,設置標題,關閉序號列
ExcelSheet sheet2 = sheetAdapte2.getExcelSheet("測試table2", ExcelSheet.DEL_ORDER_NUMBER);
// 可以手動設置單元格樣式, 也可不設置 - 使用默認樣式
sheet2.setBodyColumnTopStyleFun(workbook -> {
// 設置字體
HSSFFont font = workbook.createFont();
font.setFontHeightInPoints((short)10); //設置字體大小
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); //字體加粗
font.setFontName("Courier New"); //設置字體名字
//設置樣式;
HSSFCellStyle style = workbook.createCellStyle();
style.setBorderBottom(HSSFCellStyle.BORDER_THIN); //設置底邊框;
style.setFont(font); //在樣式用應用設置的字體;
return style;
});
// 通過 ExcelHandle 設置sheet頁,並輸出到指定目錄
ExcelHandle.builder().setSheet(sheet1).setSheet(sheet2).build("D:\\test\\files\\test.xls");
}
public static void main(String[] args) {
// HandleTimer.runTime() 是用來統計方法耗時的一個工具類
HandleTimer.runTime(TestMain::execute);
}
}
import com.swotxu.verifyideas.demo02.annotation.ExcelColunm;
import lombok.Getter;
import lombok.Setter;
/**
* @Date: 2019/12/14 22:47
* @Author: swotXu
*/
public class PeopleEntity {
@Getter
@Setter
@ExcelColunm(colunmName = "姓名", order = 20)
private String name;
@Getter
@Setter
@ExcelColunm(colunmName = "性別", order = 10)
private String sex;
@Getter
@Setter
@ExcelColunm(colunmName = "年齡", order = 40)
private int age;
@Getter
@Setter
@ExcelColunm(colunmName = "身份證", order = 30)
private String idCard;
}
上面代碼演示生成有兩個sheet頁的excel。
sheet1,使用默認樣式,開啓序號列,結果如下
sheet2,使用指定樣式,關閉序號列,結果如下
三、代碼實現
咱們先看看類結構圖:
1、@ExcelColunm 註解
我們先來創建一個 @ExcelColunm
註解,用於標記實體屬性上。
其中:
colunmName
用於標識實體屬性與excel中table表列的映射關係
order
用於標識excel中table表列的排列順序
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 此註解標記於實體屬性上,用於聲明實體轉Excel表頭的對應關係
* @Date: 2019/12/14 21:51
* @Author: swotXu
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ExcelColunm {
/**
* Excel 列名
* @return
*/
String colunmName() default "";
/**
* 列排序 由小到大
* @return
*/
int order() default 0;
}
2、ExcelColunmParse
接下來,編寫解析註解的工具類
ExcelColunmParse
用於解析實體上的 @ExcelColunm
註解
import com.swotxu.verifyideas.demo02.annotation.ExcelColunm;
import com.swotxu.verifyideas.demo02.pojo.PeopleEntity;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @ExcelColunm 的解析工具
*
* @Date: 2019/12/14 21:53
* @Author: swotXu
*/
@Slf4j
public class ExcelColunmParse {
public static void main(String[] args) {
List<ParseResult> results = parseExcelColunm(PeopleEntity.class);
log.info("{}", results);
}
/**
* 解析實體類中 @ExcelColunm
* @param aClass
* @return
*/
public static List<ParseResult> parseExcelColunm(Class<?> aClass){
return Arrays.stream(aClass.getDeclaredFields())
// 類型轉換:將 field 對象轉換爲 ParseResult 對象
.map(field -> {
if (field.isAnnotationPresent(ExcelColunm.class)) {
ExcelColunm excelColunm = field.getAnnotation(ExcelColunm.class);
ParseResult parseResult = new ParseResult(field.getName()
, excelColunm.colunmName(), excelColunm.order());
return parseResult;
}
return null;
})
// 過濾空對象
.filter(parseResult -> parseResult != null)
// 根據 order 排序
.sorted((r1, r2) -> r1.getOrder() - r2.getOrder())
.collect(Collectors.toList());
}
/**
* @ExcelColunm 解析後的封裝對象
*/
public static class ParseResult {
@Getter
@Setter
private String sourceKey;
@Getter
@Setter
private String colunmName;
@Getter
@Setter
private int order;
private ParseResult(String sourceKey, String colunmName, int order) {
this.sourceKey = sourceKey;
this.colunmName = colunmName;
this.order = order;
}
}
}
3、ExcelSheet
然後,創建ExcelSheet
對象,封裝poi對excel的操作
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
/**
* @Date: 2019/12/15 17:01
* @Author: swotXu
*/
@Slf4j
@SuppressWarnings("deprecation")
public class ExcelSheet {
/**開啓序號列 默認開啓*/
public static final boolean USE_ORDER_NUMBER = true;
/**關閉序號列*/
public static final boolean DEL_ORDER_NUMBER = false;
public static final String ORDER_NUMBER_NAME = "序號";
// 是否開啓序號列
private boolean hasOrderNum;
// 顯示的導出表的標題
private String title;
// 導出表的列名
private String[] rowNames;
// 數據集
private List<List<Object>> dataList;
/** 列頭單元格樣式 */
@Setter
private Function<HSSFWorkbook, HSSFCellStyle> headColumnTopStyleFun;
/** 列數據信息單元格樣式 */
@Setter
private Function<HSSFWorkbook, HSSFCellStyle> bodyColumnTopStyleFun;
//構造方法,傳入要導出的數據
public ExcelSheet(String title, String[] rowNames, List<List<Object>> dataList, boolean hasOrderNum){
this.title = title;
this.rowNames = rowNames;
this.dataList = dataList;
this.hasOrderNum = hasOrderNum;
this.headColumnTopStyleFun = ExcelSheet::getHeadColumnTopStyle;
this.bodyColumnTopStyleFun = ExcelSheet::getBodyColumnTopStyle;
}
/**
* 生成excel數據
* @return
*/
public HSSFWorkbook createExcel(){
return createExcel(new HSSFWorkbook());
}
/**
* 生成excel數據
* @param workbook 創建工作簿對象
* @return
*/
public HSSFWorkbook createExcel(HSSFWorkbook workbook){
try{
// sheet 單元格樣式定義, 表頭 和 表數據樣式
HSSFCellStyle headColumnTopStyle = this.headColumnTopStyleFun.apply(workbook);
HSSFCellStyle bodyColumnTopStyle = this.bodyColumnTopStyleFun.apply(workbook);
//單元格樣式對象
HSSFSheet sheet = workbook.createSheet(title); // 創建工作表
// 產生表格標題行
setColumnHeadData(sheet, headColumnTopStyle, rowNames.length);
//將查詢出的數據設置到sheet對應的單元格中
setColumnBodyData(sheet, bodyColumnTopStyle);
//讓列寬隨着導出的列長自動適應
setColumnAutoWidth(sheet, rowNames.length);
return workbook;
}catch(Exception e){
log.warn("Create workbook failed!", e);
}
return null;
}
/**
* 生成excel table 表頭
* @param sheet sheet對象
* @param headColumnTopStyle 表頭樣式
* @param columnNum 列數量
*/
private void setColumnHeadData(HSSFSheet sheet, HSSFCellStyle headColumnTopStyle, int columnNum){
// 產生表格標題行
HSSFRow rowm = sheet.createRow(0);
HSSFCell cellTiltle = rowm.createCell(0);
// 設置title
sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, hasOrderNum?rowNames.length:rowNames.length-1));
cellTiltle.setCellStyle(headColumnTopStyle);
cellTiltle.setCellValue(title);
HSSFRow rowRowName = sheet.createRow(2); // 在索引2的位置創建行(最頂端的行開始的第二行)
// 若開啓序號,將列頭設置到sheet的單元格中
if(hasOrderNum){
setSerialNumber(rowRowName, headColumnTopStyle);
}
HSSFCell cellRowName;
for(int n=0; n<columnNum; n++){
// 創建列頭對應個數的單元格 -- 若開啓序號列,則 n+1
cellRowName = rowRowName.createCell(hasOrderNum? n + 1 : n);
cellRowName.setCellType(HSSFCell.CELL_TYPE_STRING); //設置列頭單元格的數據類型
cellRowName.setCellValue(new HSSFRichTextString(rowNames[n])); //設置列頭單元格的值
cellRowName.setCellStyle(headColumnTopStyle); //設置列頭單元格樣式
}
}
/**
* 將查詢出的數據設置到sheet對應的單元格中
*
* @param sheet sheet對象
* @param bodyColumnTopStyle 數據列樣式
*/
private void setColumnBodyData(HSSFSheet sheet, HSSFCellStyle bodyColumnTopStyle){
for(int i=0;i<dataList.size();i++){
List<Object> objList = dataList.get(i);//遍歷每個對象
HSSFRow row = sheet.createRow(i+3);//創建所需的行數
HSSFCell cell; //設置單元格的數據類型
if(hasOrderNum){
cell = row.createCell(0, HSSFCell.CELL_TYPE_NUMERIC);
cell.setCellValue(i+1);
cell.setCellStyle(bodyColumnTopStyle);
}
for(int j=0; j < objList.size(); j++){
cell = row.createCell(hasOrderNum? j + 1 : j,HSSFCell.CELL_TYPE_STRING);
if(!Objects.isNull(objList.get(j))){
cell.setCellValue(objList.get(j).toString()); //設置單元格的值
}
cell.setCellStyle(bodyColumnTopStyle); //設置單元格樣式
}
}
}
/**
* 讓列寬隨着導出的列長自動適應
* @param sheet sheet對象
* @param columnNum 列數量
*/
private void setColumnAutoWidth(HSSFSheet sheet, int columnNum){
for (int colNum = 0; colNum < columnNum; colNum++) {
int columnWidth = sheet.getColumnWidth(colNum) / 256;
for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {
HSSFRow currentRow;
//當前行未被使用過
if (sheet.getRow(rowNum) == null) {
currentRow = sheet.createRow(rowNum);
} else {
currentRow = sheet.getRow(rowNum);
}
if (currentRow.getCell(colNum) != null) {
HSSFCell currentCell = currentRow.getCell(colNum);
if (currentCell != null && currentCell.getCellType() == HSSFCell.CELL_TYPE_STRING && currentCell.getStringCellValue() != null) {
int length = currentCell.getStringCellValue().getBytes().length;
if (columnWidth < length) {
columnWidth = length;
}
}
}
}
if(colNum == 0){
try{
columnWidth = (columnWidth-2) * 256;
}catch(Exception e){
columnWidth = 1024;
e.printStackTrace();
}
sheet.setColumnWidth(colNum, columnWidth);
}else{
try{
columnWidth = (columnWidth+4) * 256;
}catch(Exception e){
columnWidth = 1024;
e.printStackTrace();
}
sheet.setColumnWidth(colNum, columnWidth);
}
}
}
/**
* 設置序號列
* @param rowRowName 行對象
* @param columnTopStyle 單元格樣式對象
*/
private static void setSerialNumber(HSSFRow rowRowName, HSSFCellStyle columnTopStyle){
HSSFCell cellRowName = rowRowName.createCell(0);
cellRowName.setCellType(HSSFCell.CELL_TYPE_STRING); //設置列頭單元格的數據類型
HSSFRichTextString text = new HSSFRichTextString(ORDER_NUMBER_NAME);
cellRowName.setCellValue(text); //設置列頭單元格的值
cellRowName.setCellStyle(columnTopStyle);
}
/*
* 默認列頭單元格樣式
*/
private static HSSFCellStyle getHeadColumnTopStyle(HSSFWorkbook workbook) {
// 設置字體
HSSFFont font = workbook.createFont();
//設置字體大小
font.setFontHeightInPoints((short)11);
//字體加粗
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
//設置字體名字
font.setFontName("Courier New");
//設置樣式;
HSSFCellStyle style = workbook.createCellStyle();
//設置底邊框;
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//設置底邊框顏色;
style.setBottomBorderColor(HSSFColor.BLACK.index);
//設置左邊框;
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
//設置左邊框顏色;
style.setLeftBorderColor(HSSFColor.BLACK.index);
//設置右邊框;
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
//設置右邊框顏色;
style.setRightBorderColor(HSSFColor.BLACK.index);
//設置頂邊框;
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
//設置頂邊框顏色;
style.setTopBorderColor(HSSFColor.BLACK.index);
//在樣式用應用設置的字體;
style.setFont(font);
//設置自動換行;
style.setWrapText(false);
//設置水平對齊的樣式爲居中對齊;
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//設置垂直對齊的樣式爲居中對齊;
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
return style;
}
/*
* 默認列數據信息單元格樣式
*/
private static HSSFCellStyle getBodyColumnTopStyle(HSSFWorkbook workbook) {
// 設置字體
HSSFFont font = workbook.createFont();
//設置字體大小
//font.setFontHeightInPoints((short)10);
//字體加粗
//font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
//設置字體名字
font.setFontName("Courier New");
//設置樣式;
HSSFCellStyle style = workbook.createCellStyle();
//設置底邊框;
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//設置底邊框顏色;
style.setBottomBorderColor(HSSFColor.BLACK.index);
//設置左邊框;
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
//設置左邊框顏色;
style.setLeftBorderColor(HSSFColor.BLACK.index);
//設置右邊框;
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
//設置右邊框顏色;
style.setRightBorderColor(HSSFColor.BLACK.index);
//設置頂邊框;
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
//設置頂邊框顏色;
style.setTopBorderColor(HSSFColor.BLACK.index);
//在樣式用應用設置的字體;
style.setFont(font);
//設置自動換行;
style.setWrapText(false);
//設置水平對齊的樣式爲居中對齊;
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//設置垂直對齊的樣式爲居中對齊;
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
return style;
}
}
4、ExcelParse2SheetAdapte
接下來,創建ExcelParse2SheetAdapte
,將實體對象集轉換爲 ExcelSheet
對象
package com.swotxu.verifyideas.demo02.utils;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @Date: 2019/12/15 23:03
* @Author: swotXu
*/
@Slf4j
public class ExcelParse2SheetAdapte<T> {
/**
* excel表頭
*/
private String[] rowsName;
/**
* excel數據體
*/
private List<List<Object>> dataList;
public ExcelParse2SheetAdapte(List<T> entityList, Class<T> aClass){
entity2ExcelSheetAdapte(entityList, aClass);
}
/**
* 實體對象與ExcelSheet適配 生成表頭及表單數據
* @param entityList
* @param aClass
*/
private void entity2ExcelSheetAdapte(List<T> entityList, Class<T> aClass){
List<ExcelColunmParse.ParseResult> parseResults = ExcelColunmParse.parseExcelColunm(aClass);
// Excel 表頭
String[] rowsName = parseResults.stream().<String>map(result -> result.getColunmName()).toArray(String[]::new);
// Excel 數據集
List<List<Object>> dataList = new ArrayList(entityList.size());
List<Object> datas;
// 解析數據實體集
for (T entity : entityList) {
datas = new ArrayList(rowsName.length);
// 解析數據實體屬性
for (ExcelColunmParse.ParseResult parseResult : parseResults) {
try {
Field f = aClass.getDeclaredField(parseResult.getSourceKey());
f.setAccessible(true);
Object o = f.get(entity);
datas.add(Objects.isNull(o)? "" : o);
} catch (Exception e) {
log.warn("Failed to get entity properties!", e);
}
}
dataList.add(datas);
}
this.rowsName = rowsName;
this.dataList = dataList;
}
/**
* 獲取ExcelSheel對象
* @param title 生成標題名
* @param hasOrderNum 是否生成排序號
* @return
*/
public ExcelSheet getExcelSheet(String title, boolean hasOrderNum){
return new ExcelSheet(title, rowsName, dataList, hasOrderNum);
}
}
5、ExcelHandle
最後,通過工具類ExcelHandle
,將 ExcelSheet
對象生成excel,輸出到指定目標
package com.swotxu.verifyideas.demo02.utils;
import com.swotxu.verifyideas.common.file.utils.FileStreamUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @Date: 2019/12/14 23:13
* @Author: swotXu
*/
@Slf4j
public class ExcelHandle {
@Getter
private HSSFWorkbook workbook = new HSSFWorkbook();
private ExcelHandle(){}
public static ExcelHandle builder(){
return new ExcelHandle();
}
/**
* 設置 sheet 頁
* @param sheet
* @return
*/
public ExcelHandle setSheet(ExcelSheet sheet){
sheet.createExcel(this.workbook);
return this;
}
/**
* 導出到指定路徑
* @param path
*/
public boolean build(String path){
try {
FileOutputStream out = new FileOutputStream(new File(path));
return build(out);
} catch (FileNotFoundException e) {
log.warn("Failed to get file stream!", e);
}
return false;
}
/**
* 導出到指定輸出流
* @param out
*/
public boolean build(OutputStream out){
boolean isOk = false;
try{
workbook.write(out);
out.flush();
isOk = true;
} catch (IOException e){
log.warn("workbook write failure!", e);
} finally {
FileStreamUtil.close(out);
}
return isOk;
}
/**
* 頁面導出下載 Excel
* @param response
* @param fileName 無後綴文件名
*/
public boolean build(HttpServletResponse response, String fileName) {
boolean isOk = false;
OutputStream out = null;
try{
response.setCharacterEncoding("utf-8");
response.setContentType("application/vnd.ms-excel");
response.addHeader(
"Content-Disposition",
"attachment;filename=" + new String(fileName.getBytes("GBK"), "ISO-8859-1") + ".xls");
out = response.getOutputStream();
workbook.write(out);
out.flush();
isOk = true;
} catch (IOException e){
e.printStackTrace();
} finally {
FileStreamUtil.close(out);
}
return isOk;
}
}
6、FileStreamUtil
補充下,評論區有小夥伴留言詢問,這個類是做什麼的?
這個工具類,是用來統一關閉IO流資源的,下面貼一下源碼
package com.swotxu.verifyideas.common.file.utils;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
/**
* @Date: 2019/12/16 21:25
* @Author: swotXu
*/
@Slf4j
public class FileStreamUtil {
public static void close(OutputStream out){
if (null != out){
try {
out.close();
} catch (IOException e) {
log.warn("OutputStream close failed!", e);
}
}
}
public static void close(InputStream in){
if (null != in){
try {
in.close();
} catch (IOException e) {
log.warn("InputStream close failed!", e);
}
}
}
public static void close(Writer writer){
if (null != writer){
try {
writer.close();
} catch (IOException e) {
log.warn("Writer close failed!", e);
}
}
}
public static void close(Reader reader){
if (null != reader){
try {
reader.close();
} catch (IOException e) {
log.warn("Reader close failed!", e);
}
}
}
}
至此,通過自定義註解 @ExcelColunm
將實體集轉爲 excel 功能就完成了。
大家如果有什麼疑問,歡迎評論留言!別忘了收藏關注~