Myexcel入门

Myexcel入门

简介

Myexcel 是一个可以导入、导出和加密 excel 的工具包。

优点

  • 生成任意复杂表格
  • 支持图片导入导出
  • 完全屏蔽POI复杂度:使用HTML作为模板,学习成本几乎为零,无需关心POI本身的任何操作
  • 支持常用的背景色、边框、字体等样式设置详情
  • 支持多种模板引擎:内置FreeMarker、groovy、Beetlthymeleaf等常用模板引擎
  • 低内存导入导出

测试文件,24.3m excel,500000行,8列,循环读取40次,平均内存占用约75兆,对比阿里巴巴easyexcel(v2.1.6)同文件测试,内存占用约三分之一easyexcel。

读取内存占用

注意点

  • MyExcel所有版本均只支持jdk8+
  • 模板文件只能放在classpath下

入门使用示例

依赖添加

<dependency>
   <groupId>com.github.liaochong</groupId>
   <artifactId>myexcel</artifactId>
   <version>3.12.0</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

Excel默认导出

附件导出示例:

    public void defaultBuild(HttpServletResponse response) throws Exception {
        List<ArtCrowd> dataList = this.getDataList();
        // 默认导出默认计算宽度、斑马线背景色
        Workbook workbook = DefaultExcelBuilder.of(ArtCrowd.class).build(dataList);
        // 不使用默认样式
        // Workbook workbook = DefaultExcelBuilder.of(ArtCrowd.class).noStyle().build(dataList);
        // 宽度策略 无自动宽度 NO_AUTO | 自适应宽度 AUTO_WIDTH | 组件调整宽度 COMPUTE_AUTO_WIDTH
        //Workbook workbook = DefaultExcelBuilder.of(ArtCrowd.class).widthStrategy(WidthStrategy.AUTO_WIDTH).build(dataList);
        // 普通导出
        // AttachmentExportUtil.export(workbook, "艺术生信息", response);
        // 加密导出
        AttachmentExportUtil.encryptExport(workbook, "艺术生信息", response,"111");
    }

文件导出示例:

    public void defaultBuild()  {
        List<ArtCrowd> dataList = this.getDataList();
        Workbook workbook = DefaultExcelBuilder.of(ArtCrowd.class).build(dataList);
        // 普通导出
        // FileExportUtil.export(workbook, new File("/User/demo.xlsx"));
        // 加密导出
        FileExportUtil.encryptExport(workbook, new File("/User/demo.xlsx"),"123456");
    }

Excel流式导出

流式导出和默认导出的区别在于,流式导出采用生产者消费者模式,可以批量获取数据,批量写入excel。

使用步骤

  1. 导出配置

    DefaultStreamExcelBuilder<ArtCrowd> streamExcelBuilder = DefaultStreamExcelBuilder
            .of(ArtCrowd.class) 
            .threadPool(Executors.newFixedThreadPool(10))// 线程池 可选
            .capacity(1000)// 设置excel 容量  如果设置,当Excel行数达到容量时,将生成一个新的EXCEL 可选
            .start();
    
  2. 数据添加

    append 参数可以是列表或单个数据

    streamExcelBuilder.asyncAppend(this::getDataList);
    
  3. 构建完成

    Workbook workbook = streamExcelBuilder.build();
    
  4. 导出数据

    附件导出

    AttachmentExportUtil.export(workbook, "艺术生信息1", response);
    

    多文件导出

     List<Path> paths = streamExcelBuilder.buildAsPaths();
    

    Zip文件导出

    Path zip = streamExcelBuilder.buildAsZip("test"); // 设置了capacity
    AttachmentExportUtil.export(zip,"finalName.zip",response); 
    

    image-20221201085859667

Excel动态导出

  1. 动态指定标题和字段顺序

    List<String> titles = new ArrayList<>();
    titles.add("姓名");
    titles.add("年龄");
    
    List<String> order = new ArrayList<>();
    order.add("name");
    order.add("age");
    
    Workbook workbook = DefaultExcelBuilder.of(TestDO.class)
                                        .sheetName("default example")
                                        .titles(titles) // 自定义表头
                                        .fieldDisplayOrder(order) // 自定义顺序
                                        .build(dataList);
    
  2. 字段分组

    该方法基于注解@ExcelColumn的groups属性

    @ExcelColumn(title="姓名",groups={People.class})
    String name;
    
    @ExcelColumn(title="年龄")
    String age;
    
    DefaultExcelBuilder.of(ArtCrowd.class).build(People.class);
    

    上面的例子只会导出“name”字段

  3. map数据导出

