1 Star 0 Fork 0

舒一笑 / 导出Excel技术分享

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

导出Excel技术分享

介绍

基础导出Excel的样式demo演示

Excel前置知识

首先大家就是在大学的计算机导论等课程肯定有了解过office全家桶中的工具之一Excel。在印象当中就是Excel是普遍使用的就是有03和07的两个不同的版本。请问一下大家就是能说一说就是这两个版本有什么区别吗?

显而易见就是从了直观上,能看到就是07的版本在文件的后缀名上多了一个x。但是除了这个之外还有什么别的不同吗?

image-20230708145807664

可能大家也一下就想到了那就是这两者的导出的行数是存在限制的。03版本的Excel是在65536行之后存在大量的白内障。而在07版本中则明显在数据容量上进行了巨大的提升。但是也是存在上限的。白内障出现的位置是在1048576行之后。百万行的数据量相比之前的03版本已经能极大的提高我们的日常工作数据所需。

image-20230708150051250

image-20230708150325505

image-20230708150546955

Excel的基本组成介绍

在导出一个Excel基本的组成部分在代码中体现的就是这四个骨架。

image-20230708183223801

目前的主流导出Excel技术介绍

在阿里巴巴开源的导出Excel工具包中介绍了三个工具。EasyExcel、Apache poi、jxl。其中目前关于这三者的技术中的最后的JXL技术是是Java中的一个原生类库。但是它只能支持Excel 95-2000。比03Excel还要古老而且这个类库已经停止更新和维护了。EasyExcel、Apache poi这两个项目一直在更新,今天就和大家分享一下这两个工具在使用上的一些实现。

EasyExcel是在POI基础之上的一些封装,所以在介绍他之前我们先来介绍一下Apache poi。

image-20230708151022763

Apache poi工具的介绍

Apache POI是用Java语言编写的工具,这一点上来不想其他的工具使用别的语言来实现(例如redis使用C/C++编写)说对Java的开发者还是比较友好的能直接看懂。Apache POI 是基于 Office Open XML 标准(OOXML)和 Microsoft 的 OLE 2 复合⽂档格式(OLE2)处理各种⽂件格式的开源项⽬。 简⽽⾔之,可以使⽤ Java 读写MS Excel ⽂件,可以使⽤ Java 读写 MS Word 和 MS PowerPoint ⽂件。

image-20230708152414868

功能模块的介绍:

  • HSSF:提供读写 Microsoft Excel XLS 格式 (Microsoft Excel 97 (-2003)) 档案的功能。
  • XSSF:提供读写 Microsoft Excel OOXML XLSX 格式 (Microsoft Excel XML (2007+))档案的功能。
  • SXSSF:提供低内存占⽤量读写 Microsoft Excel OOXML XLSX 格式档案的功能。针对大数量的写入量身打造。
  • HWPF:提供读写 Microsoft Word DOC97 格式 (Microsoft Word 97 (-2003)) 档案的功能。
  • XWPF:提供读写 Microsoft Word DOC2003 格式 (WordprocessingML (2007+)) 档案的功能。
  • HSLF/XSLF:提供读写 Microsoft PowerPoint 格式档案的功能。
  • HDGF/XDGF:提供读 Microsoft Visio 格式档案的功能。
  • HPBF:提供读 Microsoft Publisher 格式档案的功能。
  • HSMF:提供读 Microsoft Outlook 格式档案的功能。

上面的九大功能模块有的并没有直接显示,例如SXSSF在XSSF的内部。

image-20230708161340039

使用POI完成对一个基本的Excel的数据写入

通过前面对Excel的格式骨架的介绍,大致可以将书写Eexcel的编码实现分为六大步骤。

  1. 创建工作簿:Workbook。
  2. 创建工作表:sheet。
  3. 创建行:Row。
  4. 创建列上的单元格:Cell。
  5. 完成对数据的写入。
  6. 使用字节流完成文件的最终生成

