簡書三(SpringBoot實現(xiàn)Excel導(dǎo)入導(dǎo)出)

想實現(xiàn)Excel報表的導(dǎo)入導(dǎo)出,首先想到的就是POI蝶锋,POI的API確實麻煩,需要我們逐行解析什往。

EasyPoi一款非常好用的Excel導(dǎo)入導(dǎo)出工具扳缕。

EasyPoi正是這么一款工具,如果你不太熟悉POI别威,想簡單地實現(xiàn)Excel操作躯舔,用它就對了!

EasyPoi的目標(biāo)不是替代POI省古,而是讓一個不懂導(dǎo)入導(dǎo)出的人也能快速使用POI完成Excel的各種操作粥庄,而不是看很多API才可以完成這樣的工作。

在SpringBoot中集成EasyPoi非常簡單衫樊,只需添加如下一個依賴即可飒赃,真正的開箱即用!

1.添加依賴

<dependency>

? ? <group>cn.afterturn</group>

? ? <artifactId>easypoi-spring-boot-starter</artifactId>

? ? <version>4.4.0</version>

</dependency>

2.使用場景

以會員信息和訂單信息的導(dǎo)入導(dǎo)出為例科侈,分別實現(xiàn)下簡單的單表導(dǎo)出和具有關(guān)聯(lián)信息的復(fù)雜導(dǎo)出载佳。

3.簡單導(dǎo)出

以會員信息列表導(dǎo)出為例,使用EasyPoi來實現(xiàn)下導(dǎo)出功能臀栈,看看是不是夠簡單蔫慧!

首先創(chuàng)建一個會員對象Member,封裝會員信息权薯;

@Data

@EqualsAndHashCode(callSuper?=?false)

public?classMember{

????@Excel(name?=?"ID",?width?=?10)

????private?Long?id;

????@Excel(name?=?"用戶名",?width?=?20,?needMerge?=?true)

????private?String?username;

????private?String?password;

????@Excel(name?=?"昵稱",?width?=?20,?needMerge?=?true)

????private?String?nickname;

????@Excel(name?=?"出生日期",?width?=?20,?format?=?"yyyy-MM-dd")

????private?Date?birthday;

????@Excel(name?=?"手機(jī)號",?width?=?20,?needMerge?=?true,?desensitizationRule?=?"3_4")

????private?String?phone;

????private?String?icon;

????@Excel(name?=?"性別",?width?=?10,?replace?=?{"男_0",?"女_1"})

????private?Integer?gender;

}

在此我們就可以看到EasyPoi的核心注解@Excel姑躲,通過在對象上添加@Excel注解睡扬,可以將對象信息直接導(dǎo)出到Excel中去,下面對注解中的屬性做個介紹黍析;

name:Excel中的列名卖怜;

width:指定列的寬度;

needMerge:是否需要縱向合并單元格阐枣;

format:當(dāng)屬性為時間類型時马靠,設(shè)置時間的導(dǎo)出導(dǎo)出格式;

desensitizationRule:數(shù)據(jù)脫敏處理蔼两,3_4表示只顯示字符串的前3位和后4位甩鳄,其他為*號;

replace:對屬性進(jìn)行替換额划;

suffix:對數(shù)據(jù)添加后綴妙啃。

接下來我們在Controller中添加一個接口,用于導(dǎo)出會員列表到Excel俊戳,具體代碼如下揖赴;

@Controller

@Api(tags?=?"EasyPoiController",?description?=?"EasyPoi導(dǎo)入導(dǎo)出測試")

@RequestMapping("/easyPoi")

public?classEasyPoiController{

? @ApiOperation(value?=?"導(dǎo)出會員列表Excel")

? @RequestMapping(value?=?"/exportMemberList",?method?=?RequestMethod.GET)

? ?publicvoidexportMemberList(ModelMap?map,HttpServletRequest?request,HttpServletResponse?res????????ponse){

? ? ? ?List<Member>?memberList?=?LocalJsonUtil.getListFromJson("json/members.json",?Member.clas);

? ? ? ?ExportParams?params?=?new?ExportParams("會員列表",?"會員列表",?ExcelType.XSSF);

? ? ? ?map.put(NormalExcelConstants.DATA_LIST,?memberList);

? ? ? ?map.put(NormalExcelConstants.CLASS,?Member.class);

? ? ? ?map.put(NormalExcelConstants.PARAMS,?params);

? ? ? ?map.put(NormalExcelConstants.FILE_NAME,?"memberList");

? ? ? ?PoiBaseView.render(map,?request,?response,?NormalExcelConstants.EASYPOI_EXCEL_VIEW);

????}

}

LocalJsonUtil工具類,可以直接從resources目錄下獲取JSON數(shù)據(jù)并轉(zhuǎn)化為對象品抽,例如此處使用的members.json储笑;

運行項目甜熔,直接通過Swagger訪問接口圆恤,注意在Swagger中訪問接口無法直接下載,需要點擊返回結(jié)果中的下載按鈕才行腔稀,訪問地址:http://localhost:8088/swagger-ui/

