初次邂逅 EasyExcel

[复制链接]
发表于 2022-11-30 01:37:12 | 显示全部楼层 |阅读模式
前言

由于工作原因,有这种需求,就是把数据库中的数据导出成 Excel 表格,同时,也得支持人家用 Excel 表格导入数据到数据库。当前项目也是在用 EasyExcel,所以我不得不学啦!
以前学习的过程中,有听过 EasyExcel 这么一个东西,不过从来没用过,所以,正好借此机会学习,看看如何使用它来实现需求。
在学习 EasyExcel 的这段时间里,也了解到工作中这种导入导出的需求还是挺常见的,所以决定记录下来。
官方文档https://easyexcel.opensource.alibaba.com/docs/current/
需求

用户点击导入按钮,就能够上传 Excel 文件,将 Excel 文件的数据导入到系统中。
用户勾选目标数据 id,点击导出按钮,就能将系统中的数据以 Excel 文件的格式下载到本地。
分析

导入,从用户的视角来看,就是导入 Excel 文件;从开发者的视角,或者说系统的视角来看,就是读取用户的 Excel 文件的数据到系统中(实际上是读取到计算机的内存中),最后将读取到的数据存储数据库,EasyExcel 在导入的过程中进行了读操作
导出,同理,用户的视角就是导出,开发者的视角就是把系统的数据写入到用户的计算机上,即写操作
简而言之,涉及 IO 操作的,视角不同,说法不同(初学IO时就没搞清楚,为我后续的学习留下了大坑T_T!)。
当然我们也可以把导入说成写操作,毕竟数据是最终是存储在系统的数据库中的,即写到了系统的数据库里了。自己别搞混了就行。
准备

本 Demo 使用 Spring Boot 构建,配合 MyBaits Plus,以游戏数据导入和导出作为需求;一些工具依赖如下:
  1. <dependency>
  2.     <groupId>cn.hutool</groupId>
  3.     <artifactId>hutool-all</artifactId>
  4.     <version>5.7.10</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>com.alibaba</groupId>
  8.     <artifactId>fastjson</artifactId>
  9.     <version>1.2.72</version>
  10. </dependency>
  11. <dependency>
  12.     <groupId>org.apache.commons</groupId>
  13.     <artifactId>commons-lang3</artifactId>
  14.     <version>3.1</version>
  15. </dependency>
  16. <dependency>
  17.     <groupId>org.springframework.boot</groupId>
  18.     <artifactId>spring-boot-devtools</artifactId>
  19.     <scope>runtime</scope>
  20.     <optional>true</optional>
  21. </dependency>
  22. <dependency>
  23.     <groupId>org.projectlombok</groupId>
  24.     <artifactId>lombok</artifactId>
  25.     <optional>true</optional>
  26. </dependency>
复制代码
依赖

今天 EasyExcel 主菜,需要加其依赖才能食用~
  1. <dependency>
  2.     <groupId>com.alibaba</groupId>
  3.     <artifactId>easyexcel</artifactId>
  4.     <version>2.2.7</version>
  5. </dependency>
复制代码
配置
  1. server:
  2.   port: 4790
  3. spring:
  4.   application:
  5.     name: easyexcel-demo
  6.   datasource:
  7.     driver-class-name: com.mysql.jdbc.Driver
  8.     url: jdbc:mysql://localhost:3306/easy_excel_demo?useUnicode=true&autoReconnect=true&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&characterEncoding=utf8
  9.     username: root
  10.     password: 123456
复制代码
游戏实体类

咱们的游戏类就这些属性:id、游戏名称、价格、uuid,发售日期、创建时间、修改时间
  1. /**
  2. * @author god23bin
  3. * @version 1.0
  4. * @description 游戏
  5. * @date 2022/10/21 16:51:02
  6. */
  7. @Data
  8. @TableName("t_game")
  9. public class Game {
  10.     @TableId(type = IdType.AUTO)
  11.     private Long id;
  12.     private String name;
  13.     private Double price;
  14.     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  15.     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8")
  16.     private Date releaseDate;
  17.     @TableField(fill = FieldFill.INSERT)
  18.     private String uuid;
  19.     @TableField(fill = FieldFill.INSERT)
  20.     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  21.     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8")
  22.     private Date gmtCreate;
  23.     @TableField(fill = FieldFill.INSERT_UPDATE)
  24.     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  25.     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8")
  26.     private Date gmtModified;
  27. }
