SpringBoot导出Excel的四种方式

本文详细介绍了四种Java中利用Hutools、EasyExcel、ExcelImportUtil和模板进行Excel数据导入导出的方法,包括各自的优缺点和示例代码,推荐EasyExcel因其易用性和功能丰富性。

 方法一:hutools


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

//引入依赖

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.12</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.3.0</version>
        </dependency>


 

//controller方法,不得不说,调用起来是真的方便
    @PostMapping(value = "/exportData")
    public ResponseEntity<byte[]> exportData(String fileName) {
        List<ExcelOneDto> list = CommonUtil.buildDemoExcel(ExcelOneDto.class);
        Workbook workbook = new DefaultWriteHandler<ExcelOneDto>().write("sheet名称",list, ExcelOneDto.class);
        return CommonUtil.exportWorkbook(workbook, fileName);
    }
 
 //实体类
@Data
public class ExcelOneDto {
    @ExcelCell(priority = "A", cellTitle = "编号")
    private Integer code;
 
    @ExcelCell(priority = "B", cellTitle = "名称")
    private String name;
 
 
    @ExcelCell(priority = "C", cellTitle = "详情")
    private String desc;
 
    @ExcelCell(priority = "D", cellTitle = "备注")
    private String remark;
}


这是导出的测试结果:

 方法二:easyexcel

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

//引入maven依赖
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.3</version>
        </dependency>
 
