easypoi的使用和遇到的问题

大纲

本文内容简介

  1. easypoi的简单介绍
  2. easypoi的简单使用
  3. easypoi中遇到的问题(导出图片报错,导出图片不显示,导入图片不能保存到自己想要保存到的资源服务器)
  4. easypoi的导入校验和返回校验不通过的excel数据

easypoi简介

easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员
就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板
语言(熟悉的表达式语法),完成以前复杂的写法。

具体使用和注解使用等可以查看http://easypoi.mydoc.io/#text_202982
demo源码地址https://github.com/li469791221/easypoidemo
建议去码云下载新版,老版本有部分bug:https://gitee.com/lemur/easypoi

文中版本,已知开启校验错误数据的时候导出有问题,新版本中修改了源数据删除错误数据获取正确的workbook,以及源数据删除正确数据获取错误的workbook的bug。

准备工作

本demo使用fastdfs资源服务器保存图片,也有使用到httpclient请求网络资源。
1,添加maven依赖。

<!-- easypoi依赖 -->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>3.2.0</version>
        </dependency>

        <!-- fastdfs -->
        <dependency>
            <groupId>com.github.tobato</groupId>
            <artifactId>fastdfs-client</artifactId>
            <version>1.26.1-RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.4.1</version>
        </dependency>

2,配置application.properties。

fdfs.connect-timeout=600
fdfs.so-timeout=1500
#fastdfs服务器的地址
fdfs.tracker-list[0]=192.168.25.133:22122
fdfs.thumbImage.height=150
fdfs.thumbImage.width=150
IMAGE_SERVER_URL=http://192.168.25.133/
spring.jmx.enabled=false

server.port=8080
server.servlet.path=/

3,编写一个excel实体类。

public class Member {

    @Excel(name = "用户id") //表明这个字段要导出到excel或从excel导入
    private Long id;

    @Excel(name = "用户姓名")
    private String name;

    @Excel(name = "生日", format = "yyyy-MM-dd HH:mm:ss")
    //format指定字段导入导出的日期格式化类型
    private Date birthday;

    @Excel(name = "性别", replace = {"男_0", "女_1"}) //replace使用的时候直接"实际含义_数据库实际内容"即可,导入导出均适用
    private String sex;

    @Excel(name = "用户年龄")
    private String age;

    @Excel(name = "电话", width = 16)
    private String phone;

    @Excel(name = "用户账号", width = 16)
    private String loginName;

    @Excel(name = "用户头像", width = 32, height = 32, type = 2)
    //type等于2表示导出的类型为图片。导入的也是一样。
    private String pic;

    public Member() {}

    public Member(Long id, String name, String sex, Date birthday, String age, String phone, String loginName, String pic) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.birthday = birthday;
        this.age = age;
        this.phone = phone;
        this.loginName = loginName;
        this.pic = pic;
    }//getset省略
}

4,准备一个fastdfs服务器服务(资源服务器根据自己需要设定。也可以不要,看自己的图片准备保存到哪里)。

@Service
public class ExcelService {

    @Autowired
    private FastFileStorageClient storageClient;

    @Value("${IMAGE_SERVER_URL}")
    private String url;

    /**
     * 上传资源到fastdfs资源服务器
     * @param file
     * @return
     * @throws IOException
     */
    public String uploadFile(MultipartFile file) throws IOException {
        StorePath storePath = storageClient.uploadFile(file.getInputStream()
                , file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()), null);
        return url + storePath.getFullPath();
    }
}

这样准备工作就做好了。更多的标签介绍可以去上面提供的网址查看,也可以点进@Excel查看这个里面每个属性对应的注释。

easypoi的简单使用。

一.EXCEL导出

@RestController
public class ExcelController {