生成03版本Excel的效果演示

由下面的65536行一下就成为了白内障区域和文件名是xls后缀证明目前生成时03版本的Excel

image-20230708192747600

image-20230708192828468

生成03版本Excel代码示例

  public static void GenerateExcel03() throws  Exception {
        // 创建工作簿
        Workbook workbook = new HSSFWorkbook();

        // 创建工作表
        Sheet sheet = workbook.createSheet("03版本");

        // 创建行 第0行 row0
        Row row0 = sheet.createRow(0);

        // 创建行上的单元格 第一行第一个
        Cell cell01 = row0.createCell(0);
        // 创建行上单元格 第一行第二个
        Cell cell02 = row0.createCell(1);

        // 创建行 第1行row0
        Row row1 = sheet.createRow(1);
        // 创建第二行第一个
        Cell cell11 = row1.createCell(0);
        // 创建第二行第二个
        Cell cell12 = row1.createCell(1);
        // 第二行第一个赋值
        cell11.setCellValue("小花");
        cell12.setCellValue("18");


        // 数据写入
        cell01.setCellValue("姓名");
        cell02.setCellValue("年龄");


        // 利用流生成Excel表格
        FileOutputStream fileOutputStream = new FileOutputStream("./03版本的Excel.xls");
            workbook.write(fileOutputStream);
        // 关闭流
        fileOutputStream.close();
        System.out.println("03版本Excel生成完成");

    }

生成07版本Excel的效果演示

image-20230708193035366

image-20230708193210155

生成07版本Excel的代码示例

public static void GenerateExcel07() throws  Exception {
        // 创建工作簿 XSSFWorkbook这里是与03版本的不同点
        Workbook workbook = new XSSFWorkbook();

        // 创建工作表 
        Sheet sheet = workbook.createSheet("07版本");

        // 创建行 第0行row0
        Row row0 = sheet.createRow(0);

        // 创建行上的单元格 第一行第一个
        Cell cell01 = row0.createCell(0);
        // 创建行上单元格 第一行第二个
        Cell cell02 = row0.createCell(1);

        // 创建行 第1行row0
        Row row1 = sheet.createRow(1);
        // 创建第二行第一个
        Cell cell11 = row1.createCell(0);
        // 创建第二行第二个
        Cell cell12 = row1.createCell(1);
        // 第二行第一个赋值
        cell11.setCellValue("小花");
        cell12.setCellValue("18");


        // 数据写入
        cell01.setCellValue("姓名");
        cell02.setCellValue("年龄");


        // 利用流生成Excel表格
        FileOutputStream fileOutputStream = new FileOutputStream("./03版本的Excel.xlsx");
            workbook.write(fileOutputStream);
        // 关闭流
        fileOutputStream.close();
        System.out.println("07版本Excel生成完成");

    }

原生POI生成Excel的速度测试

image-20230708193921665

在EasyExcel官网中说明了POI存在的劣势与不足。那接下来我们来验证一下原生POI导出Excel的速度和内存溢出OOM问题。

生成03版本的Excel时间测试

按照03版本单个sheet数据容量上限,生成下面这部分数据花费14秒时间

image-20230709004903399

image-20230708220204265

代码示例

public static void GenerateExcel03() throws  Exception {
        // 创建工作簿
        Workbook workbook = new HSSFWorkbook();

        // 创建工作表
        Sheet sheet = workbook.createSheet("03版本");
        // 记录开始时间
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 65535; i++) {
            Row row = sheet.createRow(i);
            for (int j = 0; j < 255; j++) {
                Cell cell = row.createCell(j);
                cell.setCellValue("测试数据");
            }
        }
        // 记录结束时间
        long endTime = System.currentTimeMillis();
        // 利用流生成Excel表格
        FileOutputStream fileOutputStream = new FileOutputStream("./03版本生成时间测试.xls");
        workbook.write(fileOutputStream);
        // 关闭流
        fileOutputStream.close();
        System.out.println("03版本Excel生成完成");
        System.out.println("生成消耗时间" + (endTime-startTime)/1000 + "秒");

    }

