SpringBoot整合EasyExcel進(jìn)行報(bào)表導(dǎo)入導(dǎo)出

引入

為什么使用EasyExcel?

Java解析嗜历、生成Excel比較有名的框架有Apache poi、jxl奥邮。但他們都存在一個(gè)嚴(yán)重的問題就是非常的耗內(nèi)存腥光,poi有一套SAX模式的API可以一定程度的解決一些內(nèi)存溢出的問題,但POI還是有一些缺陷阳掐,比如07版Excel解壓縮以及解壓后存儲(chǔ)都是在內(nèi)存中完成的始衅,內(nèi)存消耗依然很大。

EasyExcel重寫了poi對(duì)07版Excel的解析缭保,一個(gè)3M的excel用POI sax解析依然需要100M左右內(nèi)存汛闸,改用EasyExcel可以降低到幾M,并且再大的excel也不會(huì)出現(xiàn)內(nèi)存溢出艺骂;03版依賴POI的sax模式诸老,在上層做了模型轉(zhuǎn)換的封裝,讓使用者更加簡(jiǎn)單方便钳恕。

官網(wǎng)GitHub地址:

https://github.com/alibaba/easyexcel

官方文檔地址:

https://www.yuque.com/easyexcel/doc/easyexcel

實(shí)例

創(chuàng)建初始數(shù)據(jù)

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NULL DEFAULT NULL,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `phone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `create_time` date NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 1, 'banq', '13588888888', '2021-11-19');

SET FOREIGN_KEY_CHECKS = 1;

創(chuàng)建SpringBoot項(xiàng)目

導(dǎo)入EasyExcel依賴

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.10</version>
</dependency>

User

@Data
public class User {
    @ExcelIgnore  //生成報(bào)表時(shí)忽略
    private Long id;

    @ExcelProperty(value = "用戶ID",index = 0)  // 定義表頭名稱和位置,0代表第一列
    private Long userId;

    @ExcelProperty(value = "用戶名稱",index = 1)
    private String username;

    @ExcelProperty(value = "電話號(hào)碼",index = 2)
    private String phone;

    @ExcelProperty(value = "創(chuàng)建日期",index = 3)
    @DateTimeFormat("yyyy年MM月dd日")
    private Date createTime;
}

監(jiān)聽器

@Slf4j
public class UserDataListener extends AnalysisEventListener<User> {

    private UserService userService;

    public UserDataListener(UserService userService) {
        this.userService = userService;
    }

    /**
     * 每隔5條存儲(chǔ)數(shù)據(jù)庫(kù)别伏,實(shí)際使用中可以3000條,然后清理list 忧额,方便內(nèi)存回收
     */
    private static final int BATCH_COUNT = 5;
    List<User> list = new ArrayList<User>();

    @Override
    public void invoke(User data, AnalysisContext context) {
        log.info("解析到一條數(shù)據(jù):{}", JSON.toJSONString(data));
        list.add(data);
        if (list.size() >= BATCH_COUNT) {
            saveData();
            list.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        log.info("所有數(shù)據(jù)解析完成厘肮!");
    }

    /**
     * 加上存儲(chǔ)數(shù)據(jù)庫(kù)
     */
    private void saveData() {
        log.info("{}條數(shù)據(jù),開始存儲(chǔ)數(shù)據(jù)庫(kù)睦番!", list.size());
        if (!CollectionUtils.isEmpty(list)) {
            userService.saveBatch(list);
        }
        log.info("存儲(chǔ)數(shù)據(jù)庫(kù)成功类茂!");
    }
}

Dao層

@Mapper
@Repository
public interface UserMapper {
    void batchInsert(List<User> list);
    List<User> queryAll();
}

<insert id="batchInsert">
    insert into user (user_id,username,phone,create_time) values
    <foreach collection="list" item="user" separator=",">
        (#{user.userId},#{user.username},#{user.phone},#{user.createTime})
    </foreach>
</insert>
<select id="queryAll" resultType="ink.banq.demo.entity.User">
    select id,user_id,username,phone,create_time from user
</select>

Service層

public interface UserService {
    void saveBatch(List<User> list);
    List<User> selectAll();
}

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public void saveBatch(List<User> list) {
        userMapper.batchInsert(list);
    }

    @Override
    public List<User> selectAll() {
        return userMapper.queryAll();
    }
}

Controller層

@RestController
public class OperateExcelController {
    @Autowired
    private UserService userService;

    /**
     * 上傳文件
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("upload")
    @ResponseBody
    public String upload(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), User.class, new UserDataListener(userService)).sheet().doRead();
        return "success";
    }

    /**
     * 導(dǎo)出文件
     * @param response
     * @throws IOException
     */
    @GetMapping("download")
    public void download(HttpServletResponse response) throws IOException {
        // 設(shè)置上下文類型
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        // 設(shè)置編碼
        response.setCharacterEncoding("utf-8");
        // 防止中文亂碼
        String fileName = URLEncoder.encode("文件名稱", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream()).sheet("模板").doWrite(userService.selectAll());
    }

}

測(cè)試

(1)測(cè)試導(dǎo)入功能,使用Postman測(cè)試托嚣,如下圖所示:

1.jpg

(2)測(cè)試導(dǎo)出功能巩检,瀏覽器訪問:http://localhost:8080/download

2.jpg

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市示启,隨后出現(xiàn)的幾起案子兢哭,更是在濱河造成了極大的恐慌,老刑警劉巖丑搔,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厦瓢,死亡現(xiàn)場(chǎng)離奇詭異提揍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)煮仇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門劳跃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浙垫,你說我怎么就攤上這事刨仑。” “怎么了夹姥?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵杉武,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我辙售,道長(zhǎng)轻抱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任旦部,我火速辦了婚禮祈搜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘士八。我一直安慰自己容燕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布婚度。 她就那樣靜靜地躺著蘸秘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝗茁。 梳的紋絲不亂的頭發(fā)上醋虏,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音评甜,去河邊找鬼灰粮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛忍坷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播熔脂,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼佩研,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了霞揉?” 一聲冷哼從身側(cè)響起旬薯,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎适秩,沒想到半個(gè)月后绊序,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硕舆,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年骤公,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抚官。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡阶捆,死狀恐怖凌节,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情洒试,我是刑警寧澤倍奢,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站垒棋,受9級(jí)特大地震影響卒煞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜叼架,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一跷坝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碉碉,春花似錦柴钻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蜡吧,卻和暖如春毫蚓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背昔善。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工元潘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人君仆。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓翩概,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親返咱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钥庇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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