当前位置:   article > 正文

SpringBoot导出Excel的四种方式

springboot导出excel

 方法一:hutools


       该方法通过自研的一套Excel注解,在实体类上添加注解,然后用一套工具类(见源码中com.leixi.excel.util.excelOne)实现实体类列表的导出。优点是不用建模板,调用简单,缺点是迁移麻烦。有好几个配套的文件如注解,工具类等,想要在别的项目中使用,就涉及到文件的拷贝。老实说,不太优雅,而且更可惜的是,这些方法里居然没有封装导出方法。下面给出实体类创建,方法调用的代码,供各位参考(相关源码会在文中提供)

//引入依赖

  1.         <dependency>
  2.             <groupId>cn.hutool</groupId>
  3.             <artifactId>hutool-all</artifactId>
  4.             <version>5.7.12</version>
  5.         </dependency>
  6.         <dependency>
  7.             <groupId>cn.afterturn</groupId>
  8.             <artifactId>easypoi-base</artifactId>
  9.             <version>4.3.0</version>
  10.         </dependency>


 

  1. //controller方法,不得不说,调用起来是真的方便
  2.     @PostMapping(value = "/exportData")
  3.     public ResponseEntity<byte[]> exportData(String fileName) {
  4.         List<ExcelOneDto> list = CommonUtil.buildDemoExcel(ExcelOneDto.class);
  5.         Workbook workbook = new DefaultWriteHandler<ExcelOneDto>().write("sheet名称",list, ExcelOneDto.class);
  6.         return CommonUtil.exportWorkbook(workbook, fileName);
  7.     }
  8.  
  9.  //实体类
  10. @Data
  11. public class ExcelOneDto {
  12.     @ExcelCell(priority = "A", cellTitle = "编号")
  13.     private Integer code;
  14.  
  15.     @ExcelCell(priority = "B", cellTitle = "名称")
  16.     private String name;
  17.  
  18.  
  19.     @ExcelCell(priority = "C", cellTitle = "详情")
  20.     private String desc;
  21.  
  22.     @ExcelCell(priority = "D", cellTitle = "备注")
  23.     private String remark;
  24. }


这是导出的测试结果:

 方法二:easyexcel

       现在使用频率较高的是用easyexcel实现的。经过一番了解,我将easyexcel的实现方式也列出来作为参考。该方法的优点是使用方便,功能强大!本文中我只实现了最简单的导入导出,easyexcel还支持很多如嵌套导入,合并行列等高级操作,相关实现可以参考大神的博客【精选】Spring Boot 集成 EasyExcel 3.x 优雅实现Excel导入导出_easyexcel3-CSDN博客。 以下是我学习了他的博客后,整理的最基本的代码:

  1. //引入maven依赖
  2.         <dependency>
  3.             <groupId>com.alibaba</groupId>
  4.             <artifactId>easyexcel</artifactId>
  5.             <version>3.1.3</version>
  6.         </dependency>
  7.  
  8. //controller:
  9.     @PostMapping(value = "/exportData")
  10.     public void exportData(String fileName, HttpServletResponse response) {
  11.         try {
  12.             this.setExcelResponseProp(response, fileName);
  13.             List<ExcelFourDto> list = CommonUtil.buildDemoExcel(ExcelFourDto.class);;
  14.             EasyExcel.write(response.getOutputStream())
  15.                     .head(ExcelFourDto.class)
  16.                     .excelType(ExcelTypeEnum.XLSX)
  17.                     .sheet(fileName)
  18.                     .doWrite(list);
  19.         } catch (IOException e) {
  20.             throw new RuntimeException(e);
  21.         }
  22.     }
  23.  
  24.     @PostMapping("/importData")
  25.     @SneakyThrows
  26.     public Object importUserExcel(@RequestPart("file") MultipartFile file) {
  27.             List<ExcelFourDto> list = EasyExcel.read(file.getInputStream())
  28.                     .head(ExcelFourDto.class).sheet().doReadSync();
  29.             return list;
  30.     }
  31.     
  32.     /**
  33.      * 设置响应结果
  34.      *
  35.      * @param response    响应结果对象
  36.      * @param rawFileName 文件名
  37.      * @throws UnsupportedEncodingException 不支持编码异常
  38.      */
  39.     private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {
  40.         response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
  41.         response.setCharacterEncoding("utf-8");
  42.         String fileName = URLEncoder.encode(rawFileName, "UTF-8").replaceAll("\\+", "%20");
  43.         response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
  44.     } 
  45.  
  46. // 实体类
  47. @Data
  48. public class ExcelFourDto {
  49.     @ExcelProperty("编号")
  50.     @ColumnWidth(20)
  51.     private Integer code;
  52.  
  53.     @ExcelProperty("名称")
  54.     @ColumnWidth(20)
  55.     private String name;
  56.  
  57.     @ExcelProperty("详情")
  58.     @ColumnWidth(20)
  59.     private String desc;
  60.  
  61.     @ExcelProperty("备注")
  62.     @ColumnWidth(20)
  63.     private String remark;
  64. }

      以下是测试结果:

方法三:ExcelImportUtil工具类

该方法的优点:不用excel模板,导出导出方便。缺点是封装的不够好。研发人员使用时需要对ExcelImportUtil进行一定的加工。下面是我封装后的代码:

//maven依赖
       

  1. <dependency>
  2.             <groupId>cn.afterturn</groupId>
  3.             <artifactId>easypoi-base</artifactId>
  4.             <version>4.3.0</version>
  5.         </dependency>
  1. //control类的导入导出
  2.  
  3.     @PostMapping(value = "/importData")
  4.     public Object importManageData(@RequestPart("file") MultipartFile file) throws Exception {
  5.         return CommonUtil.getExcelDataFromFile(file, ExcelTwoDto.class, 1,2);
  6.     }
  7.  
  8.     @PostMapping(value = "/exportData")
  9.     public ResponseEntity<byte[]> exportData(@RequestParam("fileName") String fileName){
  10.         List<ExcelTwoDto> list  = CommonUtil.buildDemoExcel(ExcelTwoDto.class);
  11.         List<Map<String, Object>> exportView = CommonUtil.buildExportView("测试Title", "测试Sheet",list);
  12.         Workbook workbook = ExcelExportUtil.exportExcel(exportView, ExcelType.XSSF);
  13.         ExcelStyleUtil.addNotExistCell(workbook, 0, 3);
  14.         return CommonUtil.exportWorkbook(workbook, fileName);
  15.     }
  16.     
  17. //实体类 
  18. @Data
  19. @Builder
  20. @NoArgsConstructor
  21. @AllArgsConstructor
  22. public class ExcelTwoDto {
  23.  
  24.     @Excel(name = "第一列" ,fixedIndex = 0, orderNum = "0")
  25.     private String codeOne;
  26.     @Excel(name = "第二列" ,fixedIndex = 1, orderNum = "1", width = 50)
  27.     private String codeTwo;
  28.     @ExcelCollection(name = "第三列" , orderNum = "2")
  29.     private List<ExcelChildDto> codeThree;
  30.  
  31.     @Excel(name = "第四列" ,fixedIndex = 4, orderNum = "4", width = 50)
  32.     private String codeFour;
  33.     @Excel(name = "第五列" ,fixedIndex = 5, orderNum = "5")
  34.     private String codeFive;
  35.     @Excel(name = "第六列A", groupName = "第六列汇总" ,fixedIndex = 6, orderNum = "6")
  36.     private String codeThreeOne;
  37.     @Excel(name = "第六列B", groupName = "第六列汇总" ,fixedIndex = 7, orderNum = "7")
  38.     private String codeThreeTwo;
  39.     @Excel(name = "第六列C", groupName = "第六列汇总" ,fixedIndex = 8, orderNum = "8")
  40.     private String codeThreeThree;
  41. }
  42.  
  43. @Data
  44. @Builder
  45. @NoArgsConstructor
  46. @AllArgsConstructor
  47. public class ExcelChildDto {
  48.     @Excel(name = "编码" ,fixedIndex = 0, orderNum = "0")
  49.     private String code;
  50.     @Excel(name = "名称" ,fixedIndex = 1, orderNum = "1", width = 50)
  51.     private String name;
  52. }

   导出测试结果:


       

方法四:Excel模板导出