下載完成后盆昙,查看下文件,一個標(biāo)準(zhǔn)的Excel文件已經(jīng)被導(dǎo)出了焊虏。

4.簡單導(dǎo)入

在Controller中添加會員信息導(dǎo)入的接口淡喜,這里需要注意的是使用@RequestPart注解修飾文件上傳參數(shù),否則在Swagger中就沒法顯示上傳按鈕了诵闭;

@Controller

@Api(tags?=?"EasyPoiController",?description?=?"EasyPoi導(dǎo)入導(dǎo)出測試")

@RequestMapping("/easyPoi")

public?classEasyPoiController{

????@ApiOperation("從Excel導(dǎo)入會員列表")

????@RequestMapping(value?=?"/importMemberList",?method?=?RequestMethod.POST)

????@ResponseBody

????publicCommonResultimportMemberList(@RequestPart("file")MultipartFile?file){

????????ImportParams?params?=?new?ImportParams();

????????params.setTitleRows(1);

????????params.setHeadRows(1);

????????try?{

????????????List<Member>?list?=?ExcelImportUtil.importExcel(

????????????????????file.getInputStream(),

????????????????????Member.class,params);

????????????return?CommonResult.success(list);

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????????return?CommonResult.failed("導(dǎo)入失斄锻拧!");

????????}

????}

}

然后在Swagger中測試接口疏尿,選擇之前導(dǎo)出的Excel文件即可瘟芝,導(dǎo)入成功后會返回解析到的數(shù)據(jù)。

5.復(fù)雜導(dǎo)出

當(dāng)然EasyPoi也可以實現(xiàn)更加復(fù)雜的Excel操作褥琐,比如導(dǎo)出一個嵌套了會員信息和商品信息的訂單列表锌俱,下面我們來實現(xiàn)下!

首先添加商品對象Product敌呈,用于封裝商品信息贸宏;

@Data

@EqualsAndHashCode(callSuper?=?false)

public?classProduct{

????@Excel(name?=?"ID",?width?=?10)

????private?Long?id;

????@Excel(name?=?"商品SN",?width?=?20)

????private?String?productSn;

????@Excel(name?=?"商品名稱",?width?=?20)

????private?String?name;

????@Excel(name?=?"商品副標(biāo)題",?width?=?30)

????private?String?subTitle;

????@Excel(name?=?"品牌名稱",?width?=?20)

????private?String?brandName;

????@Excel(name?=?"商品價格",?width?=?10)

????private?BigDecimal?price;

????@Excel(name?=?"購買數(shù)量",?width?=?10,?suffix?=?"件")

????private?Integer?count;

}

然后添加訂單對象Order造寝,訂單和會員是一對一關(guān)系,使用@ExcelEntity注解表示吭练,訂單和商品是一對多關(guān)系诫龙,使用@ExcelCollection注解表示,Order就是我們需要導(dǎo)出的嵌套訂單數(shù)據(jù)鲫咽;

@Data

@EqualsAndHashCode(callSuper?=?false)

public?classOrder{

????@Excel(name?=?"ID",?width?=?10,needMerge?=?true)

????private?Long?id;

????@Excel(name?=?"訂單號",?width?=?20,needMerge?=?true)

????private?String?orderSn;

????@Excel(name?=?"創(chuàng)建時間",?width?=?20,?format?=?"yyyy-MM-dd?HH:mm:ss",needMerge?=?true)

????private?Date?createTime;

????@Excel(name?=?"收貨地址",?width?=?20,needMerge?=?true?)

????private?String?receiverAddress;

????@ExcelEntity(name?=?"會員信息")

????private?Member?member;

????@ExcelCollection(name?=?"商品列表")

????private?List<Product>?productList;

}

接下來在Controller中添加導(dǎo)出訂單列表的接口赐稽,由于有些會員信息我們不需要導(dǎo)出,可以調(diào)用ExportParams中的setExclusions方法排除掉浑侥;

@Controller

@Api(tags?=?"EasyPoiController",?description?=?"EasyPoi導(dǎo)入導(dǎo)出測試")

@RequestMapping("/easyPoi")

public?classEasyPoiController{

@ApiOperation(value?=?"導(dǎo)出訂單列表Excel")

@RequestMapping(value?=?"/exportOrderList",?method?=?RequestMethod.GET)

publicvoidexportOrderList(ModelMap?map,HttpServletRequest?request,HttpServletResponse?response){

? ? ? List<Order>?orderList?=?getOrderList();

? ? ? ExportParams?params?=?new?ExportParams("訂單列表",?"訂單列表",?ExcelType.XSSF);

? ? ? //導(dǎo)出時排除一些字段

? ? ? params.setExclusions(new?String[]{"ID",?"出生日期",?"性別"});

? ? ? map.put(NormalExcelConstants.DATA_LIST,?orderList);

? ? ? map.put(NormalExcelConstants.CLASS,?Order.class);

? ? ? map.put(NormalExcelConstants.PARAMS,?params);

? ? ? map.put(NormalExcelConstants.FILE_NAME,?"orderList");

? ? ? PoiBaseView.render(map,?request,?response,?NormalExcelConstants.EASYPOI_EXCEL_VIEW);

????}

}

