poi-tl的使用(通俗易懂,全面,内含动态表格实现 包会!!)

最近在做项目时候有一个关于解析Html文件,然后将解析的数据转化成word的需求,经过调研,使用poi-tl来实现这个需求,自己学习花费了一些时间,现在将这期间的经验总结起来,让大家可以快速入门

poi-tl的介绍

poi-tl(poi template language)是Word模板引擎,使用模板和数据创建很棒的Word文档

官网地址:中文文档地址

源码地址:https://github.com/Sayi/poi-tl

poi-tl的快速入门

  • 引入依赖
<!--poi-tl-->
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.12.0</version>
</dependency>

文本标签(常用)

用法:{{var}}

支持的数据类型:

  • String :文本

  • TextRenderData :有样式的文本

  • HyperlinkTextRenderData :超链接和锚点文本

  • Object :调用 toString() 方法转化为文本

推荐使用工厂 Texts 构建文本模型。

   //文本标签
    @Test
    public void textTest() throws IOException {
        //解析模板
        XWPFTemplate template = XWPFTemplate.compile("D://hjl//textTemplate.docx");
        //封装模型数据
        HashMap<String, Object> map = new HashMap<>();

        map.put("text1","我是普通文本");
        map.put("text2",Texts.of("我是带有样式的文本").color("000000").bold().create());
        map.put("text3",Texts.of("我是用来处理超链接").link("http://www.baidu.com").create());
        map.put("text4",Texts.of("我是用来处理锚点文本").anchor("anchor11").create());

        //渲染数据
        template.render(map);
        //以文件形式输出
        template.writeAndClose(new FileOutputStream("D://hjl//textTemplate1.docx"));

    }

模板:

 

生成的结果:

图像标签(常用)

用法:图片标签以@开始:{{@var}}

数据模型:

  • String :图片url或者本地路径,默认使用图片自身尺寸

  • ByteArrayPictureRenderData

  • FilePictureRenderData

  • UrlPictureRenderData

推荐使用工厂 Pictures 构建图片模型。

@Test
public void imageTest() throws IOException {
    //解析模板
    XWPFTemplate template = XWPFTemplate.compile("D://hjl//imageTemplate.docx");
    //封装模型数据
    HashMap<String, Object> map = new HashMap<>();

    //处理本地图片,大小默认为图大小(以url路径的形式插入)
    map.put("image1","C:\\Users\\admin\\Desktop\\工作日志\\微信图片_20240407110311.jpg");
    map.put("svg", "https://img.shields.io/badge/jdk-1.6%2B-orange.svg");
    // 设置文件图片大小
    map.put("image2", Pictures.ofLocal("C:\\Users\\admin\\Desktop\\工作日志\\微信图片_20240407110311.jpg").size(120, 120).create());

    // 图片流(以流的方式插入)
    map.put("streamImg", Pictures.ofStream(new FileInputStream("C:\\Users\\admin\\Desktop\\工作日志\\微信图片_20240407110311.jpg"), PictureType.JPEG)
      .size(100, 120).create());

    // 网络图片(注意网络耗时对系统可能的性能影响,根据URL链接加载图片,并根据给定的尺寸进行大小调整,以对象的形式插入)
    map.put("urlImg", Pictures.ofUrl("http://deepoove.com/images/icecream.png")
            .size(100, 100).create());
    // 将生成一个bufferImage,以缓冲图像的的形式写入到模板中
    int width = 200;
    int height = 200;
    // 创建一个BufferedImage实例
    BufferedImage bufferImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    // 获取Graphics2D对象,并在图像上绘制内容
    Graphics2D g2d = bufferImage.createGraphics();
    g2d.setColor(Color.RED); // 设置颜色为红色
    int[] xPoints = {width/2, 0, width}; // 三角形的x坐标
    int[] yPoints = {0, height, height}; // 三角形的y坐标
    g2d.fillPolygon(xPoints, yPoints, 3); // 绘制填充的三角形
    g2d.dispose();
    // java图片,我们可以利用Java生成图表插入到word文档中
    map.put("buffered", Pictures.ofBufferedImage(bufferImage, PictureType.PNG)
            .size(100, 100).create());

    //渲染数据
    template.render(map);
    //以文件形式输出
    template.writeAndClose(new FileOutputStream("D://hjl//imageTemplate1.docx"));
}