生成07版本的Excel时间测试

按照03版本的生成数据页体量数据写入方式生成07版本的Excel文件。

image-20230708225714925

image-20230708225740256

生成07版本的Excel相较与03版本,相同数据体量的情况下。时间明显长于03版本的生成,因为在使用XSSFWorkbook,07版本的Excel会在sheet页中存在百万行单元格,但是文件的生成是通过解析数据到磁盘中生成临时文件(过程是一个DOM模型),最后将临时文件转化为Excel。该类全量读取数据到内存会可能导致OOM,还有就是在数据还没有读取完之前是不会有临时文件生成,不能生成Excel会导致实际上操作的时候很慢。

生成时间由于太慢了没有结果就先kill进程先进行后续的验证。

image-20230709010332766

代码示例

public static void GenerateExcel07() throws  Exception {
        // 创建工作簿
        Workbook workbook = new XSSFWorkbook();

        // 创建工作表
        Sheet sheet = workbook.createSheet("07版本");
        // 记录开始时间
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 65535; i++) {
            Row row = sheet.createRow(i);
            for (int j = 0; j < 255; j++) {
                Cell cell = row.createCell(j);
                cell.setCellValue("测试数据");
            }
        }
        // 记录结束时间
        long endTime = System.currentTimeMillis();
        // 利用流生成Excel表格
        FileOutputStream fileOutputStream = new FileOutputStream("./07版本生成时间测试.xls");
        workbook.write(fileOutputStream);
        // 关闭流
        fileOutputStream.close();
        System.out.println("07版本Excel生成完成");
        System.out.println("生成消耗时间" + (endTime-startTime)/1000 + "秒");

    }

解决大数据量的写入

image-20230827131457983

官方给我们提供了一个SXSSFWorkbook对象用于生成正对大数据量的生成Excel文件。

image-20230708231102863

大数据量的写是如何解决的?

这一点在官方的文档中有涉及。翻译一下这段文字大致的意思就是正对原先的的HSSFWorkbook的实现方式是一次新读取全部的行数,有一万行那就读取一万行。那么就会很容易引发OOM问题。而SXSSFWorkbook是通过增加一个窗口的方式进行,窗口值要是不手动设置默认就是100,每次也支持读取100行数据到内存,当读取到下一个101行数据的时候,就将最早的也就是最旧的索引值刷新到磁盘的临时文件中。由此来控制内存的使用。完成数据写入之后将临时文件中的数据全部写入到Excel中,最后需要显示调用dispose()。方法来将临时文件删除。

Streaming version of XSSFWorkbook implementing the "BigGridDemo" strategy. This allows to write very large files without running out of memory as only a configurable portion of the rows are kept in memory at any one time. You can provide a template workbook which is used as basis for the written data. See https://poi.apache.org/spreadsheet/how-to.html#sxssf for details. Please note that there are still things that still may consume a large amount of memory based on which features you are using, e.g. merged regions, comments, ... are still only stored in memory and thus may require a lot of memory if used extensively. SXSSFWorkbook defaults to using inline strings instead of a shared strings table. This is very efficient, since no document content needs to be kept in memory, but is also known to produce documents that are incompatible with some clients. With shared strings enabled all unique strings in the document has to be kept in memory. Depending on your document content this could use a lot more resources than with shared strings disabled. Carefully review your memory budget and compatibility needs before deciding whether to enable shared strings or not.

SXSSF (package: org.apache.poi.xssf.streaming) is an API-compatible streaming extension of XSSF to be used when very large spreadsheets have to be produced, and heap space is limited. SXSSF achieves its low memory footprint by limiting access to the rows that are within a sliding window, while XSSF gives access to all rows in the document. Older rows that are no longer in the window become inaccessible, as they are written to the disk.