Excel模板导出

常用

    public void buildWithDefaultStyle(HttpServletResponse response) {
        Map<String, Object> dataMap = this.getDataMap();
        try (FreemarkerExcelBuilder excelBuilder = new FreemarkerExcelBuilder()){
            Workbook workbook = excelBuilder
                    // fileTemplate(dirPath,fileName)
                    .classpathTemplate("/templates/freemarkerToExcelExample1.ftl")
                    .build(dataMap);
            AttachmentExportUtil.export(workbook, "freemarker_excel", response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

多个table生成在同一个sheet里

    public void buildWithDefaultStyle(HttpServletResponse response) {
        Map<String, Object> dataMap = this.getDataMap();
        try (FreemarkerExcelBuilder excelBuilder = new FreemarkerExcelBuilder()){
            Workbook workbook = excelBuilder
                    .classpathTemplate("/templates/freemarkerToExcelExample1.ftl")
                    .sheetStrategy(SheetStrategy.ONE_SHEET)
                    .build(dataMap);
            AttachmentExportUtil.export(workbook, "freemarker_excel", response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

效果

image-20221201115656691

每个table各生成一个sheet

    public void buildWithDefaultStyle(HttpServletResponse response) {
        Map<String, Object> dataMap = this.getDataMap();
        try (FreemarkerExcelBuilder excelBuilder = new FreemarkerExcelBuilder()){
            Workbook workbook = excelBuilder 
                    .classpathTemplate("/templates/freemarkerToExcelExample1.ftl")
                    .sheetStrategy(SheetStrategy.MULTI_SHEET)
                    .build(dataMap);
            AttachmentExportUtil.export(workbook, "freemarker_excel", response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

效果

image-20221201120017467

sheet1

image-20221201120033582

sheet2

image-20221201120049072

sheet3

image-20221201120104156

支持公式

在td上添加属性:formula,无需设定具体值

<table>
    <tr>
        <td>1</td>
    </tr>
    <tr>
        <td>19</td>
    </tr>
    <tr>
        <td formula>SUM(A1:A2)</td>
    </tr>
</table>

单元格设置

string

<table>
    <tr>
         <td string>199999999999999.0999999234</td>
    </tr>
</table>

double

<table>
    <tr>
        <td double>199999999999999.0999999234</td>
    </tr>
</table>

boolean

<table>
    <tr>
        <td boolean>true</td>
    </tr>
</table>

image-20221201174104228

单元格斜线绘制

斜线样式:SOLID、DOT、DASH、LG_DASH、DASH_DOT、LG_DASH_DOT、LG_DASH_DOT_DOT、SYS_DASH、SYS_DOT、SYS_DASH_DOT、SYS_DASH_DOT_DOT

// 2代表斜线的宽度width #000000 颜色
<td slant="solid 2 #000000">

</td>

image-20221201182218291

添加批注

<td comment-text="批注内容" comment-author="作者"></td>

image-20221201182705455

freemarkerToExcelExample1.ftl

<table>
    <caption>${sheetName}</caption>
    <thead>
    <tr style="background-color: #6495ED">
        <th colspan="3" style="text-align: center;vertical-align: middle;font-weight: bold;font-size: 14px;">产品介绍</th>
    </tr>
    <tr>
        <#list titles as title>
            <th>${title}</th>
        </#list>
    </tr>
    </thead>
    <tbody>
    <#list data as item>
        <tr>
            <td>${item.category}</td>
            <td>${item.name}</td>
            <td>${item.count}</td>
            <td url>百度地址</td>
        </tr>
    </#list>
    </tbody>
</table>
<table>
    <caption>${sheetName}</caption>
    <thead>
    <tr style="background-color: #6495ED">
        <th colspan="3" style="text-align: center;vertical-align: middle;font-weight: bold;font-size: 14px;">产品介绍</th>
    </tr>
    <tr>
        <#list titles as title>
            <th>${title}</th>
        </#list>
    </tr>
    </thead>
    <tbody>
    <#list data1 as item>
        <tr>
            <td style="border-top-style:dotted">${item.category}</td>
            <td style="border-top-style:thick">${item.name}</td>
            <td style="border-top-style:double">${item.count}</td>
            <td url>百度地址</td>
            <td style="border-top-style:hair"></td>
            <td style="border-top-style:medium_dashed"></td>
            <td style="border-top-style:dash_dot"></td>
        </tr>
    </#list>
    </tbody>
</table>
<table>
    <caption>${sheetName}</caption>
    <thead>
    <tr style="background-color: #6495ED">
        <th colspan="3" style="text-align: center;vertical-align: middle;font-weight: bold;font-size: 14px;">产品介绍</th>
    </tr>
    <tr>
        <#list titles as title>
            <th>${title}</th>
        </#list>
    </tr>
    </thead>
    <tbody>
    <#list data2 as item>
        <tr>
            <td style="text-decoration: underline;font-style:italic;border-top-style:thin;font-family: 微软雅黑">${item.category}</td>
            <td style="text-decoration: line-through ;font-family:Times Microsoft YaHei UI;border-top-style:dashed">${item.name}</td>
            <td style="border-top-style:medium">${item.count}</td>
            <td url>百度地址</td>
            <td><a href="http://www.baidu.com">百度</a></td>
            <td><a url="http://www.baidu.com">Baidu</a></td>
            <td style="color:blue"><a href="mailto:poi@apache.org?subject=Hyperlinks">邮件地址</a></td>
            <td dropDownList>男, 女</td>
            <td style="width: 10px;height: 10px">

            </td>
            <td string>19</td>
            <td string slant="solid 2 #000000">199999999999999.0999999234</td>
            <td double>199999999999999.0999999234</td>
            <td boolean>19</td>
        </tr>
    </#list>
    </tbody>
</table>

<table>
    <tr>
        <td>1</td>
    </tr>
    <tr>
        <td>19</td>
    </tr>
    <tr>
        <td formula>SUM(A1:A2)</td>
    </tr>
    <tr>
        <td formula>MAX(A1:A2)</td>
    </tr>
    <tr>
        <td string slant="SOLID 2 #000000">SOLID</td>
    </tr>
    <tr>
        <td string slant="DOT 2 #000000">DOT</td>
    </tr>
    <tr>
        <td string slant="DASH 2 #000000">DASH</td>
    </tr>
    <tr>
        <td string slant="LG_DASH 2 #000000">LG_DASH</td>
    </tr>
    <tr>
        <td string slant="DASH_DOT 2 #000000">DASH_DOT</td>
    </tr>
    <tr>
        <td string slant="LG_DASH_DOT 2 #000000">LG_DASH_DOT</td>
    </tr>
    <tr>
        <td string slant="LG_DASH_DOT_DOT 2 #000000">LG_DASH_DOT_DOT</td>
    </tr>
    <tr>
        <td string slant="SYS_DASH 2 #000000">SYS_DASH</td>
    </tr>
    <tr>
        <td string slant="SYS_DOT 2 #000000">SYS_DOT</td>
    </tr>
    <tr>
        <td string slant="SYS_DASH_DOT 2 #000000">SYS_DASH_DOT</td>
    </tr>
    <tr>
        <td string slant="SYS_DASH_DOT_DOT 2 #000000" comment-text="批注内容" comment-author="作者">SYS_DASH_DOT_DOT</td>
    </tr>
</table>

CSV导出

    public void csv(HttpServletResponse response) {
        Csv csv = CsvBuilder.of(ArtCrowd.class)
                .build(getDataList());
        AttachmentExportUtil.export(csv.getFilePath(), "123.csv", response);
    }

自定义样式

标题(title)样式自定义

@ExcelColumn(style={"title->color:red","cell->color:green"})
Integer age;

内容行样式自定义

@ExcelColumn(style="cell->color:green")
Integer age;

方法调用设定样式

DefaultExcelBuilder.of(ArtCrowd.class)
                   .style("title->color:red","background-color:green;")
                   .build(dataList);

使用 -> 分隔符:

  • title标明该样式针对标题;
  • cell标明该样式针对内容行;
  • odd标明该样式针对奇数内容行;
  • even标明该样式针对偶数内容行;

模板设定样式

        <tr>
            <td style="text-decoration: underline;font-style:italic;border-top-style:thin;font-family: 微软雅黑">${item.category}</td>
            <td style="text-decoration: line-through ;font-family:Times Microsoft YaHei UI;border-top-style:dashed" >${item.name}</td>
            <td style="border-top-style:medium">${item.count}</td>
            <td url>百度地址</td>
        </tr>

常用样式

width

CSS Value Example
width such as 15px style="width: 15px"

height

CSS Value Example
height such as 15px, special attention A kind of If the template is used, the style can only be placed on tr style="height: 15px"

background

CSS Value Example
background-color Hex: ffffff, RGB: rgb (0255255), common background color name: green, Hex is recommended style="background-color:#ABFF00"

border

CSS Value Example
border-style thin、dashed、medium、dotted、thick、double、hair、medium_dashed、dash_dot style="border-style:thin"
border-top-style thin、dashed、medium、dotted、thick、double、hair、medium_dashed、dash_dot style="border-top-style:thin"
border-right-style thin、dashed、medium、dotted、thick、double、hair、medium_dashed、dash_dot style="border-top-style:thin"
border-bottom-style thin、dashed、medium、dotted、thick、double、hair、medium_dashed、dash_dot style="border-top-style:thin"
border-left-style thin、dashed、medium、dotted、thick、double、hair、medium_dashed、dash_dot style="border-top-style:thin"

font

CSS Value Example
color green style="color:green;"
font-size value: 14px (only the value will be intercepted, and the non value part will be deleted) style="font-size:14px"
font-family Times New Roman(alternative fonts are not supported) style="font-family:Times New Roman"
font-style italic style="font-style:italic"
font-weight bold style="font-weight:bold"
text-decoration line-through、underline style="text-decoration: underline"

多级表头

多级表头,针对的是DefaultExcelBuilder、DefaultStreamExcelBuilder

@ExcelColumn(title="拓展信息->年龄")
Integer age

默认以->作为分隔符,也可自定义分隔符:@ExcelModel(titleSeparator="#")

@ExcelColumn(title="拓展信息#年龄")
Integer age

单元格换行

DefaultExcelBuilder、DefaultStreamExcelBuilder

@ExcelModel(wrapText=true)
public class Entity(){
}

模板换行使用<br/或者

图片导出

属性定义

@ExcelColumn(fileType = FileType.IMAGE)
File image;

@ExcelColumn(fileType = FileType.IMAGE)
InputStream image;

@ExcelColumn(fileType = FileType.IMAGE)
Path image;

@ExcelColumn(fileType = FileType.IMAGE)
String image="https://img1.baidu.com/it/u=1499001738,37769528&fm=253&fmt=auto&app=120&f=JPEG?w=889&h=500";

@ExcelColumn(fileType = FileType.IMAGE)
String image="/Usr/location/1.jpg";

模板导出

<td>
   <img src="图片路径(绝对路径、Http、base64)"/>
</td>

效果图

image-20221201153039051

下拉列表

该功能仅针对DefaultExcelBuilder、DefaultStreamExcelBuilder

下拉列表是受字数限制的。列表的总字符不能超过 250 个字符

@ExcelColumn(title="下拉列表")
List<String> options;

模板下拉列表

option 1, option 2, option 3 , 英文逗号分隔

<td dropDownList>option 1, option 2, option 3</td>

写入自定义转化

简单映射

该功能仅针对DefaultExcelBuilder、DefaultStreamExcelBuilder。

导出经常遇到的一个场景:导出数据包含可枚举字段,如性别,存储在数据库中以0、1,导出为男、女。

@ExcelColumn(title="性别",mapping="0:男,1:女")
Integer gender;

使用 mapping 属性,以 , 分隔成组,每组以 :分隔,需要注意的是,该属性仅支持简单映射,不支持含有:,,特殊字符的映射

自定义转化

实现CustomWriteConverter<Object, Object>接口

 // 1
@Component
public class DefaultCustomWriteConverter implements CustomWriteConverter<Object, Object> {
    
    @Autowired
    private MyConverter myConverter;
    
    @Override
    public Object convert(Object originalData, CustomWriteContext customWriteContext) {

        if (originalData.equals(0)) {
            return "男";
        }else {
            return "女";
        }

    }
}
//2 使用注解
@ExcelColumn(title = "性别", writeConverter = DefaultCustomWriteConverter.class)
Integer gender;

// 3.如使用了spring等,则需要绑定上下文,如无,则无需使用binding
@Autowired
private DefaultCustomWriteConverter defaultCustomWriteConverter;

DefaultStreamExcelBuilder.of(Stu.class).binding(defaultCustomWriteConverter).start();

添加水印

// 使用水印工具添加水印
WatermarkUtil.addWatermark(workbook,"水印");

image-20221201174902739

posted @ 2022-12-01 08:45  iforeverhz  阅读(1228)  评论(0编辑  收藏  举报