模板:

渲染后的word:

 

表格标签(常用)

用法:表格标签以#开始:{{#var}}

数据模型:

  • TableRenderData

推荐使用工厂 Tables 、 Rows 和 Cells 构建表格模型。

@Test
public void tableTest() throws IOException {
    //解析模板
    XWPFTemplate template = XWPFTemplate.compile("D://hjl//tableTemplate.docx");
    //封装模型数据
    HashMap<String, Object> map = new HashMap<>();

    //1  一个2行2列的表格
    map.put("table0", Tables.of(new String[][] {
            new String[] { "00", "01" },
            new String[] { "10", "11" }
    }).border(BorderStyle.DEFAULT).create());
    //2  第0行居中且背景为蓝色的表格
    RowRenderData row0 = Rows.of("姓名", "学历").textColor("FFFFFF")
            .bgColor("4472C4").center().create();
    //第一行默认形式
    ArrayList<String> strings = new ArrayList<>();
    strings.add("李四");
    strings.add("博士");
    RowRenderData row1 = Rows.create("李四", "博士");
    map.put("table1", Tables.create(row0, row1));
    //3  合并第1行所有单元格的表格
    RowRenderData row00 = Rows.of("列0", "列1", "列2").center().bgColor("4472C4").create();
    RowRenderData row11 = Rows.create("没有数据", null, null);
    //规定合并单元格规则
    MergeCellRule rule = MergeCellRule.builder().map(MergeCellRule.Grid.of(1, 0), MergeCellRule.Grid.of(1, 2)).build();
    map.put("table2", Tables.of(row00, row11).mergeRule(rule).create());
    
    //渲染数据
    template.render(map);
    //以文件形式输出
    template.writeAndClose(new FileOutputStream("D://hjl//tableTemplate1.docx"));
}

 模板:

渲染结果:

 

 列表

用法:列表标签以*开始:{{*var}}

数据模型:

  • List<String>

  • NumberingRenderData

推荐使用工厂 Numberings 构建列表模型。

 

 

@Test
public void listTest() throws IOException {
    //解析模板
    XWPFTemplate template = XWPFTemplate.compile("D://hjl//listTemplate.docx");
    //封装模型数据
    HashMap<String, Object> map = new HashMap<>();
    ArrayList<String> strings = new ArrayList<>();
    strings.add("text1");
    strings.add("text2");
    strings.add("text3");
    map.put("list1",strings);
    //列表样式
    //DECIMAL //1. 2. 3.
    //DECIMAL_PARENTHESES //1) 2) 3)
    //BULLET //● ● ●
    //LOWER_LETTER //a. b. c.
    //LOWER_ROMAN //i ⅱ ⅲ
    //UPPER_LETTER //A. B. C.
    map.put("list2", Numberings.of(NumberingFormat.DECIMAL).addItem("text1").addItem("text2").create());

    //渲染数据
    template.render(map);
    //以文件形式输出
    template.writeAndClose(new FileOutputStream("D://hjl//listTemplate1.docx"));
}

模板:

 

结果:

这是word识别有点问题 

 

区块对

用法:区块对由前后两个标签组成,

开始标签以?标识,结束标签以/标识:{{?sections}}{{/sections}}

  • 区块对在处理一系列文档元素的时候非常有用,位于区块对中的文档元素可以被渲染零次,一次或N次,这取决于区块对的取值。
  • False或空集合

        隐藏区块中的所有文档元素

  • 非False且不是集合

        显示区块中的文档元素,渲染一次

  • 非空集合

        根据集合的大小,循环渲染区块中的文档元素

简单总结:对于False或空集合,就是不会显示区块对中的数据;对于非False且不是集合,只渲染一次区块对中的模板;对于集合,会根据集合大小,多次渲染