You can specify the window size at workbook construction time via new SXSSFWorkbook(int windowSize) or you can set it per-sheet via SXSSFSheet#setRandomAccessWindowSize(int windowSize)

When a new row is created via createRow() and the total number of unflushed records would exceed the specified window size, then the row with the lowest index value is flushed and cannot be accessed via getRow() anymore.

The default window size is 100 and defined by SXSSFWorkbook.DEFAULT_WINDOW_SIZE.

A windowSize of -1 indicates unlimited access. In this case all records that have not been flushed by a call to flushRows() are available for random access.

Note that SXSSF allocates temporary files that you must always clean up explicitly, by calling the dispose method.

SXSSFWorkbook defaults to using inline strings instead of a shared strings table. This is very efficient, since no document content needs to be kept in memory, but is also known to produce documents that are incompatible with some clients. With shared strings enabled all unique strings in the document has to be kept in memory. Depending on your document content this could use a lot more resources than with shared strings disabled.

Please note that there are still things that still may consume a large amount of memory based on which features you are using, e.g. merged regions, hyperlinks, comments, ... are still only stored in memory and thus may require a lot of memory if used extensively.

Carefully review your memory budget and compatibility needs before deciding whether to enable shared strings or not.

The example below writes a sheet with a window of 100 rows. When the row count reaches 101, the row with rownum=0 is flushed to disk and removed from memory, when rownum reaches 102 then the row with rownum=1 is flushed, etc.

官网文档的链接:https://poi.apache.org/apidocs/5.0/

image-20230709001216679

代码示例

public static void GenerateBigDataExcel07() throws  Exception {
        // 创建工作簿
        Workbook workbook = new SXSSFWorkbook();

        // 创建工作表
        Sheet sheet = workbook.createSheet("07大数据版本");
        // 记录开始时间
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 65536; i++) {
            Row row = sheet.createRow(i);
            for (int j = 0; j < 255; j++) {
                Cell cell = row.createCell(j);
                cell.setCellValue("测试数据");
            }
        }
        // 记录结束时间
        long endTime = System.currentTimeMillis();
        // 利用流生成Excel表格
        FileOutputStream fileOutputStream = new FileOutputStream("./07大数据版本生成时间测试.xlsx");
        workbook.write(fileOutputStream);
        // 关闭流
        fileOutputStream.close();
        // 清除临时文件
        ((SXSSFWorkbook)workbook).dispose();

        System.out.println("07大数据版本Excel生成完成");
        System.out.println("生成消耗时间" + (endTime-startTime)/1000 + "秒");

    }

读取Excel文件信息

实现读取的代码书写流程类似于生成EXCEL文件,大致上也分为七大步骤

  1. 通过文件流读取工作簿,并且这里不区分版本,一视同仁
  2. 通过文件流获取工作簿,这里需要更具不同的工作簿版本使用不同的类
  3. 获取工作表sheet
  4. 获取行单元格
  5. 获取列单元格
  6. 读取数据
  7. 关闭流

读取03版本Excel数据

效果演示

image-20230709012518719

代码示例

  public static void ReadExcel03() throws Exception {
        // 通过文件流读取工作簿,并且这里不区分版本,一视同仁
        FileInputStream fileInputStream = new FileInputStream("03版本的Excel.xls");

        // 通过文件流获取工作簿,这里需要更具不同的工作簿版本使用不同的类
        Workbook workbook = new HSSFWorkbook(fileInputStream);

        // 获取工作表sheet
        Sheet sheet = workbook.getSheet("03版本");
//        Sheet sheet = workbook.getSheetAt(0);

        // 获取行单元格 获取第一行
        Row row = sheet.getRow(0);

        // 获取列单元格 获取第一行第一个单元格
        Cell cell = row.getCell(0);

        // 读取数据
        System.out.println("cell = " + cell);

        // 关闭流
        fileInputStream.close();
    }

读取Excel07版本的Excel数据

