首页 > 其他分享 >使用easypoi处理工作簿多sheet导出

使用easypoi处理工作簿多sheet导出

时间:2024-10-26 19:18:50浏览次数:6  
标签:sheet String import 导出 private project new put easypoi

         普通的单表以及数据都是单列呈现的,没有各种合并单元格的样式可以直接使用easyexcel,使用注解加实体类,java实体类属性一一对应excel每列,直接导出非常简单。不过最近的需求非常复杂,需要导出的工作簿,里边有几十张sheet,而且每个sheet的表格样式都是花里胡哨的,而且还要带各种本地超链接以及下拉选型数据有效性验证,以及单元格还得插入图片之类的,样式很复杂,所以使用easyexcel不太好处理,但是又不想直接使用原生的apache poi去逐个单元格去处理,那样的话,一个工作簿一个月都处理不完,公司肯定也是不想花钱用商业版的java工具包(如 Aspose.Cells for Java或者Spire.XLS for Java),所以只能暂时锁定了easypoi,可以灵活利用模版去设置数据填充,同时又可以很好保留表格的整体样式和布局。

     做一个测试,设计了一个比较简单的模版,模版文件是这样的

 

 暂时只设计了两个sheet。

模板表中的指令说明:

  • 三目运算 {{test ? obj:obj2}}
  • n: 表示 这个cell是数值类型 {{n:}}
  • le: 代表长度{{le:()}} 在if/else 运用{{le:() > 8 ? obj1 : obj2}}
  • fd: 格式化时间 {{fd:(obj;yyyy-MM-dd)}}
  • fn: 格式化数字 {{fn:(obj;###.00)}}
  • fe: 遍历数据,创建row
  • !fe: 遍历数据不创建row
  • $fe: 下移插入,把当前行,下面的行全部下移.size()行,然后插入
  • #fe: 横向遍历
  • v_fe: 横向遍历值
  • !if: 删除当前列 {{!if:(test)}}
  • 单引号表示常量值 ‘’ 比如’1’ 那么输出的就是 1
  • &NULL& 空格
  • &INDEX& 表示循环中的序号,自动添加
  • ]] 换行符 多行遍历导出
  • sum: 统计数据
  • cal: 基础的+-X% 计算
  • dict: 字典
  • i18n: 国际化

我用到了时间格式的设置的指令和金额格式指令(设置千位分隔符格式)以及列表数据的循环遍历

$fe:   冒号后是列表数据集合的名字,然后跟每行数据的属性名,默认用t表示每行数据对象,也可以不要t

然后项目案例代码

主要的Maven依赖包

  <!-- https://mvnrepository.com/artifact/cn.afterturn/easypoi-spring-boot-starter -->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-spring-boot-starter</artifactId>
            <version>4.5.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>

然后模拟测试方法

import cn.afterturn.easypoi.entity.ImageEntity;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.img.ImgUtil;
import lombok.Data;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ResourceUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * @author xiaomifeng1010
 * @version 1.0
 * @date: 2024-10-26 13:23
 * @Description
 */
public class ExportManySheetTest {


    public static void main(String[] args) throws IOException {
//        获取要导出的模版文件
        TemplateExportParams params = new TemplateExportParams(
                "excel/exportManySheet.xlsx", 0, 1);
//        params.setHeadingRows(2);
//        params.setHeadingStartRow(2);
//      每个sheet的数据对应一个map
        Map<Integer, Map<String, Object>> sheetMap = new HashMap<>();
//        处理第一个sheet(项目说明)
        Map<String, Object> sheet1Map = new HashMap<String, Object>();
//        模拟从数据库中查询出项目信息
        ProjectAnalysis project = new ProjectAnalysis();
        project.setProjectName("物流项目");
        project.setAnalysisItem("物流项目分析可行性的时候要关注多种因素");
        project.setTechnicalSkill("java,python,mysql");
        project.setAmount(BigDecimal.valueOf(100000d));
        project.setContent("前景广阔");
        project.setMakeDate(new Date());
        project.setManufacturingCost("10000000元");
        project.setDay(120);
        project.setOtherItem("补充事项");
        project.setReportPerson("xiaomifeng1010");
        sheet1Map.put("projectName", project.getProjectName());
        sheet1Map.put("analysisItem", project.getAnalysisItem());
        sheet1Map.put("technicalSkill", project.getTechnicalSkill());
        sheet1Map.put("amount", project.getAmount());
        sheet1Map.put("content", project.getContent());
        sheet1Map.put("makeDate", project.getMakeDate());
        sheet1Map.put("manufacturingCost", project.getManufacturingCost());
        sheet1Map.put("day", project.getDay());
        sheet1Map.put("otherItem", project.getOtherItem());
        sheet1Map.put("reportPerson", project.getReportPerson());
//        将第一个sheet的数据放入map中
        sheetMap.put(0, sheet1Map);

//        开始处理工作簿中的第二个sheet(接口内容)
        Map<String, Object> sheet2Map = new HashMap<>();
//        模拟从数据库中查出来4条数据
        List<InterfaceInfo> interfaceList = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            InterfaceInfo interfaceInfo = new InterfaceInfo();
            interfaceInfo.setInterfaceName("接口" + i);
//            不用设置,可以自动填充(&INDEX&自动填充索引数据)
//            interfaceInfo.setInterfaceNum("编号" + i);
            interfaceInfo.setInterfaceChargeMan("负责人" + i);
            interfaceInfo.setTestPerson("测试人员" + i);
            interfaceInfo.setTestType("测试类型" + i);
            ImageEntity image = new ImageEntity();
            image.setHeight(200);
            image.setWidth(500);
            image.setType("data");
//            image.setRowspan(4);
//            image.setColspan(2);
            if (i < 2) {

//                image.setUrl("imgs/company/baidu.png");
//                直接读取图片为字节数组
                ClassPathResource classPathResource = new ClassPathResource("imgs"+ File.separator +"company"+ File.separator +"baidu.png");
                InputStream inputStream = classPathResource.getInputStream();
//                BufferedImage bufferedImage = ImgUtil.read(inputStream);
//                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//                ImageIO.write(bufferedImage, "png",byteArrayOutputStream );
//                image.setData(byteArrayOutputStream.toByteArray());
                byte[] bytes = IOUtils.toByteArray(inputStream);
                System.out.println("bytes:" + bytes.toString());
                image.setData(bytes);
            } else {
//                image.setUrl("imgs/company/ali.png");
                //                直接读取图片为字节数组

                ClassPathResource classPathResource = new ClassPathResource("imgs"+ File.separator +"company"+ File.separator +"ali.png");
                InputStream inputStream = classPathResource.getInputStream();
//                BufferedImage bufferedImage = ImgUtil.read(inputStream);
//                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//                ImageIO.write(bufferedImage, "png",byteArrayOutputStream );
//                image.setData(byteArrayOutputStream.toByteArray());
                image.setData(IOUtils.toByteArray(inputStream));
            }
            interfaceInfo.setImg(image);
            interfaceList.add(interfaceInfo);
        }
//        填充到map中
        List<Map<String, Object>> sheetDataList = new ArrayList<>();
        for (InterfaceInfo interfaceInfo : interfaceList) {
            Map<String, Object> temp = new HashMap<>();
            temp.put("interfaceName", interfaceInfo.getInterfaceName());
            temp.put("interfaceNum", interfaceInfo.getInterfaceNum());
            temp.put("interfaceChargeMan", interfaceInfo.getInterfaceChargeMan());
            temp.put("testPerson", interfaceInfo.getTestPerson());
            temp.put("testType", interfaceInfo.getTestType());
            temp.put("img", interfaceInfo.getImg());
            sheetDataList.add(temp);
        }
//        表中的$fe:后的集合的名字是list,就是map绑定的key
        sheet2Map.put("list", sheetDataList);
//        将第二个sheet中的数据放到map中
        sheetMap.put(1, sheet2Map);
//        导出到本地
        Workbook book = ExcelExportUtil.exportExcel(sheetMap, params);
//     获取resources路径
        String path = ExportManySheetTest.class.getClassLoader().getResource("").getPath();
        System.out.println("resources的目录:" + path);
        try {
            FileOutputStream fos = new FileOutputStream(path + "test.xls");
            book.write(fos);
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


}

@Data
class ProjectAnalysis {
    private String projectName;
    private String projectNum;
    //    分析事项
    private String analysisItem;
    private String technicalSkill;
    //    生产能力
    private String produceAbility;
    //    制造费用
    private String manufacturingCost;
    //    开发时间
    private Integer day;
    //    新增费用
    private BigDecimal amount;
    //    其他事项
    private String otherItem;
    //    报告人
    private String reportPerson;
    //    编制时间
    private Date makeDate;
    //    会签内容
    private String content;
}

@Data
class InterfaceInfo {
    private String interfaceName;
    private String interfaceNum;
    //    接口负责人
    private String interfaceChargeMan;
    //    测试人员
    private String testPerson;
    private String testType;
    //    图片对象
    private ImageEntity img;
}

注意这个框架的坑还是挺多的,官方文档说的是xls和xlsx两种格式都支持的,但是实测,如果你的模版文件是xls,在读取的时候会报错的

比如我把这行代码改一下:

将resources目录下的模版文件后缀改成xls,不只是直接改后缀,因为我有两个同名的模版文件,后缀不同,相当于是让程序读另外一个xls后缀的模版文件

 

当我改成xls那个文件时,运行方法就会报错:

 就会提示XSSF对象不能转换成HSSF对象

HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls 

XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx  

但是如果是xlsx后缀的文件,就可以正常读取

然后运行后,不会报错

输出的时候,后缀格式目前两种都支持,没出现错误

 

可以查看到导出的test文件

 

 可以看到两个sheet表中都填充好了数据;但是图片目前导出也是也有bug,我尝试使用了图片的实体类设置url方式获取图片数据,以及data方式直接获取图片字节数组数据,去填充图片列,目前导出图片都是空白:

网上有很多其他人也有这个问题,导出图片空白,应该是新版本的bug问题,目前还没有修复,

去年就有人遇到了,不过似乎一直没解决这个问题。 

如果要图片导出,可能还是需要自己手动使用apache poi原生api自己实现一下,不过如果你的需求中,不需要图片的导出,那这个框架已经够用了!

标签:sheet,String,import,导出,private,project,new,put,easypoi
From: https://blog.csdn.net/u011174699/article/details/143257608

相关文章

  • SwiftUI 中.sheet的简单使用
    在SwiftUI中,使用.sheet显示视图时,可以通过状态变量来控制视图的显示和隐藏。onDismiss 在视图关闭时执行某些操作。structCatView:View{@StateprivatevarshowSheet=false//控制视图的显示状态@Stateprivatevarmessage=""//用于显示的信息......
  • Vue2 - 完美解决html2canvas截图不全问题,截屏导出的图片显示不全只有一部分或缺一块,vu
    前言该解决方案任意前端技术栈通用,不仅限Vue。在vue2(手机H5移动端/微信公众号H5页面)项目开发中,使用html2canvas截屏时发现有一部分未截取到少了一块截图不完整,导出保存图片时发现截图只有一半显示不全,另外还有一个问题就是截图时截取当前可视区域的问题(出现滚动条只保......
  • Java EasyExcel 导出报内存溢出的原因与解决方案
    JavaEasyExcel导出报内存溢出的原因与解决方案在现代企业级应用开发中,数据导出功能是一项常见且重要的任务。随着数据量的不断增长,如何高效、稳定地完成数据导出成为开发者面临的一大挑战。EasyExcel是阿里巴巴开源的一款基于Java的Excel处理工具,它以其高效、简洁的特性,广泛......
  • 如何导入导出浏览器indexedDB数据库中的数据
    varDB;varDBName='';varTableName='';indexedDB.open(DBName).onsuccess=asyncfunction(event){DB=event.target.result;};//导入letdata=JSON.parse(fileData);//json字符串形式的数据letresult=awaitinput(DB,data);consol......
  • Oracle数据泵导出的DMP文件还原
    Oracle数据库备份的DMP文件如何还原到数据库中,或者还原到另外一个Oracle数据库中下面这个命令在oracle所在服务器中根据自身情况修改后执行:impdpusername/password@orcldirectory=dbbackupdumpfile=backupfilename.DMPschemas=xxdbremap_schema=xxdb:newxxdb接下来对命令......
  • Vue文件下载和导出
    1.Promise.all()的运行机制输入参数是一个可迭代对象,每个元素是一个Promise。返回一个新的Promise,该Promise在所有输入的Promise都成功解决时解决,或者在任何一个输入的Promise被拒绝时立即拒绝。1.以下解释:该Promise在所有输入的Promise都成功解决时解决//工......
  • 手把手教你使用easyexcel导出数据【附带源码】
    一、前言​ 项目开发过程中,免不了需要数据导出功能,常见的导出工具包有poi,easypoi,easyexcel,它们各有优缺点,简要来说:poi:功能强大,使用起来相对复杂,大数据时可能导致内存溢出easypoi:基于poi实现,功能强大,简单易用,大数据时可能导致内存溢出,小数据量时推荐easyexcel:基于poi实现,性能......
  • exports导出和module.exports导出和require导入
    exports导出module.exports导出require细节情况一情况二情况三......
  • 【原创】修正fpspreadsheet读某些复杂xlsx文件时出错的Bug
    网友“海”在使用fpspreadsheet时遇到读取复杂的xlsx文件会出错: 经跟踪发现运行到fpspreadsheet\source\common\xlsxooxml.pas的procedureTsSpreadOOXMLReader.ReadFromStream的ReadDefinedNames(Doc.DocumentElement.FindNode('definedNames'))这行出错,查看早期(fpspreadsheet......
  • 美团商家电话采集神器 批量导出美团商户联系方式软件
    文章分享作者:1143561141(v同q)使用Python编写美团商家电话采集神器,批量导出美团商户联系方式软件引言:美团商家电话采集神器是一款利用Python编写的脚本工具,旨在批量采集美团商家的联系方式,并将结果导出为Excel文件。本文将介绍如何使用Python编写此工具,并提供相应的代码示例。......