复制代码
模型

啥是模型?别慌,先假设需要导入的 Excel 表格长这样:

那么这个就是所谓的模型啦,不管是还是,都需要相对应的对象,所以一般会编写一个读对象的类和写对象的类,当然,如果读写的表头字段都是一模一样,直接一个类就可以了,导入导出都用这个类。
读对象

读对象-GameImportExcelModel:
  1. /**
  2. * @author god23bin
  3. * @version 1.0
  4. * @description Game 导入的 Excel 数据模型(读对象)
  5. * @date 2022/10/21 17:18:50
  6. */
  7. @Data
  8. public class GameImportExcelModel {
  9.     private String name;
  10.     private Double price;
  11.     private Date releaseDate;
  12. }
复制代码
写对象

写对象-GameExportExcelModel:
  1. /**
  2. * @author god23bin
  3. * @version 1.0
  4. * @description Game 导出的 Excel 数据模型(写对象)
  5. * @date 2022/10/21 17:18:50
  6. */
  7. @Data
  8. public class GameExportExcelModel {
  9.     @ExcelProperty("游戏ID")
  10.     private Long id;
  11.     @ExcelProperty("游戏名")
  12.     private String name;
  13.     @ExcelProperty("价格")
  14.     private Double price;
  15.     @ExcelProperty("发售日期")
  16.     private Date releaseDate;
  17. }
复制代码
实现

导入功能

用户点击导入按钮,就能够上传 Excel 文件,将 Excel 文件的数据导入到系统中。
前端实现一个上传文件的按钮,后端就接收这个文件,读取这个文件的数据,存储到数据库中。
开胃菜-后端

搭个整体的代码框架先!
持久层

GameMapper:
  1. @Mapper
  2. public interface GameMapper extends BaseMapper<Game> {
  3. }
复制代码
业务层

GameService:
  1. /**
  2. * @author god23bin
  3. * @version 1.0
  4. * @description
  5. * @date 2022/11/8 14:36:43
  6. */
  7. public interface GameService {
  8.     /**
  9.      * 导入Excel数据到数据库
  10.      * @date 2022/11/8 14:38
  11.      * @param file Excel文件
  12.      * @return boolean
  13.      **/
  14.     boolean importExcel(MultipartFile file);
  15.    
  16. }
复制代码
GameServiceImpl:
  1. /**
  2. * @author god23bin
  3. * @version 1.0
  4. * @description
  5. * @date 2022/11/8 14:40:08
  6. */
  7. @Slf4j
  8. @Service
  9. public class GameServiceImpl extends ServiceImpl<GameMapper, Game> implements GameService {
  10.     @Resource
  11.     private GameMapper gameMapper;
  12.     /**
  13.      * 导入Excel数据到数据库
  14.      *
  15.      * @param file Excel文件
  16.      * @return boolean
  17.      * @date 2022/11/8 14:38
  18.      **/
  19.     @Override
  20.     public boolean importExcel(MultipartFile file) {
  21.         // 这里就需要用到「读监听器」了,需要我们自己实现
  22.         return null;
  23.     }
  24. }
复制代码
控制层

GameController:
  1. /**
  2. * @author god23bin
  3. * @version 1.0
  4. * @description
  5. * @date 2022/11/8 14:31:50
  6. */
  7. @RestController
  8. public class GameController {
  9.     @Resource
  10.     private GameService gameService;
  11.     @PostMapping("/excel/import/game")
  12.     public ResponseEntity<String> importExcel(@RequestPart("file") MultipartFile file) {
  13.         gameService.importExcel(file);
  14.         return new ResponseEntity<>("OK", HttpStatus.OK);
  15.     }
  16. }
复制代码
正餐-读数据需要用到的监听器

对于读取,有一个监听器需要我们实现,根据文档的说明,这个监听器是不可以让 Spring 来管理的。
有个很重要的点  DemoDataListener 不能被 spring管理,要每次读取 excel都要 new,然后里面用到 spring 可以构造方法传进去
所以我们也不需要加上 @Component 注解把这个类作为组件让 Spring 扫描。直接一个普通的类就行
具体代码如下,需要知道的是:

  • 需要继承 AnalysisEventListener 类,参数化的类型(泛型)为 GameImportExcelModel(读对象)