效果演示

image-20230709012832616

代码展示

    public static void ReadExcel07() throws Exception {
        // 通过文件流读取工作簿,并且这里不区分版本,一视同仁
        FileInputStream fileInputStream = new FileInputStream("07版本的Excel.xlsx");

        // 通过文件流获取工作簿,这里需要更具不同的工作簿版本使用不同的类
        Workbook workbook = new XSSFWorkbook(fileInputStream);

        // 获取工作表sheet
        Sheet sheet = workbook.getSheet("07版本");
//        Sheet sheet = workbook.getSheetAt(0);

        // 获取行单元格 获取第一行
        Row row = sheet.getRow(0);

        // 获取列单元格 获取第一行第一个单元格
        Cell cell = row.getCell(0);

        // 读取数据
        System.out.println("cell = " + cell);

        // 关闭流
        fileInputStream.close();
    }

批量读取Excel中的数据

首先我们对原先生成的EXCEL进行一下字段的扩展

image-20230709013457385

简单的批量读取03版本Excel

首先获取表头信息,接着获取表头下的具体内容信息。

效果演示

image-20230709123052724

代码示例

public static void ReadCell03() throws Exception {
        // 通过文件流读取工作簿,并且这里不区分版本,一视同仁
        FileInputStream fileInputStream = new FileInputStream("03版本的Excel.xls");

        // 通过文件流获取工作簿,这里需要更具不同的工作簿版本使用不同的类
        Workbook workbook = new HSSFWorkbook(fileInputStream);

        // 获取工作表sheet
        Sheet sheet = workbook.getSheet("03版本");
//        Sheet sheet = workbook.getSheetAt(0);

        // 获取行单元格 获取第一行 获取标题行数据
        Row rowTitle = sheet.getRow(0);

        if (rowTitle != null) {
            // 获取标题的单元格数量
            int cellNum = rowTitle.getPhysicalNumberOfCells();
            for (int i = 0; i < cellNum; i++) {
                // 获取所有单元格
                Cell cell = rowTitle.getCell(i);
                if (cell != null) {
                    // 获取单元格数量
                    String value = cell.getStringCellValue();
                    System.out.println(value + "|");
                }
            }
        }

        // 获取内容行数据
        int rowNum = sheet.getPhysicalNumberOfRows();
        // 从第二行开始获取内容行数据
        for (int i = 1; i < rowNum; i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                // 获取当前行一共有多少单元格
                int cellNum = row.getPhysicalNumberOfCells();
                // 获取当前行中单元格的数据
                for (int j = 0; j < cellNum; j++) {
                    Cell cell = row.getCell(j);
                    if (cell != null) {
                        // 获取单元格数据类型
                        CellType cellType = cell.getCellType();
                        // 根据不同数据类型获取数据
                        String cellValue = "";
                        switch (cellType){
                            // 字符串
                            case STRING:
                                cellValue = cell.getStringCellValue();
                                System.out.println(cellValue);
                                System.out.println("字符串类型");
                                break;
                            // 数值类型:包括整数、小数、日期
                            case NUMERIC:
                                // 判断是否为日期类型
                                if (DateUtil.isCellDateFormatted(cell)){
                                    Date date = cell.getDateCellValue();
                                    cellValue = new SimpleDateFormat("yyyy-MM-dd").format(date);
                                    System.out.println(cellValue);
                                    System.out.println("日期类型");
                                }else {
                                    cellValue = cell.toString();
                                    System.out.println(cellValue);
                                    System.out.println("整数或小数类型");
                                }
                                break;
                            // 空白单元格类型
                            case BLANK:
                                System.out.println("空白单元格");
                                break;
                            case BOOLEAN:
                                cellValue = String.valueOf(cell.getBooleanCellValue());
                                System.out.println(cellValue);
                                System.out.println("布尔类型");
                                break;
                            case ERROR:
                                System.out.println("错误类型");
                                break;
                        }
                    }
                }
            }

        }


        // 关闭流
        fileInputStream.close();
    }