    @Autowired
    private ExcelService excelService;
	//准备一些图片以供测试
    public static final String[] imgs = new String[]{
//            "http://192.168.25.133/group1/M00/00/01/wKgZhVvC78SAfpWaAAAsAp7EzlE763.jpg",
            "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=108228188,2741176027&fm=27&gp=0.jpg",
            "http://192.168.25.133/group1/M00/00/01/wKgZhVvC8OCAJRuiAABeY6xwxBQ960.jpg",
            "http://192.168.25.133/group1/M00/00/01/wKgZhVvC8PGAIo8LAABP3bR1ZnU861.jpg",
            "http://192.168.25.133/group1/M00/00/01/wKgZhVvC8P6AFx5KAAA22wMuH2A112.jpg"
    };

    /**
     * 上传文件到fastdfs
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/uploadFile")
    public String uploadFile(MultipartFile file) throws IOException {
        String path = excelService.uploadFile(file);
        return path;
    }

    /**
     * 下载excel
     */
    @GetMapping("/export")
    public void export(HttpServletResponse response) throws IOException {
        List<Member> list = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            list.add(new Member((long)i, "张三" + i, i % 2 + "", new Date(), 20 + i + "",
                    "15219873928", "123456" + i, imgs[i]));
        }
		//ExportParams可以通过构造的两个参数设置导出的sheet名字和excel的title列名
        ExportParams params = new ExportParams();
        Workbook workbook = ExcelExportUtil.exportExcel(params, Member.class, list);

        // 告诉浏览器用什么软件可以打开此文件
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 下载文件的默认名称
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户数据表","UTF-8") + ".xls");
        //编码
        response.setCharacterEncoding("UTF-8");
        workbook.write(response.getOutputStream());
    }
    }

直接在浏览器上面输入http://localhost:8080/export下载excel。

导出图片的时候遇到的问题ArrayIndexOutOfBoundsException

1,导出图片的时候报错:

java.lang.ArrayIndexOutOfBoundsException: 0
	at cn.afterturn.easypoi.util.PoiPublicUtil.getFileExtendName(PoiPublicUtil.java:147)

问题描述是导出图片的时候下标越界。让我们debug来看下问题原因
在这里插入图片描述
可以看到是从ImageCache中获取的data为空造成。
继续到ImageCache中查找原因。
在这里插入图片描述
可以看到是在ImageIO.write()我们图片url的时候得到了一个空的字节数组。
那么问题出来了,这里为什么返回了一个空的字节数组。从write方法的三个参数中的第二个参数我们可以看到这里将图片路径进行了字符串截取,截取的是第一个点以后的字符串,显然这是在截取图片的后缀名。
因为我们使用的图片路径为http://192.168.25.133/group1/M00/00/01/wKgZhVvC78SAfpWaAAAsAp7EzlE763.jpg。随意第一个点之后的字符串显然有问题,所以这里应该截取最后一个点后面的字符串。

发现了问题,那么我们就需要解决问题:
Easypoi的ImageCache为我们提供了setLoadingCache()方法,使得我们可以设置自己想要的loadingCache,所以,我们只需要自己重写一个loadingCache并赋值给ImageCache。
我们可以在Spring容器启动后把这个自定义的loadingCache赋值给ImageCache。
只需要修改这个截取的地方即可。
在这里插入图片描述

导出图片的时候遇到图片不显示的问题

在导出图片的时候,部分图片显示不出来。
这个问题的原因肯定就要从导出图片的时候获取图片的流信息上面查找。
从上面的问题我们发现图片的流是在loadingCache里面通过POICacheManager.getFile()获取的,所以我们需要到这个类里面去找到获取图片流的地方。
在这里插入图片描述
这里显示这个fileLoader是默认实现,通过这个类里面的setFileLoader()我们可以知道。我们可以重写这个fileLoader
在这里插入图片描述
从这里我们看到easypoi是使用URLConnection去获取网络图片流的
那么问题肯定就是URLConnection获取图片流的时候出了问题。
所以我换成了httpclient来获取图片,可能还会有其他问题,但是我这边目前没有发现问题。