GameImportExcelListener:
  1. /**
  2. * @author god23bin
  3. * @version 1.0
  4. * @description
  5. * @date 2022/10/24 08:45:15
  6. */
  7. @Slf4j
  8. public class GameImportExcelListener extends AnalysisEventListener<GameImportExcelModel> {
  9.     /**
  10.      * 每隔100条存储到数据库,然后清理list ,方便内存回收
  11.      */
  12.     private static final int BATCH_COUNT = 100;
  13.     /**
  14.      * 缓存的数据
  15.      */
  16.     private List<Game> cachedDataList = new ArrayList<>(BATCH_COUNT);
  17.     /**
  18.      * 每解析一行数据就会执行这个方法
  19.      *
  20.      * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
  21.      * @param context
  22.      */
  23.     @Override
  24.     public void invoke(GameImportExcelModel data, AnalysisContext context) {
  25.         log.info("解析到一条数据:{}", JSON.toJSONString(data));
  26.         Game game = new Game();
  27.         BeanUtil.copyProperties(data, game);
  28.         cachedDataList.add(game);
  29.         if (cachedDataList.size() >= BATCH_COUNT) {
  30.             saveData();
  31.             // 存储完成清理 list
  32.             cachedDataList.clear();
  33.         }
  34.     }
  35.     private void saveData() {
  36.         // 这里写存储到数据库的逻辑代码
  37.     }
  38.     /**
  39.      * 解析完之后会执行这个方法,如果有其他事情需要做,可以在这里加上代码来完成
  40.      *
  41.      * @param context
  42.      */
  43.     @Override
  44.     public void doAfterAllAnalysed(AnalysisContext context) {
  45.         // 这里也要保存数据,确保最后遗留的数据也存储到数据库
  46.         saveData();
  47.         log.info("所有数据解析完成!");
  48.     }
  49. }
复制代码
但是!如果我们想要使用 Spring IOC 管理对象,比如 Dao、Mapper 这些对象,现在当前类是用不了 @Autowired 注解将这些对象注入的,那我们怎么获取它们?
方法就是:在该类中写一个构造方法,将这些被 Spring 管理的对象作为参数传入进来!
比如我这里需要用到 GameMapper 对象,那么就将它作构造方法的参数传进来。
  1. @Slf4j
  2. public class GameImportExcelListener extends AnalysisEventListener<GameImportExcelModel> {
  3.     // 省略其他代码
  4.    
  5.     private GameMapper gameMapper;
  6.    
  7.     public GameImportExcelListener(GameMapper gameMapper) {
  8.         this.gameMapper = gameMapper;
  9.     }
  10.     @Override
  11.     public void invoke(GameImportExcelModel data, AnalysisContext context) {
  12.         // ...
  13.     }
  14.     private void saveData() {
  15.         // ...
  16.     }
  17.     @Override
  18.     public void doAfterAllAnalysed(AnalysisContext context) {
  19.         // ...
  20.     }
  21. }
复制代码
完整的监听器代码