@Test
public void sectionTest() throws IOException {
    //解析模板
    XWPFTemplate template = XWPFTemplate.compile("D://hjl//sectionTemplate.docx");
    //封装模型数据
    HashMap<String, Object> map = new HashMap<>();

    //当数据为false,null,集合大小为0时,区块对的内容不展示
    map.put("section1",false);
    map.put("section2",null);
    map.put("section3",new ArrayList());

    map.put("section4",true);
    String name = "jack";
    map.put("section5",name);
    ArrayList<String> strings = new ArrayList<>();
    strings.add("a");
    strings.add("b");
    strings.add("c");
    strings.add("d");
    HashMap<String, Object> stringObjectHashMap = new HashMap<>();
    stringObjectHashMap.put("value",strings);
    map.put("section6",stringObjectHashMap);

    //渲染数据
    template.render(map);
    //以文件形式输出
    template.writeAndClose(new FileOutputStream("D://hjl//sectionTemplate1.docx"));
}

模板:

渲染结果

 

嵌套

用法:嵌套又称为导入、包含或者合并,以+标识:{{+var}}

数据模型:

  • DocxRenderData

推荐使用工厂 Includes 构建嵌套模型。

实现:

@Test
public void includeTest() throws IOException {
    //解析模板
    XWPFTemplate template = XWPFTemplate.compile("D://hjl//includeTemplate.docx");
    //封装模型数据
    HashMap<String, Object> map = new HashMap<>();

    map.put("mainContent","我是主模板的数据1111");
    //子模版数据
    HashMap<String, Object> subMap = new HashMap<>();
    subMap.put("name","jack");
    subMap.put("age","18");

    map.put("nested", Includes.ofLocal("D://hjl//sub.docx").setRenderModel(subMap).create());

    //渲染数据
    template.render(map);
    //以文件形式输出
    template.writeAndClose(new FileOutputStream("D://hjl//includeTemplate1.docx"));
}

 

主 模板:

子模版:

结果:

复杂图表

用法:需要事先在模板中加入图标的结构,然后修改可选问题,这样就会替换数据

//使用工厂 Charts 构建图表模型
@Test
public void ChartsTest() throws IOException {
    //图表渲染出来后,后面具体的样式可以在图标中调整
    //解析模板
    XWPFTemplate template = XWPFTemplate.compile("D://hjl//ChartsTemplate.docx");
    //封装模型数据
    HashMap<String, Object> map = new HashMap<>();

    //引用图片
    // 设置文件图片大小
    map.put("image", Pictures.ofLocal("C:\\Users\\admin\\Desktop\\工作日志\\微信图片_20240407110311.jpg").size(120, 120).create());


    //多系列图表条形图(3D条形图)、柱形图(3D柱形图)、面积图(3D面积图)、折线图(3D折线图)、雷达图、散点图等
    //柱形图
    ChartMultiSeriesRenderData chart = Charts
            .ofMultiSeries("医院综合排名", new String[] { "齐鲁医院","泰山医院","第二人民医院","第三医院"})
            .addSeries("数据质量排名", new Double[] { 70.5,40.6,22.7,85.4})
            .addSeries("价格质量排名", new Double[] { 80.5,75.6,72.7,85.4})
            .create();
    map.put("barChart", chart);
    //折线图
    ChartMultiSeriesRenderData qst = Charts
            .ofMultiSeries("任务趋势", new String[] { "06-10","06-11","06-12","06-13","06-14","06-15"})
            .addSeries("微信端", new Double[] { 70.5,40.6,22.7,85.4,700.0,40.8})
            .addSeries("PC端", new Double[] { 80.5,50.6,62.7,45.4,200.0,140.8})
            .addSeries("小程序端", new Double[] { 120.5,520.6,362.7,405.4,300.0,340.8})
            .create();
    map.put("qst", qst);


    //单系列图表指的是饼图(3D饼图)、圆环图等
    //饼图
    ChartSingleSeriesRenderData pie = Charts
            .ofSingleSeries("国家GDP对比", new String[] { "美国", "中国","日本","韩国" })
            .series("经济占比", new Integer[] { 50, 35,10,5 })
            .create();
    map.put("pieChart", pie);

    //组合图表指的是由多系列图表(柱形图、折线图、面积图)组合而成的图表。
    ChartMultiSeriesRenderData comb = Charts
            .ofComboSeries("MyChart", new String[] { "中文", "English" })
            .addBarSeries("countries", new Double[] { 15.0, 6.0 })
            .addBarSeries("speakers", new Double[] { 223.0, 119.0 })
            .addLineSeries("youngs", new Double[] { 323.0, 89.0 })
            .addLineSeries("NewLine", new Double[] { 123.0, 59.0 }).create();
    map.put("combChart", comb);

    //柱状图、折线图共存
    ChartMultiSeriesRenderData hntb = Charts
            .ofComboSeries("某省社会排名", new String[] { "城市1","城市2","城市3","城市4","城市5","城市6"})
            .addBarSeries("GDP",new Double[] {70.5,40.6,22.7,85.4,700.0,40.8})
            .addBarSeries("人口",new Double[] {80.5,50.6,62.7,45.4,200.0,140.8})
            .addLineSeries("指数",new Double[] {0.6,0.3,0.7,0.4,0.1,0.8})
            .create();
    map.put("hntb", hntb);
    
    //渲染数据
    template.render(map);
    //以文件形式输出
    template.writeAndClose(new FileOutputStream("D://hjl//ChartsTemplate1.docx"));

}