具体解决方法自己写一个fileloader实现IFileLoader接口,我们只需要重写上面获取网络图片的这一块地方,然后赋值给POICacheManager。
在这里插入图片描述
在这里插入图片描述

easypoi的简单导入

简单导入只需要一行代码。

    /**
     * 简单导入
     * @param file
     * @throws Exception
     */
    @PostMapping("/easyImport")
    public void easyImport(MultipartFile file) throws Exception {
        List<Member> list = ExcelImportUtil.importExcel(file.getInputStream(), Member.class, new ImportParams());
        for (Member member : list) {
            System.out.println(member);
        }

//Member{id=0, name='张三0', birthday=Sun Oct 14 16:22:16 CST 2018, sex='0', age='20', phone='15219873928', loginName='1234560', pic='/excel/upload/img\Member\pic3571587826.JPG'}
//Member{id=1, name='张三1', birthday=Sun Oct 14 16:22:16 CST 2018, sex='1', age='21', phone='15219873928', loginName='1234561', pic='/excel/upload/img\Member\pic20436614652.JPG'}
//Member{id=2, name='张三2', birthday=Sun Oct 14 16:22:16 CST 2018, sex='0', age='22', phone='15219873928', loginName='1234562', pic='/excel/upload/img\Member\pic88937536202.JPG'}
//Member{id=3, name='张三3', birthday=Sun Oct 14 16:22:16 CST 2018, sex='1', age='23', phone='15219873928', loginName='1234563', pic='/excel/upload/img\Member\pic57721772929.JPG'}
    }

结果如上面的注释,可以看到图片是保存到了项目目录下面的。这个可以通过@Excel里面的savePath属性改写保存到项目下的哪个目录。

简单导入Excel并将图片保存到fastdfs自定义的资源服务器上面

查看easypoi源码。导入的ExcelImportUtil.importExcel()方法里面使用的是new ExcelImportService().importExcelByIs(inputstream, pojoClass, params, false).getList();

发现上传图片的逻辑在ExcelImportService.saveImage()方法里
在这里插入图片描述
发现只有两种保存图片方式:一种保存到服务器目录下,一种保存到数据库,这也对应了@Excel里面的注释描述

解决方法:自己重写ExcellImportService.java(实际上是重写他的saveImage里面保存图片的方法)。
然后直接使用这个自定义的ExcellImportService进行导入,不能在使用之前easypoi提供的导入入口。

在这里插入图片描述
在这里插入图片描述
结果也在上面的注释里面,可以看到pic的路径已经是我们fastdfs资源服务器里面的资源的路径了。

复杂导入(数据校验并返回校验失败的excel同时携带了每条报错的原因)

编写校验规则

我们在导入的时候经常需要做数据校验。
easypoi可以帮助我们完成这件事情,我们只需要在excel实体类上面添加校验规则和校验失败的提示信息即可,同时也可以自定义校验规则

1.添加校验规则注解。
public class Member implements IExcelModel {

    @Excel(name = "用户id")
    @NotNull //基本数据类型使用,都是javax.validation.constraints包里的
    private Long id;

    @Excel(name = "用户姓名")
    @NotEmpty //字符串类型使用
    private String name;

    @Excel(name = "生日", format = "yyyy-MM-dd HH:mm:ss")
    private Date birthday;

    @Excel(name = "性别", replace = {"男_0", "女_1"}) //replace使用的时候直接"实际含义_数据库实际内容"即可,导入导出均适用
    @Pattern(regexp = "^[0-1]$", message = "性别输入有误") //字符串类型使用
    private String sex;

    @Excel(name = "用户年龄")
    @Pattern(regexp = "^\\d{1,3}$", message = "年龄输入有误")
    private String age;

    @Excel(name = "电话", width = 16)
    @Pattern(regexp = "^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$", message = "电话输入有误")
    private String phone;

    @Excel(name = "用户账号", width = 16)
    private String loginName;