GameImportExcelListener:
  1. package cn.god23bin.demo.excel.listener;
  2. import cn.god23bin.demo.entity.Game;
  3. import cn.god23bin.demo.excel.bean.GameImportExcelModel;
  4. import cn.god23bin.demo.mapper.GameMapper;
  5. import cn.hutool.core.bean.BeanUtil;
  6. import com.alibaba.excel.context.AnalysisContext;
  7. import com.alibaba.excel.event.AnalysisEventListener;
  8. import com.alibaba.fastjson.JSON;
  9. import lombok.extern.slf4j.Slf4j;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. /**
  13. * @author zwb
  14. * @version 1.0
  15. * @description
  16. * @date 2022/10/24 08:45:15
  17. */
  18. @Slf4j
  19. public class GameImportExcelListener extends AnalysisEventListener<GameImportExcelModel> {
  20.     /**
  21.      * 每隔100条存储到数据库,然后清理list ,方便内存回收
  22.      */
  23.     private static final int BATCH_COUNT = 100;
  24.     /**
  25.      * 缓存的数据
  26.      */
  27.     private List<Game> cachedDataList = new ArrayList<>(BATCH_COUNT);
  28.     private GameMapper gameMapper;
  29.     public GameImportExcelListener(GameMapper gameMapper) {
  30.         this.gameMapper = gameMapper;
  31.     }
  32.     /**
  33.      * 每解析一行数据就会执行这个方法
  34.      *
  35.      * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
  36.      * @param context
  37.      */
  38.     @Override
  39.     public void invoke(GameImportExcelModel data, AnalysisContext context) {
  40.         log.info("解析到一条数据:{}", JSON.toJSONString(data));
  41.         Game game = new Game();
  42.         BeanUtil.copyProperties(data, game);
  43.         cachedDataList.add(game);
  44.         if (cachedDataList.size() >= BATCH_COUNT) {
  45.             saveData();
  46.             // 存储完成清理 list
  47.             cachedDataList.clear();
  48.         }
  49.     }
  50.     private void saveData() {
  51.         // 这里写存储到数据库的逻辑代码
  52.         for (Game game : cachedDataList) {
  53.             gameMapper.insert(game);
  54.         }
  55.     }
  56.     /**
  57.      * 解析完之后会执行这个方法,如果有其他事情需要做,可以在这里加上代码来完成
  58.      *
  59.      * @param context
  60.      */
  61.     @Override
  62.     public void doAfterAllAnalysed(AnalysisContext context) {
  63.         // 这里也要保存数据,确保最后遗留的数据也存储到数据库
  64.         saveData();
  65.         log.info("所有数据解析完成!");
  66.     }
  67. }
复制代码
完善业务层


  • 使用 EasyExcel.read() 方法构建一个 Excel reader builder,第一个参数是文件输入流,第二个参数是读对象,指定它这个class去读,第三个参数就是读监听器
  • 接着链式调用 sheet() 方法和 doRead() 方法,完成整个 Excel 的读取操作。
  1. @Slf4j
  2. @Service
  3. public class GameServiceImpl extends ServiceImpl<GameMapper, Game> implements GameService {
  4.     @Resource
  5.     private GameMapper gameMapper;
  6.     /**
  7.      * 导入Excel数据到数据库
  8.      *
  9.      * @param file Excel文件
  10.      * @return boolean
  11.      * @date 2022/11/8 14:38
  12.      **/
  13.     @Override
  14.     public boolean importExcel(MultipartFile file) {
  15.         try {
  16.             // 使用 EasyExcel.read() 方法构建一个 Excel reader builder,第一个参数是文件输入流,第二个参数是读对象,指定它这个class去读,第三个参数就是读监听器
  17.             EasyExcel.read(file.getInputStream(), GameImportExcelModel.class, new GameImportExcelListener(gameMapper))
  18.                     .sheet()
  19.                     .doRead();
  20.         } catch (IOException e) {
  21.             log.error("Error importing: {}", e.getMessage());
  22.             return false;
  23.         }
  24.         return true;
  25.     }
  26. }
复制代码
测试

使用 Postman 测试,请求后端的导入 Excel 的接口,在 Postman 中选好 Post 请求并且输入请求路径。
点击 Headers 设置请求头:

  • Key 中输入 Content-Type,属性的值输入 multipart/form-data
点击 Body 设置请求体:

  • 选择 form-data 格式,Key 中输入 file,便可以选择文件进行上传了

测试结果:

可以看到Excel中的数据成功存储到数据库中了,这就完成了导入的功能
导出功能

用户勾选目标数据 id,点击导出按钮,就能将系统中的数据以 Excel 文件的格式下载到本地。
细节:需要导出的文件名称为这种格式:游戏列表-2022-11-11-12-30-00.xlsx
在这个导出文件的场景下,就需要后端返回前端文件数据,后端有两种方式可以返回,让前端进行下载。

  • 后端返回文件所在的 URL,前端直接根据 URL 进行下载。
  • 后端以二进制流的形式返回文件流,前端再接受这个流下载到本地。