在Swagger中訪問接口測試姊舵,導(dǎo)出訂單列表對應(yīng)Excel;

6.自定義處理

如果你想對導(dǎo)出字段進(jìn)行一些自定義處理寓落,EasyPoi也是支持的括丁,比如在會員信息中,如果用戶沒有設(shè)置昵稱伶选,我們添加下暫未設(shè)置信息史飞。

我們需要添加一個處理器繼承默認(rèn)的ExcelDataHandlerDefaultImpl類,然后在exportHandler方法中實現(xiàn)自定義處理邏輯仰税;

public?classMemberExcelDataHandlerextendsExcelDataHandlerDefaultImpl{

??@Override

??publicObjectexportHandler(Member?obj,?String?name,?Object?value){

????if("昵稱".equals(name)){

??????String?emptyValue?=?"暫未設(shè)置";

??????if(value==null){

????????return?super.exportHandler(obj,name,emptyValue);

??????}

??????if(value?instanceof?String&&StrUtil.isBlank((String)?value)){

????????return?super.exportHandler(obj,name,emptyValue);

??????}

????}

????return?super.exportHandler(obj,?name,?value);

??}

??@Override

??publicObjectimportHandler(Member?obj,?String?name,?Object?value){

????return?super.importHandler(obj,?name,?value);

??}

}

然后修改Controller中的接口构资,調(diào)用MemberExcelDataHandler處理器的setNeedHandlerFields設(shè)置需要自定義處理的字段,并調(diào)用ExportParams的setDataHandler設(shè)置自定義處理器陨簇;

@Controller

@Api(tags?=?"EasyPoiController",?description?=?"EasyPoi導(dǎo)入導(dǎo)出測試")

@RequestMapping("/easyPoi")

public?classEasyPoiController{

????@ApiOperation(value?=?"導(dǎo)出會員列表Excel")

????@RequestMapping(value?=?"/exportMemberList",?method?=?RequestMethod.GET)

????publicvoidexportMemberList(ModelMap?map,

HttpServletRequest?request,

HttpServletResponse?response){

? ? ? ?List<Member>?memberList?=?LocalJsonUtil.getListFromJson("json/members.json",?Member.class);

? ExportParams?params?=?new?ExportParams("會員列表",?"會員列表",?ExcelType.XSSF);

? ?//對導(dǎo)出結(jié)果進(jìn)行自定義處理

? ?MemberExcelDataHandler?handler?=?new?MemberExcelDataHandler();

? ? handler.setNeedHandlerFields(new?String[]{"昵稱"});

? ? ?params.setDataHandler(handler);

? ? ?map.put(NormalExcelConstants.DATA_LIST,?memberList);

? ? ?map.put(NormalExcelConstants.CLASS,?Member.class);

? ? ?map.put(NormalExcelConstants.PARAMS,?params);

? ? ?map.put(NormalExcelConstants.FILE_NAME,?"memberList");

? ? ? PoiBaseView.render(map,?request,?response,?NormalExcelConstants.EASYPOI_EXCEL_VIEW);

????}

}

再次調(diào)用導(dǎo)出接口吐绵,我們可以發(fā)現(xiàn)昵稱已經(jīng)添加默認(rèn)設(shè)置了。

體驗了一波EasyPoi河绽,它使用注解來操作Excel的方式確實非常好用己单。如果你想生成更為復(fù)雜的Excel的話,可以考慮下它的模板功能耙饰。

參考資料:

項目官網(wǎng):https://gitee.com/lemur/easypoi

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纹笼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子苟跪,更是在濱河造成了極大的恐慌廷痘,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件件已,死亡現(xiàn)場離奇詭異笋额,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拨齐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門鳞陨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事厦滤≡遥” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵掏导,是天一觀的道長享怀。 經(jīng)常有香客問我,道長趟咆,這世上最難降的妖魔是什么添瓷? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮值纱,結(jié)果婚禮上鳞贷,老公的妹妹穿的比我還像新娘。我一直安慰自己虐唠,他們只是感情好搀愧,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疆偿,像睡著了一般咱筛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杆故,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天迅箩,我揣著相機(jī)與錄音,去河邊找鬼处铛。 笑死饲趋,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罢缸。 我是一名探鬼主播篙贸,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼枫疆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起敷鸦,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤息楔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扒披,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體值依,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年碟案,在試婚紗的時候發(fā)現(xiàn)自己被綠了愿险。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖辆亏,靈堂內(nèi)的尸體忽然破棺而出风秤,到底是詐尸還是另有隱情,我是刑警寧澤扮叨,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布缤弦,位于F島的核電站,受9級特大地震影響彻磁,放射性物質(zhì)發(fā)生泄漏碍沐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一衷蜓、第九天 我趴在偏房一處隱蔽的房頂上張望累提。 院中可真熱鬧,春花似錦磁浇、人聲如沸刻恭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鳍贾。三九已至,卻和暖如春交洗,著一層夾襖步出監(jiān)牢的瞬間骑科,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工构拳, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留咆爽,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓置森,卻偏偏與公主長得像斗埂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子凫海,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容