    @Excel(name = "用户头像", width = 32, height = 32, type = 2)
    private String pic;

    public Member() {}

    public Member(Long id, String name, String sex, Date birthday, String age, String phone, String loginName, String pic) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.birthday = birthday;
        this.age = age;
        this.phone = phone;
        this.loginName = loginName;
        this.pic = pic;
    }
}

添加自定义校验规则需要继承IExcelVerifyHandler,然后给importParam设置这个校验器

/**
 * 自定义的导入校验器
 */
public class MyVerifyHandler implements IExcelVerifyHandler<Member> {

    @Override
    public ExcelVerifyHandlerResult verifyHandler(Member member) {
        ExcelVerifyHandlerResult result = new ExcelVerifyHandlerResult();
        //假设我们要添加用户,
        //现在去数据库查询loginName,如果存在则表示校验不通过。
        //假设现在数据库中有个loginName 1234560
        if ("1234560".equals(member.getLoginName())) {
            result.setMsg("该用户已存在");
            result.setSuccess(false);
            return result;
        }
        result.setSuccess(true);
        return result;
    }
}

打开校验功能

ImportParams params = new ImportParams();
params.setNeedVerfiy(true);

Member继承IExcelModel 接口获取校验失败信息。

    private String errorMsg; //自定义一个errorMsg接受下面重写IExcelModel接口的get和setErrorMsg方法。

    @Override
    public String getErrorMsg() {
        return errorMsg;
    }

    @Override
    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

写一个MemberFailed extends Member。

**
 * excel导入错误信息实体类
 */
public class MemberFailed extends Member {

    @Excel(name = "错误信息")
    private String errorMsg;

    @Override
    public String getErrorMsg() {
        return errorMsg;
    }

    @Override
    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public static MemberFailed member2MemberFailed(Member member) {
        MemberFailed failed = new MemberFailed();
        failed.setErrorMsg(member.getErrorMsg());
        failed.setAge(member.getAge());
        failed.setBirthday(member.getBirthday());
        failed.setId(member.getId());
        failed.setLoginName(member.getLoginName());
        failed.setName(member.getName());
        failed.setPhone(member.getPhone());
        failed.setPic(member.getPic());
        failed.setSex(member.getSex());
        return failed;
    }

    public static List<MemberFailed> members2MemberFaileds(List<Member> members) {
        List<MemberFailed> list = new ArrayList<>();
        for (Member member : members) {
            list.add(member2MemberFailed(member));
        }
        return list;
    }
}

要获取校验失败的集合或者workbook的话需要设置needMore等于true。

在这里插入图片描述

开始导入

@PostMapping("/complexImport")
    public void complexImport(MultipartFile file, HttpServletResponse response) throws Exception {
        ImportParams params = new ImportParams();
        params.setNeedVerfiy(true);
        params.setVerifyHandler(new MyVerifyHandler());
        ExcelImportResult importResult = new ExcelImportService().importExcelByIs(file.getInputStream(),
                Member.class, params, true);
        //getList()里面的就是所有校验成功的excel数据        
        List<Member> list = importResult.getList();
        if (list != null) {
            for (Member member : list) {
                System.out.println(member);
            }
        }
        System.out.println("-----------------------");
        
        //getFailWorkbook()和getFailList()里面的就是所有校验失败的excel数据 
        Workbook failWorkbook = importResult.getFailWorkbook();
        List<Member> failList = importResult.getFailList();

        List<MemberFailed> faileds = MemberFailed.members2MemberFaileds(failList);

//        response.setHeader("content-Type", "application/vnd.ms-excel");
//        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户数据表","UTF-8") + ".xls");
//        response.setCharacterEncoding("UTF-8");
//        failWorkbook.write(response.getOutputStream());

		//将错误excel信息返回给客户端
        ExportParams exportParams = new ExportParams();
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, MemberFailed.class, faileds);
        response.setHeader("content-Type", "application/vnd.ms-excel");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户数据表","UTF-8") + ".xls");
        response.setCharacterEncoding("UTF-8");
        workbook.write(response.getOutputStream());
    }