由于我们的数据是在数据库中的,并不是直接存储 Excel 文件的,所以我们以二进制流的形式返回文件流给前端,让前端下载。
看看 EasyExcel 的 write 方法签名,里面有好多个重载的 write 方法,我们看看这个就行:
public static ExcelWriterBuilder write(OutputStream outputStream, Class head)
参数说明:

  • 第一个参数是文件输出流
  • 第二个参数是指定我们要参照哪个模型类去写这个 Excel,head 意思就是该类的属性将作为 Excel 的表头。
代码

主要逻辑
  1. // 假设这里是从数据库获取的集合
  2. List<Game> data = ...;
  3. // 文件格式
  4. String fileName = new String("");
  5. String format = "yyyy-MM-dd-HH-mm-ss";
  6. fileName = fileName + DateUtil.format(new Date(), format);
  7. // 将数据写到输出流返回给前端
  8. EasyExcel.write(ExcelUtil.getResponseOutputStream(fileName, response), GameExportExcelModel.class)
  9.     .sheet("工作簿")
  10.     .doWrite(dataList);
复制代码
Excel 工具类
  1. /**
  2. * @author god23bin
  3. * @version 1.0
  4. * @description Excel 工具类
  5. * @date 2022/11/18 17:55:48
  6. */
  7. public class ExcelUtil {
  8.     /**
  9.      * 获取响应输出流
  10.      * @date 2022/11/18 18:10
  11.      * @param fileName 文件名
  12.      * @param response 响应
  13.      * @return java.io.OutputStream
  14.      **/
  15.     public static OutputStream getResponseOutputStream(String fileName, HttpServletResponse response) {
  16.         try {
  17.             // 给文件名编码,则前端接收后进行解码
  18.             fileName = URLEncoder.encode(fileName, "UTF-8");
  19.             // 指定客户端接收的响应内容类型为Excel以及字符编码为UTF-8
  20.             response.setContentType("application/vnd.ms-excel");
  21.             response.setCharacterEncoding("utf8");
  22.             // 让浏览器提供打开、保存的对话框,以附件的形式下载,同时设置文件名格式
  23.             response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
  24.             // 禁止缓存
  25.             response.setHeader("Cache-Control", "no-store");
  26.             response.addHeader("Cache-Control", "max-age=0");
  27.             return response.getOutputStream();
  28.         } catch (IOException e) {
  29.             e.printStackTrace();
  30.         }
  31.         return null;
  32.     }
  33. }
复制代码
控制层

用 Set 集合去重,防止多次查询同一数据。
  1.     @PostMapping("/excel/export/game")
  2.     public ResponseEntity<String> exportExcel(@RequestBody Set<String> uuidList, HttpServletResponse response) {
  3.         gameService.exportExcel(new ArrayList<>(uuidList), response);
  4.         return new ResponseEntity<>("OK", HttpStatus.OK);
  5.     }
复制代码
业务层

主要逻辑是去数据库查询出需要导出的数据,然后转成对应的导出模型对象,最后使用 EasyExcel 的 write() 方法将数据写到输出流。
  1.     /**
  2.      * 导出数据库记录到Excel
  3.      *
  4.      * @param uuidList uuid集合
  5.      * @param response 响应
  6.      * @return boolean
  7.      * @date 2022/11/11 14:23
  8.      **/
  9.     @Override
  10.     public boolean exportExcel(List<String> uuidList, HttpServletResponse response) {
  11.         // 根据uuid找到需要导出的记录集合
  12.         LambdaQueryWrapper<Game> achievementWrapper = new LambdaQueryWrapper<>();
  13.         achievementWrapper.in(Game::getUuid, uuidList);
  14.         achievementWrapper.orderByDesc(Game::getGmtCreate);
  15.         List<Game> games = this.baseMapper.selectList(achievementWrapper);
  16.         // 将查询到的数据转换成对应Excel的导出模型对象
  17.         List<GameExportExcelModel> dataList = games.stream().map(game -> {
  18.             GameExportExcelModel gameExportExcelModel = new GameExportExcelModel();
  19.             BeanUtil.copyProperties(game, gameExportExcelModel);
  20.             return gameExportExcelModel;
  21.         }).collect(Collectors.toList());
  22.         // 文件格式
  23.         String fileName = new String("");
  24.         String format = "yyyy-MM-dd-HH-mm-ss";
  25.         fileName = fileName + DateUtil.format(new Date(), format);
  26.         // 将数据写到输出流返回给前端
  27.         EasyExcel.write(ExcelUtil.getResponseOutputStream(fileName, response), GameExportExcelModel.class)
  28.                 .sheet("工作簿")
  29.                 .doWrite(dataList);
  30.         return true;
  31.     }