//controller:
    @PostMapping(value = "/exportData")
    public void exportData(String fileName, HttpServletResponse response) {
        try {
            this.setExcelResponseProp(response, fileName);
            List<ExcelFourDto> list = CommonUtil.buildDemoExcel(ExcelFourDto.class);;
            EasyExcel.write(response.getOutputStream())
                    .head(ExcelFourDto.class)
                    .excelType(ExcelTypeEnum.XLSX)
                    .sheet(fileName)
                    .doWrite(list);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
 
    @PostMapping("/importData")
    @SneakyThrows
    public Object importUserExcel(@RequestPart("file") MultipartFile file) {
            List<ExcelFourDto> list = EasyExcel.read(file.getInputStream())
                    .head(ExcelFourDto.class).sheet().doReadSync();
            return list;
    }
    
    /**
     * 设置响应结果
     *
     * @param response    响应结果对象
     * @param rawFileName 文件名
     * @throws UnsupportedEncodingException 不支持编码异常
     */
    private void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode(rawFileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    } 
 
// 实体类
@Data
public class ExcelFourDto {
    @ExcelProperty("编号")
    @ColumnWidth(20)
    private Integer code;
 
    @ExcelProperty("名称")
    @ColumnWidth(20)
    private String name;
 
    @ExcelProperty("详情")
    @ColumnWidth(20)
    private String desc;
 
    @ExcelProperty("备注")
    @ColumnWidth(20)
    private String remark;
}

      以下是测试结果:

方法三:ExcelImportUtil工具类

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

//maven依赖
       

<dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.3.0</version>
        </dependency>
//control类的导入导出
 
    @PostMapping(value = "/importData")
    public Object importManageData(@RequestPart("file") MultipartFile file) throws Exception {
        return CommonUtil.getExcelDataFromFile(file, ExcelTwoDto.class, 1,2);
    }
 
    @PostMapping(value = "/exportData")
    public ResponseEntity<byte[]> exportData(@RequestParam("fileName") String fileName){
        List<ExcelTwoDto> list  = CommonUtil.buildDemoExcel(ExcelTwoDto.class);
        List<Map<String, Object>> exportView = CommonUtil.buildExportView("测试Title", "测试Sheet",list);
        Workbook workbook = ExcelExportUtil.exportExcel(exportView, ExcelType.XSSF);
        ExcelStyleUtil.addNotExistCell(workbook, 0, 3);
        return CommonUtil.exportWorkbook(workbook, fileName);
    }
    
//实体类 
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExcelTwoDto {
 
    @Excel(name = "第一列" ,fixedIndex = 0, orderNum = "0")
    private String codeOne;
    @Excel(name = "第二列" ,fixedIndex = 1, orderNum = "1", width = 50)
    private String codeTwo;
    @ExcelCollection(name = "第三列" , orderNum = "2")
    private List<ExcelChildDto> codeThree;
 
    @Excel(name = "第四列" ,fixedIndex = 4, orderNum = "4", width = 50)
    private String codeFour;
    @Excel(name = "第五列" ,fixedIndex = 5, orderNum = "5")
    private String codeFive;
    @Excel(name = "第六列A", groupName = "第六列汇总" ,fixedIndex = 6, orderNum = "6")
    private String codeThreeOne;
    @Excel(name = "第六列B", groupName = "第六列汇总" ,fixedIndex = 7, orderNum = "7")
    private String codeThreeTwo;
    @Excel(name = "第六列C", groupName = "第六列汇总" ,fixedIndex = 8, orderNum = "8")
    private String codeThreeThree;
}
 
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExcelChildDto {
    @Excel(name = "编码" ,fixedIndex = 0, orderNum = "0")
    private String code;
    @Excel(name = "名称" ,fixedIndex = 1, orderNum = "1", width = 50)
    private String name;
}

   导出测试结果:


       

方法四:Excel模板导出

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

// controller方法
    @PostMapping(value = "/exportData")
    public ResponseEntity<byte[]> exportData(@RequestParam("fileName") String fileName) {
        TemplateExportParams params = new TemplateExportParams("templates/template.xlsx");
        params.setScanAllsheet(true);
        Map<String, Object> dataMap = new HashMap<>();
        List<ExcelThreeDto> list  = CommonUtil.buildDemoExcel(ExcelThreeDto.class);
        dataMap.put("titleName", "标题名称");
        dataMap.put("desc", "备注名称");
        dataMap.put("dataList", list);
        Workbook workbook = ExcelExportUtil.exportExcel(params, dataMap);
        ExcelStyleUtil.setAutoHeight(workbook, 0, 4);
        return CommonUtil.exportWorkbook(workbook, fileName);
    }
    
//实体类
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class ExcelThreeDto {
        private Integer code;
        private String name;
        private String desc;
        private String remark;
    }

        Excel模板的配置

        导出的结果:

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

//maven依赖
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.3.0</version>
        </dependency>
 
    /**
     * excel 导入
     */
    @PostMapping("/importData")
    public Object upload(@RequestParam(name = "file") MultipartFile file) {
        return CommonUtil.importExcel(file, 3, ExcelThreeDto.class);
    }
 
    /**
     * 通用的excel导入的方法
     *
     * @param file 导入文件
     * @param startRow 第几行开始读数据
     * @param clazz 导入后转成的实体类
     * @return
     * @param <T> 
     */
    @SneakyThrows
    public static <T> List<T> importExcel(MultipartFile file, Integer startRow, Class<T> clazz) {
        Workbook wb = new XSSFWorkbook(file.getInputStream());
        //1.2.获取Sheet
        Sheet sheet = wb.getSheetAt(0);
        List<T> list = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (int rowNum = startRow; rowNum <= sheet.getLastRowNum(); rowNum++) {
            //根据索引获取每一个行
            Row row = sheet.getRow(rowNum);
            T obj = clazz.newInstance();
            for (int cellNum = 0; cellNum < row.getLastCellNum() && cellNum< fields.length; cellNum++) {
                Cell cell = row.getCell(cellNum);
                Object value = CommonUtil.getCellValue(cell);
                Field field = fields[cellNum];
                field.setAccessible(true);
                // 注意,这里是为了演示,只分析了Integer和String的写法,实际上要根据Field数据的枚举分类处理
                if (field.getType().equals(Integer.class) && value != null) {
                    field.set(obj, new Double(value.toString()).intValue());
                } else {
                    field.set(obj, value);
                }
            }
            list.add(obj);
        }
        return list;
    }

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

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

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

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

### Spring Boot 中实现 Excel 文件导出功能 在现代企业级应用开发中,Excel 文件的导出是一个常见的需求。Spring Boot 提供了一个灵活的框架,可以通过集成第三方库(如 Apache POI 或 EasyExcel)轻松实现这一目标。 #### 工具选择:Apache POI vs EasyExcel - **Apache POI** 是一个强大的 Java 库,用于读写 Microsoft Office 文档,包括 Word 和 Excel。它提供了丰富的 API 来控制文档结构和样式[^1]。 - **EasyExcel** 则是在 Apache POI 的基础上进行了二次封装,简化了复杂的操作逻辑,尤其适合大数据量场景下的性能优化[^2]。 以下是基于 EasyExcel 的具体实现方案: --- #### Maven 依赖引入 为了使用 EasyExcel,需先将其作为依赖项添加到项目的 `pom.xml` 文件中: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.0.5</version> </dependency> ``` 此版本号可能随时间更新,请根据实际需要调整[^3]。 --- #### 创建实体类映射 假设我们需要导出一份员工信息表,则应创建对应的实体类并标注字段与 Excel 表头的关系: ```java import com.alibaba.excel.annotation.ExcelProperty; public class EmployeeData { @ExcelProperty("姓名") private String name; @ExcelProperty("年龄") private Integer age; @ExcelProperty("部门") private String department; // Getter and Setter methods... } ``` 上述代码片段展示了如何利用注解将对象属性绑定至特定列名上[^4]。 --- #### 编写服务层方法完成导出 下面展示了一种典型的服务端实现方式,该函数接受 HTTP 请求参数,并返回生成好的 Excel 文件流给客户端浏览器下载: ```java import org.springframework.web.bind.annotation.GetMapping; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/export") public class ExportController { @GetMapping("/employees") public void exportEmployees(HttpServletResponse response) throws IOException { List<EmployeeData> list = new ArrayList<>(); // 构造模拟数据集 for (int i = 1; i <= 10; i++) { EmployeeData employee = new EmployeeData(); employee.setName("Employee-" + i); employee.setAge(25 + i % 10); employee.setDepartment("Dept." + ((i / 10) + 1)); list.add(employee); } // 设置响应头信息 response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Disposition", "attachment; filename=employee_list.xlsx"); // 调用 EasyExcel 方法执行导出动作 EasyExcel.write(response.getOutputStream(), EmployeeData.class).sheet("Sheet1").doWrite(list); } } ``` 这里的关键在于调用了 `EasyExcel.write()` 函数指定输出位置、模型类型以及工作簿名称等基本信息后再传入待写入的数据集合即可。 --- #### 自定义样式增强用户体验 如果希望进一步美化最终呈现效果的话,还可以借助 HorizontalCellStyleStrategy 类型来自定义全局统一风格或者单独针对某些特殊区域设置专属外观特性。例如让所有数值类型的单元格右对齐显示等等。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值