我自己的测试返回的校验失败的结果如下:
在这里插入图片描述

导入导出有标题列的excel

导出

@GetMapping("/export")
    public void export(HttpServletResponse response) throws IOException {
        List<Member> list = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            list.add(new Member((long)i, "张三" + i, i % 2 + "", new Date(), 20 + i + "",
                    "15219873928", "123456" + i, imgs[i]));
        }
        //ExportParams params = new ExportParams();
        //导出的时候指明标题列名和sheet名字
        ExportParams params = new ExportParams("用户数据", "用户数据");
        Workbook workbook = ExcelExportUtil.exportExcel(params, Member.class, list);

        // 告诉浏览器用什么软件可以打开此文件
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 下载文件的默认名称
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户数据表","UTF-8") + ".xls");
        //编码
        response.setCharacterEncoding("UTF-8");
        workbook.write(response.getOutputStream());
    }

结果如下:
在这里插入图片描述

导入

如果按照之前那么导入会获取不到数据或者报错。
原因:这里多了一个标题列,导出的时候还是从第一列开始读取,结果就会出问题。我们因该从第二列开始读取。
解决:指定标题列params.setTitleRows(1);

@PostMapping("/complexImport")
    public void complexImport(MultipartFile file, HttpServletResponse response) throws Exception {
        ImportParams params = new ImportParams();
        //在有标题列的时候,需要指明标题列在1,默认是0
        params.setTitleRows(1);
        params.setNeedVerfiy(true);
        params.setVerifyHandler(new MyVerifyHandler());
        ExcelImportResult importResult = new ExcelImportService().importExcelByIs(file.getInputStream(),
                Member.class, params, true);
        List<Member> list = importResult.getList();
        if (list != null) {
            for (Member member : list) {
                System.out.println(member);
            }
        }
        System.out.println("-----------------------");
        Workbook failWorkbook = importResult.getFailWorkbook();
        List<Member> failList = importResult.getFailList();

        List<MemberFailed> faileds = MemberFailed.members2MemberFaileds(failList);

//        response.setHeader("content-Type", "application/vnd.ms-excel");
//        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户数据表","UTF-8") + ".xls");
//        response.setCharacterEncoding("UTF-8");
//        failWorkbook.write(response.getOutputStream());

        ExportParams exportParams = new ExportParams();
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, MemberFailed.class, faileds);

        // 告诉浏览器用什么软件可以打开此文件
        response.setHeader("content-Type", "application/vnd.ms-excel");
        // 下载文件的默认名称
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户数据表","UTF-8") + ".xls");
        //编码
        response.setCharacterEncoding("UTF-8");
        workbook.write(response.getOutputStream());
    }