复制代码
测试

以请求体的方式传递一个需要导出的游戏的 uuid 数组

点击 Send 按钮旁边的三角符号,点击 Send and Download,这样就可以下载了,最后下载的 Excel 打开后如下:

额,翻车,格式有点点问题,问题不大,这时候就需要一个自定义的拦截器帮我们处理单元格。
自定义拦截器

拿来主义,写法基本是这样:
EasyExcel导出自动适应列宽 Excel样式
  1. public class CustomCellWriteHandler extends AbstractColumnWidthStyleStrategy {
  2.     private static final int MAX_COLUMN_WIDTH = 255;
  3.     private Map<Integer, Map<Integer, Integer>> cache = new HashMap<>(16);
  4.     public CustomCellWriteHandler() {
  5.     }
  6.     /**
  7.      * Sets the column width when head create
  8.      *
  9.      * @param writeSheetHolder
  10.      * @param cellDataList
  11.      * @param cell
  12.      * @param head
  13.      * @param relativeRowIndex
  14.      * @param isHead
  15.      */
  16.     @Override
  17.     protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
  18.         boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);
  19.         if (needSetWidth) {
  20.             Map<Integer, Integer> maxColumnWidthMap = cache.get(writeSheetHolder.getSheetNo());
  21.             if (maxColumnWidthMap == null) {
  22.                 maxColumnWidthMap = new HashMap<>(16);
  23.                 cache.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);
  24.             }
  25.             Integer columnWidth = this.dataLength(cellDataList, cell, isHead);
  26.             if (columnWidth >= 0) {
  27.                 if (columnWidth > 255) {
  28.                     columnWidth = 255;
  29.                 }
  30.                 Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());
  31.                 if (maxColumnWidth == null || columnWidth > maxColumnWidth) {
  32.                     maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);
  33.                     writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 7250);
  34.                 }
  35.             }
  36.         }
  37.     }
  38.     private Integer dataLength(List<CellData> cellDataList, Cell cell, Boolean isHead) {
  39.         if (isHead) {
  40.             return cell.getStringCellValue().getBytes().length;
  41.         } else {
  42.             CellData cellData = (CellData) cellDataList.get(0);
  43.             CellDataTypeEnum type = cellData.getType();
  44.             if (type == null) {
  45.                 return -1;
  46.             } else {
  47.                 switch (type) {
  48.                     case STRING:
  49.                         return cellData.getStringValue().getBytes().length;
  50.                     case BOOLEAN:
  51.                         return cellData.getBooleanValue().toString().getBytes().length;
  52.                     case NUMBER:
  53.                         return cellData.getNumberValue().toString().getBytes().length;
  54.                     default:
  55.                         return -1;
  56.                 }
  57.             }
  58.         }
  59.     }
  60. }
复制代码
但是为什么这样写,好吧,目前不了解T_T,有待研究。
接着注册这个拦截器,让它知道该如何处理,修改业务层的代码:
  1. EasyExcel.write(ExcelUtil.getResponseOutputStream(fileName, response), GameExportExcelModel.class)
  2.                 .sheet("工作簿")
  3.                 .registerWriteHandler(new CustomCellWriteHandler())
  4.                 .doWrite(dataList);
复制代码
最后导出效果:

总结

某张 Excel 表需要你导入到系统中,这里系统指的就是你所做的项目,更准确来说将 Excel 的数据插入到你系统中的数据库里。那么就可以使用 EasyExcel。
常见的需求就是对 Excel 数据的导入导出,我们需要做的就是根据 Excel 表进行建模,创建对应的读对象和写对象。
对于导入,就需要读对象配合读监听器来实现。
对于导出,就直接通过 write 方法,以二进制流的方式将数据写到响应体中。
最后的最后

由本人水平所限,难免有错误以及不足之处, 屏幕前的靓仔靓女们 如有发现,恳请指出!
最后,谢谢你看到这里,谢谢你认真对待我的努力,希望这篇博客对你有所帮助!
你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表