模板:

结果:

 

到这里,poi-tl基本的用法都差不多介绍完了,还有一些没将的可以看官网的文档,里面有更多的细节

 

动态表格的实现

第一步:写一个类去继承    DynamicTableRenderPolicy  这个类,重写里面的render方法

render()的主要步骤:

  • 获取数据
  • 插入表格
  • 合并表格
public class DynamicTableProxy extends DynamicTableRenderPolicy {

    //渲染策略制定
    @Override
    public void render(XWPFTable xwpfTable, Object tableData) throws Exception {
        //判断数据是否存在
        if (null == tableData) {
            return;
        }
        // 类型转化
        ServerTableData serverTableData = (ServerTableData) tableData;
        List<RowRenderData> serverDataList = serverTableData.getServerDataList();

        if(serverDataList.size()>0){
            // 1 先删除一行, demo中第一行是为了调整 三线表 样式(也是一个空行)
            xwpfTable.removeRow(1);
            //2 向表格中渲染数据
            // 行从中间插入, 因此采用倒序渲染数据
            for (int i = serverDataList.size() - 1; i >= 0; i--) {
                XWPFTableRow newRow = xwpfTable.insertNewTableRow(1);
                newRow.setHeight(400);
                for (int j = 0; j < 4; j++) {
                    newRow.createCell();
                }
                // 渲染一行数据
                TableRenderPolicy.Helper.renderRow(newRow, serverDataList.get(i));
            }
            //3 合并表格
            TableTools.mergeCellsVertically(xwpfTable, 0, 1, 2);
            TableTools.mergeCellsVertically(xwpfTable, 0, 3, 4);

        }
    }


}

第二步:封装数据

private ServerTableData getServerTableData() {
    ServerTableData serverTableData = new ServerTableData();
    List<RowRenderData> serverDataList = new ArrayList<>();
    for (int j = 0; j < 4; j++) {
        String value;
        RowRenderData serverData;
        //前二行
        if (j > 1) {
            value = "索隆";
            serverData = Rows.of(value, "喝酒", "三千世界", "无").center().create();
        }else {
            value = "路飞";
            serverData = Rows.of(value, "大鸡腿", "巨人手枪", "橡胶果实").center().create();
        }
        serverDataList.add(serverData);
    }
    
    List<Map<String, Object>> groupDataList = new ArrayList<>();
    Map<String, Object> groupData1 = new HashMap<>();
    groupData1.put("typeName", "索隆");
    groupData1.put("listSize", "2");

    Map<String, Object> groupData2 = new HashMap<>();
    groupData2.put("typeName", "路飞");
    groupData2.put("listSize", "2");

    groupDataList.add(groupData1);
    groupDataList.add(groupData2);

    serverTableData.setServerDataList(serverDataList);
    serverTableData.setGroupDataList(groupDataList);
    serverTableData.setMergeColumn(0);
    return serverTableData;
}

 

第三步:绑定策略

注意:这里绑定的oneTable是写在表格中的