简单的批量读取07版本Excel

这里有一个问题就是在使用代码自动导出EXCEL之后设置导出文件的单元格熟悉,原有的单元格熟悉不会因为你修改了单元格熟悉而改变。

效果演示

image-20230709123739478

代码示例

 public static void ReadCell07() throws Exception {
        // 通过文件流读取工作簿,并且这里不区分版本,一视同仁
        FileInputStream fileInputStream = new FileInputStream("07版本的Excel.xlsx");

        // 通过文件流获取工作簿,这里需要更具不同的工作簿版本使用不同的类
        Workbook workbook = new XSSFWorkbook(fileInputStream);

        // 获取工作表sheet
        Sheet sheet = workbook.getSheet("07版本");
//        Sheet sheet = workbook.getSheetAt(0);

        // 获取行单元格 获取第一行 获取标题行数据
        Row rowTitle = sheet.getRow(0);

        if (rowTitle != null) {
            // 获取标题的单元格数量
            int cellNum = rowTitle.getPhysicalNumberOfCells();
            for (int i = 0; i < cellNum; i++) {
                // 获取所有单元格
                Cell cell = rowTitle.getCell(i);
                if (cell != null) {
                    // 获取单元格数量
                    String value = cell.getStringCellValue();
                    System.out.println(value + "|");
                }
            }
        }

        // 获取内容行数据
        int rowNum = sheet.getPhysicalNumberOfRows();
        // 从第二行开始获取内容行数据
        for (int i = 1; i < rowNum; i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                // 获取当前行一共有多少单元格
                int cellNum = row.getPhysicalNumberOfCells();
                // 获取当前行中单元格的数据
                for (int j = 0; j < cellNum; j++) {
                    Cell cell = row.getCell(j);
                    if (cell != null) {
                        // 获取单元格数据类型
                        CellType cellType = cell.getCellType();
                        // 根据不同数据类型获取数据
                        String cellValue = "";
                        switch (cellType){
                            // 字符串
                            case STRING:
                                cellValue = cell.getStringCellValue();
                                System.out.println(cellValue);
                                System.out.println("字符串类型");
                                break;
                            // 数值类型:包括整数、小数、日期
                            case NUMERIC:
                                // 判断是否为日期类型
                                if (DateUtil.isCellDateFormatted(cell)){
                                    Date date = cell.getDateCellValue();
                                    cellValue = new SimpleDateFormat("yyyy-MM-dd").format(date);
                                    System.out.println(cellValue);
                                    System.out.println("日期类型");
                                }else {
                                    cellValue = cell.toString();
                                    System.out.println(cellValue);
                                    System.out.println("整数或小数类型");
                                }
                                break;
                            // 空白单元格类型
                            case BLANK:
                                System.out.println("空白单元格");
                                break;
                            case BOOLEAN:
                                cellValue = String.valueOf(cell.getBooleanCellValue());
                                System.out.println(cellValue);
                                System.out.println("布尔类型");
                                break;
                            case ERROR:
                                System.out.println("错误类型");
                                break;
                        }
                    }
                }
            }

        }


        // 关闭流
        fileInputStream.close();
    }

EasyExcel导出Excel

EasyExcel的简单介绍

EasyExcel的读操作使用

EasyExcel的写操作使用

公司业务中模板要求的具体代码实现

简单样式如何实现

数据权限如何过滤(具体场景下的设计)

如何提高读写速度(使用线程池加多线程试试)

写在最后

谢谢你看到了这里,要是觉得可以扫码支持一下 image-20230708193035366 image-20230708193035366

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

基础导出Excel的样式demo演示 展开 收起
Java
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/shuyixiao-only/export-excel-technology-share.git
git@gitee.com:shuyixiao-only/export-excel-technology-share.git
shuyixiao-only
export-excel-technology-share
导出Excel技术分享
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891