<think>嗯,用户问的是关于EasyPoi使用教程,我需要用中文回答。首先,我得回忆一下EasyPoi的基本信息,它是一个基于Apache POI的简化开发库,主要用于处理ExcelWord文档。用户可能想了解如何快速上手,所以应该从基础开始,比如导入依赖,然后逐步介绍常用功能。 首先,要确认用户对JavaMaven是否熟悉,但可能他们已经有基础,所以直接给出Maven依赖的示例。然后,可能需要分模块介绍,比如注解导出、模板导出导入数据等。每个部分需要简洁的代码示例,说明关键点,比如实体类注解的使用,以及如何调用方法导出。 接下来,用户可能需要知道如何处理更复杂的情况,比如导出图片或者使用模板,这时候要提到相关的注解如@ExcelImage,以及模板导出的步骤。同时,导入数据也是常见需求,需要说明如何读取Excel并转换为对象列表。 还需要注意一些常见问题,比如文件路径的正确性,依赖冲突的可能性,以及如何处理大数据量的导出,避免内存溢出。可能用户在使用过程中会遇到这些问题,提前给出提示会更有帮助。 另外,用户可能希望了解EasyPoi的优势适用场景,是否需要对比其他库如Apache POI或EasyExcel,但用户没有明确提到,所以暂时先集中在EasyPoi本身。最后,提供官方文档链接GitHub地址,方便用户进一步查阅。 需要检查步骤是否清晰,代码示例是否正确,以及是否有遗漏的重要功能。比如导出到Word可能也是用户关心的,但可能优先级不如Excel高。根据时间限制,可能简要提及,或者留到进阶部分。总之,结构要清晰,从入门到常用功能,再到注意事项,帮助用户快速上手。</think>以下是一个简明的 **EasyPoi 使用教程**,适用于快速处理 Excel/Word 的导入导出需求: --- ### **1. EasyPoi 简介** - **是什么**:基于 Apache POI 的简化开发库,通过注解模板机制快速实现 Excel/Word 的读写。 - **优势**:代码量少、支持注解、模板导出、大数据量导出(SXSSF模式)。 --- ### **2. 快速入门** #### **2.1 添加依赖** ```xml <!-- Maven 依赖 --> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-spring-boot-starter</artifactId> <version>4.4.0</version> </dependency> ``` --- #### **2.2 注解导出 Excel** **步骤 1:实体类添加注解** ```java @ExcelTarget("user") // 定义导出实体标识 public class User { @Excel(name = "姓名", orderNum = "0") // 表头名称与列顺序 private String name; @Excel(name = "年龄", orderNum = "1") private Integer age; @Excel(name = "头像", type = 2, width = 20, height = 20) // type=2 表示图片 private String avatarPath; // 省略 Getter/Setter } ``` **步骤 2:导出代码** ```java List<User> userList = getUsers(); // 获取数据 ExportParams params = new ExportParams("用户列表", "用户数据"); Workbook workbook = ExcelExportUtil.exportExcel(params, User.class, userList); FileOutputStream fos = new FileOutputStream("user_list.xlsx"); workbook.write(fos); fos.close(); ``` --- #### **2.3 模板导出 Excel** **步骤 1:创建 Excel 模板** - 使用 `{{}}` 标记变量,如 `{{name}}`、`{{age}}`。 **步骤 2:代码调用** ```java TemplateExportParams params = new TemplateExportParams("template.xlsx"); Map<String, Object> data = new HashMap<>(); data.put("name", "张三"); data.put("age", 25); Workbook workbook = ExcelExportUtil.exportExcel(params, data); // 写入文件(同上) ``` --- #### **2.4 导入 Excel 数据** ```java ImportParams params = new ImportParams(); params.setTitleRows(1); // 标题占1行 params.setHeadRows(1); // 表头占1行 List<User> userList = ExcelImportUtil.importExcel( new File("user_list.xlsx"), User.class, params); ``` --- ### **3. 常用功能扩展** 1. **导出图片** - 使用 `@Excel(name="头像", type=2)` 注解,字段存储图片路径。 2. **自定义格式** - 通过 `@Excel(format = "yyyy-MM-dd")` 处理日期格式。 3. **大数据量导出** - 使用 `ExportParams.setType(ExcelType.XSSF)` 并启用 SXSSF 模式。 4. **Word 导出** - 类似 Excel使用 `WordExportUtil` `@WordText` 注解。 --- ### **4. 注意事项** - **文件路径**:确保模板文件路径正确(建议放在 `resources` 目录)。 - **依赖冲突**:避免与老版本 POI 冲突,检查依赖树。 - **性能**:大数据量导出使用 `SXSSFWorkbook` 模式。 --- ### **5. 官方资源** - [GitHub 地址](https://github.com/lemur-official/lemur-poi) - [详细文档](http://easypoi.mydoc.io/) 如需具体场景的代码示例(如合并单元格、复杂表头),可进一步说明需求!
评论 68
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值