@Test
void contextLoads() throws IOException {
    // 获取模板文件流
    InputStream resourceAsStream = new FileInputStream("D://template.docx");
    //poi-tl 配置
    ConfigureBuilder builder = Configure.builder();
    builder.useSpringEL(false);
    Map<String,Object> map = new HashMap<>();

    // 伪造一个表格数据
    //(生成表格数据)
    ServerTableData oneTable = getServerTableData();
    //单个表格
    map.put("oneTable",oneTable);
    builder.bind("oneTable",new DynamicTableProxy());

    //输出文件
    XWPFTemplate template = XWPFTemplate.compile(Objects.requireNonNull(resourceAsStream), builder.build()).render(map);
    template.writeAndClose(new FileOutputStream("D://out.docx"));

}

 

 

@Data
public class ServerTableData {

    /**
     *  携带表格中真实数据
     */
    private List<RowRenderData> serverDataList;

    /**
     * 携带要分组的信息
     */
    private List<Map<String, Object>> groupDataList;

    /**
     * 需要合并的列,从0开始
     */
    private Integer mergeColumn;

}

 

 模板:

结果

 

 

综合案例:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/543186.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux应用 select编程

1、概念 1.1 多路复用 在Linux中&#xff0c;多路复用是一种机制&#xff0c;用于同时监视多个文件描述符的状态&#xff0c;以便在其中任何一个文件描述符准备好进行读写操作时立即通知进程。常见的多路复用机制包括 select、poll 和 epoll。 1.2 select select 是一种用于…

【aws】在DBeaver上用终端节点连接Redshift

碎碎念 最近想要尝试redshift的一个叫做重新定位的功能&#xff0c;重新定位触发之后会停止当前的集群&#xff0c;转而在同一个区域的另一个可用区中启动一个一样的集群&#xff0c;这个过程视情况会花上10到60分钟不等。 但是目前项目中连接到redshift用的是私有ip&#xf…

C# Window form 自定义控件的结构和设计(三)

C# Window form 自定义控件的结构和设计(三) 一、前面介绍了如何来创建第一个自定义的控件&#xff0c;以及一个测试程序。下面我们来看下如何在自定义控件中添加属性。 C#和其他.NET语言支持属性作为语言的第一类成员。把属性作为语言的基础属性有两点主要的有点&#xff1a…

foreach无法修改数组值解决方案

效果展示&#xff1a; 解决办法&#xff1a; this.sportList.forEach((item,index) >{let that this;if(item.idinfo.id) {that.sportList[index].sportTime e.detail.value} }) 这里小编解释下&#xff0c;将this赋值给that通常是为了在回调函数或者异步代码中保持对Vu…

Android安卓开发 - 开发基础(二)

App的工程结构 本节介绍App工程的基本结构及其常用配置&#xff0c;首先描述项目和模块的区别&#xff0c;以及工程内部各目录与配置 文件的用途说明&#xff1b;其次阐述两种级别的编译配置文件build.gradle…

吴恩达2022机器学习专项课程(一) 第二周课程实验:特征工程和多项式回归(Lab_04)

目标 探索特征工程和多项式回归&#xff0c;使用线性回归来拟合非常复杂甚至非线性的函数。 1.为什么线性回归能拟合非线性函数&#xff1f; fxw*xb&#xff0c;属于线性回归的扩展&#xff0c;这个公式在数学中不属于线性&#xff0c;因为有x&#xff0c;而在机器学习中属于…

接口的三个常见使用案例

下面的三个案例&#xff0c;都是需要实现接口&#xff0c;才能进行的操作。 目录 1.比较对象大小 2.给对象排序 3.深浅拷贝 1.比较对象大小 1.1引入 &#xff08;1&#xff09;普通类型比较 &#xff08;2&#xff09;引入类型比较 发现报错&#xff0c;因为在Java中&…

如何理解Vue 3组件的component关键字

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

新质生产力与智能制造:推动制造业转型升级的双引擎

引言 随着科技的不断进步和全球制造业的快速发展&#xff0c;新质生产力与智能制造成为推动制造业转型升级的关键驱动力。新质生产力强调的是以科技创新和制度创新为核心&#xff0c;通过提高生产效率和经济效益来推动经济发展。而智能制造则是利用现代信息技术&#xff0c;实现…

window2012等显示桌面上面的【我的电脑】图标