第三种方案是通过excel模板来实现的方法,现在基本已经废弃了,之所以放在这里是为了做一个参照,让大家看看不同的实现方法的区别。这种方式通过创建一个Excel模板和对应模板的实体类来实现文件导出,优点是实体类里不需要加注解了,而且在excel里可以设计一些style和格式,缺点是配置excelTemplate太麻烦了。配置繁琐,且过程中如出现参数名错误,符号错误等 ,调试起来很不方便,如果要增减字段,实体类和excel都得调整。下面给出编写的代码:

  1. // controller方法
  2.     @PostMapping(value = "/exportData")
  3.     public ResponseEntity<byte[]> exportData(@RequestParam("fileName") String fileName) {
  4.         TemplateExportParams params = new TemplateExportParams("templates/template.xlsx");
  5.         params.setScanAllsheet(true);
  6.         Map<String, Object> dataMap = new HashMap<>();
  7.         List<ExcelThreeDto> list  = CommonUtil.buildDemoExcel(ExcelThreeDto.class);
  8.         dataMap.put("titleName", "标题名称");
  9.         dataMap.put("desc", "备注名称");
  10.         dataMap.put("dataList", list);
  11.         Workbook workbook = ExcelExportUtil.exportExcel(params, dataMap);
  12.         ExcelStyleUtil.setAutoHeight(workbook, 0, 4);
  13.         return CommonUtil.exportWorkbook(workbook, fileName);
  14.     }
  15.     
  16. //实体类
  17.     @Data
  18.     @Builder
  19.     @NoArgsConstructor
  20.     @AllArgsConstructor
  21.     public class ExcelThreeDto {
  22.         private Integer code;
  23.         private String name;
  24.         private String desc;
  25.         private String remark;
  26.     }

        Excel模板的配置

        导出的结果:

        由于年代久远,我没能找到对应的模板导入的方法,于是在网上搜索了相关资料,编写了一个较通用的文件导入方法:

  1. //maven依赖
  2.         <dependency>
  3.             <groupId>cn.afterturn</groupId>
  4.             <artifactId>easypoi-base</artifactId>
  5.             <version>4.3.0</version>
  6.         </dependency>
  7.  
  8.     /**
  9.      * excel 导入
  10.      */
  11.     @PostMapping("/importData")
  12.     public Object upload(@RequestParam(name = "file") MultipartFile file) {
  13.         return CommonUtil.importExcel(file, 3, ExcelThreeDto.class);
  14.     }
  15.  
  16.     /**
  17.      * 通用的excel导入的方法
  18.      *
  19.      * @param file 导入文件
  20.      * @param startRow 第几行开始读数据
  21.      * @param clazz 导入后转成的实体类
  22.      * @return
  23.      * @param <T> 
  24.      */
  25.     @SneakyThrows
  26.     public static <T> List<T> importExcel(MultipartFile file, Integer startRow, Class<T> clazz) {
  27.         Workbook wb = new XSSFWorkbook(file.getInputStream());
  28.         //1.2.获取Sheet
  29.         Sheet sheet = wb.getSheetAt(0);
  30.         List<T> list = new ArrayList<>();
  31.         Field[] fields = clazz.getDeclaredFields();
  32.         for (int rowNum = startRow; rowNum <= sheet.getLastRowNum(); rowNum++) {
  33.             //根据索引获取每一个行
  34.             Row row = sheet.getRow(rowNum);
  35.             T obj = clazz.newInstance();
  36.             for (int cellNum = 0; cellNum < row.getLastCellNum() && cellNum< fields.length; cellNum++) {
  37.                 Cell cell = row.getCell(cellNum);
  38.                 Object value = CommonUtil.getCellValue(cell);
  39.                 Field field = fields[cellNum];
  40.                 field.setAccessible(true);
  41.                 // 注意,这里是为了演示,只分析了Integer和String的写法,实际上要根据Field数据的枚举分类处理
  42.                 if (field.getType().equals(Integer.class) && value != null) {
  43.                     field.set(obj, new Double(value.toString()).intValue());
  44.                 } else {
  45.                     field.set(obj, value);
  46.                 }
  47.             }
  48.             list.add(obj);
  49.         }
  50.         return list;
  51.     }

        导入的结果还是蛮令人满意的:

        原以为方法一已经是别开生面了,但是对比起来,仍然是有些差强人意。时代真是进步的飞快,对于程序员来说,这种变迁显得尤为明显。它就像一根鞭子,不断的抽打着码农们,稍有懈怠就会被这洪流所淹没…

        (文中附上四种方式的源码,仅用于学习和参考!)

本人力荐前两种方法,有大量的项目使用,相关的博客也比较多,尤其是easyexcel,官方对每种导入导出的方式都有完整的案例参考,简单上手!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/913647
推荐阅读
相关标签
  

闽ICP备14008679号