SpringBoot 实现 Excel 导入导出功能的三种实现方式

发布于:2025-08-12 ⋅ 阅读:(14) ⋅ 点赞:(0)

在日常开发中,Excel 的导入导出是非常常见的需求,尤其在管理系统中更是必不可少的功能。本文将基于实际项目代码,介绍三种不同的 Excel 导入导出实现方式,包括使用 EasyPOI 工具、自定义 POI 操作以及结合模板的 Excel 生成方式,并对它们的优缺点进行分析对比。

 

一、使用 EasyPOI 实现 Excel 操作

EasyPOI 是一款基于 POI 封装的 Excel 处理工具,它简化了 Excel 的导入导出代码,使开发更加高效。

1.1 导出功能实现

/**
 * 数据导出接口
 */
@GetMapping("/exportExcel")
public Result exportExcel(PersonListQuery query) {
    // 1. 获取要导出的人员数据列表
    List<PersonListVO> personListvo = personService.exportExcel(query);
    
    // 2. 设置导出参数
    ExportParams exportParams = new ExportParams("人员数据报表","人员数据");
    exportParams.setStyle(ExcelExportStylerColorImpl.class);
    
    // 3. 生成Excel工作簿
    Workbook workbook = ExcelExportUtil.exportExcel(exportParams, PersonListVO.class, personListvo);
    String fileName = System.currentTimeMillis()+".xls";
    String filePath = Paths.get(excelPath, fileName).toString();
    
    // 4. 确保存储目录存在
    File file = new File(excelPath);
    if (!file.exists()) {
        file.mkdirs();
    }
    
    try{
        // 5. 写入文件
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        workbook.write(out);
        byte[] excelBytes = out.toByteArray();
        Files.write(Paths.get(filePath), excelBytes);
        
        // 6. 关闭资源
        out.close();
        workbook.close();
    }catch (Exception e){
        e.printStackTrace();
        return Result.error("导出失败");
    }
    return Result.ok().put("data",fileName);
}

1.3 EasyPOI 方式优缺点

优点

  • 代码简洁,开发效率高
  • 注解驱动,配置灵活
  • 支持复杂表头、图片等复杂场景
  • 自带样式美化功能

缺点

  • 额外引入第三方依赖
  • 对于非常复杂的 Excel 模板支持不够灵活

二、基于 POI 的自定义 Excel 工具类

当需要更精细的控制 Excel 格式时,可以直接使用 Apache POI 进行自定义开发,封装成工具类使用。

public class ExcelUtil {

    public static String ExpPersonInfo(List<PersonVO> info, String path){
        POIFSFileSystem fs = null;
        int headRow = 2;// 数据起始行(跳过前2行表头)
        String descfile = null;
        
        try {
            // 1. 复制模板文件
            String srcfile = path + "personInfo.xls";// 源模板文件路径
            Date date = new Date();
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            String dateStr = format.format(date);
            descfile = dateStr + ".xls";
            FileInputStream fis = new FileInputStream(srcfile);
            FileOutputStream fos = new FileOutputStream(path+descfile);
            byte [] buffer = new byte[1024*4];
            while(fis.read(buffer) != -1){
                fos.write(buffer);
            }
            fis.close();
            fos.close();
            
            // 2. 打开新创建的文件并写入数据
            fs = new POIFSFileSystem(new FileInputStream(path + descfile));
            fos = new FileOutputStream(path + descfile);
            HSSFWorkbook wb1 = new HSSFWorkbook(fs);
            HSSFSheet sheet = wb1.getSheetAt(0);
            
            // 3. 创建单元格样式
            HSSFCellStyle style = wb1.createCellStyle();
            style.setBorderLeft(BorderStyle.THIN);
            style.setBorderRight(BorderStyle.THIN);
            style.setBorderTop(BorderStyle.THIN);
            style.setBorderBottom(BorderStyle.THIN);
            
            // 4. 写入数据
            int size = info.size();
            for(int i = 0;i < size;i++){
                int col = 0;
                PersonVO p = info.get(i);
                HSSFRow row = sheet.createRow(i+headRow);
                
                HSSFCell cell = row.createCell(col++);
                cell.setCellStyle(style);
                cell.setCellValue(p.getPersonId());
                
                cell = row.createCell(col++);
                cell.setCellStyle(style);
                cell.setCellValue(p.getCommunityName());
                
                // 其他列...
            }
            
            // 5. 保存并关闭
            wb1.write(fos);
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return descfile;
    }
}

2.1 自定义工具类优缺点

优点

  • 完全自定义,灵活性高
  • 可以精确控制 Excel 的每一个单元格
  • 可以结合模板生成复杂格式的 Excel

缺点