服务器版本&#xff0c;登录进去&#xff0c;就留个垃圾桶在桌面上&#xff0c;一点也没有用处。 如何显示经典的“我的电脑”呢。 网络介绍了几种方法都木用。这种还点用&#xff1a; win图标点右键》运行&#xff1a; rundll32.exe shell32.dll,Control_RunDLL desk.cpl,…

【系统分析师】计算机网络

文章目录 1、TCP/IP协议族1.1 DHCP协议1.2 DNS协议1.3网络故障诊断 2、网路规划与设计2.1逻辑网络设计2.2物理网络设计2.3 分层设计 3、网络接入3.1 接入方式3.2 IPv6地址 4、综合布线技术5、物联网5.1物联网概念与分层5.2 物联网关键技术 6、云计算7、网络存储技术&#xff08…

使用odbc链接dm8数据库

一、环境说明 windows11 VMware Workstation 17 Pro ubuntu22.04 docker $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.3 LTS Release: 22.04 Codename: jammy因docker版本的dm8中&#xff0c;没有…

【每日刷题】代码随想录-动规32

1. 代码随想录-动规32.LC121买卖股票的最佳时机 题目链接 不用动规。双指针法。快指针遍历&#xff0c;慢指针指向最小的。 max维护最大差值。 min第一天价格&#xff0c;如果碰到有比min低的&#xff0c;则更新min。 代码 public int maxProfit(int[] prices) {int min pr…

国内开通gpt会员方法

ChatGPT镜像 今天在知乎看到一个问题&#xff1a;“平民不参与内测的话没有账号还有机会使用ChatGPT吗&#xff1f;” 从去年GPT大火到现在&#xff0c;关于GPT的消息铺天盖地&#xff0c;真要有心想要去用&#xff0c;途径很多&#xff0c;别的不说&#xff0c;国内GPT的镜像…

【WinForm】如何在自己的程序窗口中显示并调用外部桌面程序

当你爱上一个程序的功能&#xff0c;并且希望扩展它以满足自己的需求时&#xff0c;你可能会觉得困惑。毕竟&#xff0c;你已经为此付出了很多努力&#xff0c;并希望能够有效地整合这些功能。那么&#xff0c;是否可以将这些功能嵌套到自己的程序中呢&#xff1f; 首先&#…

三年了,期待下一个三年

第一个三年 时间好快&#xff0c;距离我发布我第一篇文章都已经三个年头了。 转眼也从大一新生变成了大四打工人。 在平台上发布博客&#xff0c;分享自己的项目、学习思路、解决的bug都带给我很多收获。 平台上的粉丝&#xff0c;阅读量等&#xff0c;也让我的简历更加出彩。…

数据结构初阶:二叉树(二)

二叉树链式结构的实现 前置说明 在学习二叉树的基本操作前&#xff0c;需先要创建一棵二叉树&#xff0c;然后才能学习其相关的基本操作。由于现在对二叉树结构掌握还不够深入&#xff0c;为了降低学习成本&#xff0c;此处手动快速创建一棵简单的二叉树&#xff0c;快速进入二…

【MATLAB应用】去噪算法

01.引言 图像的产生是电子和光学相互作用的结果&#xff0c;而图像中的噪声则是由于成像过程中的颗粒性质而客观存在的。不同类型的噪声从不同的视角产生&#xff0c;各自具有特点。因此&#xff0c;有效地去除图像中的噪声以获得更高质量的图像具有实际意义。目前存在多种图像…

IPD集成产品开发

时间&#xff1a;2024年04月14日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 微信&#xff1a;wei_wei10 解密IPD集成产品开发_小蒋聊技术_免费在线阅读收听下载 - 喜马拉雅欢迎收听小蒋聊技术的类最新章节声音“解密IPD集成产品开发”。大家好&#xff…

MAT工具详解

简介 Java自带的JVisualVm可以用来分析Java堆内存&#xff0c;可以用来排查内存泄漏和内存浪费的问题&#xff0c;但是功能不是特别强大&#xff0c; MAT&#xff08;Memory Aanlysis Tool&#xff09;是一款更优的工具。 MAT功能 功能组 全局信息 直方图 按照类的数量倒序…