  • 代码量大,开发效率低
  • 需要手动处理样式、边框等细节
  • 需注意资源关闭,否则可能导致内存泄漏

三、基于 POI 的通用导入实现

对于 Excel 导入,也可以直接使用 POI 实现通用的解析方案,适用于各种复杂结构的 Excel。

/**
 * 数据导入操作
 */
@PostMapping("/parsefile/{fileName}")
public Result parsefile(@PathVariable("fileName") String fileName, HttpSession session){
    User user = (User) session.getAttribute("user");
    POIFSFileSystem fs = null;
    HSSFWorkbook wb = null;
    
    try {
        // 1. 读取Excel文件
        String basePath = excel + fileName;
        fs = new POIFSFileSystem(new FileInputStream(basePath));
        wb = new HSSFWorkbook(fs);
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    // 2. 解析Excel内容到二维数组
    HSSFSheet sheet = wb.getSheetAt(0);
    Object[][] data = null;
    int r = sheet.getLastRowNum()+1;
    int c = sheet.getRow(0).getLastCellNum();
    int headRow = 2;
    data = new Object[r - headRow][c];
    
    for (int i = headRow; i < r; i++) {
        HSSFRow row = sheet.getRow(i);
        for (int j = 0; j < c; j++) {
            HSSFCell cell = null;
            try {
                cell = row.getCell(j);
                DataFormatter dataFormater = new DataFormatter();
                String a = dataFormater.formatCellValue(cell);
                data[i - headRow][j] = a;
            } catch (Exception e) {
                data[i-headRow][j] = "";
                // 特殊处理第一列
                if(j==0){
                    try {
                        double d = cell.getNumericCellValue();
                        data[i - headRow][j] = (int)d + "";
                    }catch(Exception ex){
                        data[i-headRow][j] = "";
                    }
                }
            }
        }
    }
    
    // 3. 处理解析后的数据并保存到数据库
    int row = data.length;
    String errinfo = "";
    headRow = 3;
    
    for (int i = 0; i < row; i++) {
        Person single = new Person();
        single.setPersonId(0);
        single.setState(1);
        single.setFaceUrl("");
        
        try {
            int col=1;
            String communityName = data[i][col++].toString();
            QueryWrapper<Community> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("community_name", communityName);
            Community community = this.communityService.getOne(queryWrapper);
            
            if( community == null){
                errinfo += "Excel文件第" + (i + headRow) + "行小区名称不存在!";
                return Result.ok().put("status", "fail").put("data", errinfo);
            }
            
            single.setCommunityId(community.getCommunityId());
            single.setTermName(data[i][col++].toString());
            single.setHouseNo(data[i][col++].toString());
            single.setUserName(data[i][col++].toString());
            // 设置其他字段...
            
            this.personService.save(single);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    return Result.ok().put("status", "success").put("data","数据导入完成!");
}

3.1 通用 POI 导入优缺点

优点

  • 可以处理各种复杂格式的 Excel
  • 对 Excel 结构的控制更加精细
  • 适合导入格式不固定的场景

缺点

  • 代码复杂,需要处理各种异常情况
  • 解析逻辑与业务逻辑混合,可读性差
  • 开发和维护成本高

四、三种方式的对比与选择建议

实现方式 开发效率 灵活性 适用场景 依赖
EasyPOI 大部分常规导入导出场景 需引入 EasyPOI 依赖
自定义 POI 工具类 需要精确控制 Excel 格式,结合模板 仅需 POI 依赖
通用 POI 导入 复杂 Excel 结构,格式不固定 仅需 POI 依赖

选择建议

  1. 对于大多数常规的 Excel 导入导出需求,优先选择 EasyPOI,开发效率最高
  2. 当需要使用模板生成复杂格式 Excel 时,可以采用自定义 POI 工具类的方式
  3. 当 Excel 格式复杂且不固定,或者有特殊解析需求时,才考虑使用通用 POI 导入方式
  4. 导入导出功能较多的项目,建议封装统一的工具类或服务,避免代码重复

五、文件上传通用处理

无论采用哪种导入方式,都需要先处理文件上传,以下是一个通用的文件上传实现:

@PostMapping("/excelUpload")
public Result excelUpload(@RequestParam("uploadExcel") MultipartFile file) throws Exception {
    if(file.getOriginalFilename().equals("")){
        return Result.error("没有选中要上传的文件");
    }else {
        // 生成唯一文件名
        String picName = UUID.randomUUID().toString();
        String oriName = file.getOriginalFilename();
        String extName = oriName.substring(oriName.lastIndexOf("."));
        String newFileName = picName + extName;
        
        // 保存文件
        File targetFile = new File(excel, newFileName);
        file.transferTo(targetFile);
        
        return Result.ok().put("data",newFileName);
    }
}

六、总结

Excel 导入导出是 Java 开发中的常见功能,选择合适的实现方式可以大大提高开发效率。EasyPOI 作为封装完善的工具,能够满足大部分需求;而当遇到复杂场景时,直接使用 POI 进行自定义开发则更加灵活。在实际项目中,应根据具体需求选择合适的实现方式,同时注意代码的可维护性和资源的正确释放。


网站公告

今日签到

点亮在社区的每一天
去签到