Java输出PPT文件(二) - 占位符数据替换

2023-11-01

Java输出PPT文件(二) - 占位符数据替换

0. 前言

Java输出PPT文件(一) - 合并PPT

1. 依赖

<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-full -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-full</artifactId>
    <version>5.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>ooxml-schemas</artifactId>
    <version>1.4</version>
</dependency>

注意:poi-ooxml、poi-ooxml-full目前最高版本是5.2.3,但需要Apache的commons-io也为高版本,所以这里使用了5.0.0,想试用5.2.3的朋友先解决下依赖问题,笔者遇到的报错如下:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/io/output/UnsynchronizedByteArrayOutputStream

2. 代码

PowerPoint工具测试类:

import org.apache.poi.xslf.usermodel.*;
import org.springframework.util.CollectionUtils;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;

/**
 * Copyright: Horizon
 *
 * @ClassName PowerPointUtilTest
 * @Description PowerPoint工具测试类
 * @Author Nile (QQEmail:576109623)
 * @Date 15:48 2022/11/5
 * @Version 1.0.0
 */
public class PowerPointUtilTest {
    public static void main(String[] args) throws IOException {
        // 文件路径及文件名称
        String rootDir = "src/main/resources/ppt/";
        String[] pptArray = {"Title.pptx", "Foreword.pptx", "Dependency.pptx"};
        // 参数map
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("${date}", "2022年11月13日");
        paramMap.put("${book}", "《马普尔小姐最后的案件》");
        paramMap.put("${thought}", "不想出去");
        paramMap.put("${drink}", "恩施绿茶");
        paramMap.put("${doing}", "写写blog");
        paramMap.put("${rent}", "25");
        paramMap.put("${dining}", "15");
        paramMap.put("${shopping}", "10");
        paramMap.put("${debt}", "49");
        paramMap.put("${saving}", "1");
        // 合并
        mergePPT(rootDir, Arrays.asList(pptArray), paramMap);
    }

    /**
     * 合并PPT
     * @Author Nile (QQEmail:576109623)
     * @Date 22:18 2022/11/13
     * @param rootDir 文件路径
     * @param fileNameList 文件名称列表
     * @param paramMap 参数map
     * @return void
     */
    private static void mergePPT(String rootDir, List<String> fileNameList, Map<String, String> paramMap) throws IOException {
        if (CollectionUtils.isEmpty(fileNameList)) {
            return;
        }
        // 1. 使用第1个PPT作为基础文件
        XMLSlideShow ppt = new XMLSlideShow(new FileInputStream(rootDir + fileNameList.get(0)));
        // PPT通用处理
        pptCommentHandle(ppt, paramMap);
        // 2. 从第2个文件开始遍历,合并
        for (int i = 1; i < fileNameList.size(); i++) {
            FileInputStream inputstream = new FileInputStream(rootDir + fileNameList.get(i));
            XMLSlideShow src = new XMLSlideShow(inputstream);
            // PPT通用处理
            pptCommentHandle(src, paramMap);
            // 遍历每张幻灯片
            for (XSLFSlide srcSlide : src.getSlides()) {
                // 合并
                ppt.createSlide().importContent(srcSlide);
            }
        }
        // 3. 输出
        String resultName = "Result.pptx";
        FileOutputStream out = new FileOutputStream(rootDir + resultName);
        ppt.write(out);
        out.close();
    }

    /**
     * PPT通用处理(文本和表格)
     * @Author Nile (QQEmail:576109623)
     * @Date 23:15 2022/11/13
     * @param pptx PPT
     * @param paramMap 参数map
     * @return void
     */
    private static void pptCommentHandle(XMLSlideShow pptx, Map<String, String> paramMap) {
        PowerPointUtil powerPointUtil = new PowerPointUtil(pptx);
        // 遍历幻灯片
        List<XSLFSlide> slideList = pptx.getSlides();
        for (XSLFSlide slide : slideList) {
            // 1. 替换段落占位符
            // 1.1 获取所有的shape,并解析为文本段落
            List<XSLFShape> shapes = slide.getShapes();
            List<XSLFTextParagraph> paragraphsFromSlide = new ArrayList<>();
            for (XSLFShape shape : shapes) {
                List<XSLFTextParagraph> textParagraphs = powerPointUtil.parseParagraph(shape);
                paragraphsFromSlide.addAll(textParagraphs);
            }
            // 1.2 替换文本段落中的占位符
            for (XSLFTextParagraph paragraph : paragraphsFromSlide) {
                powerPointUtil.replaceTagInParagraph(paragraph, paramMap, -1);
            }
            // 2. 替换表格内占位符
            // 2.1 循环获取到表格的单元格,并获取到文本段落
            List<XSLFTable> allTableFromSlide = powerPointUtil.getAllTableFromSlide(slide);
            for (XSLFTable xslfTableRows : allTableFromSlide) {
                List<XSLFTableRow> rows = xslfTableRows.getRows();
                for (XSLFTableRow row : rows) {
                    for (XSLFTableCell cell : row.getCells()) {
                        List<XSLFTextParagraph> textParagraphs = cell.getTextParagraphs();
                        for (XSLFTextParagraph textParagraph : textParagraphs) {
                            // 2.2 替换文本段落中的占位符
                            powerPointUtil.replaceTagInParagraph(textParagraph, paramMap, -1);
                        }
                    }
                }
            }
        }
    }
}

工具类:

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.sl.usermodel.TextBox;
import org.apache.poi.xslf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Copyright: Horizon
 *
 * @ClassName PowerPointUtil
 * @Description PowerPoint工具类
 * @Author Nile (QQEmail:576109623)
 * @Date 15:23 2022/11/5
 * @Version 1.0.0
 */
@Data
@Slf4j
public class PowerPointUtil {
    /**
     * PPT文件
     */
    private XMLSlideShow pptx;

    public PowerPointUtil(XMLSlideShow pptx) {
        this.pptx = pptx;
    }

    /**
     * 从幻灯片中获取表格列表
     * @Author Nile (QQEmail:576109623)
     * @Date 16:55 2022/11/5
     * @param slide 幻灯片
     * @return 表格列表
     */
    public List<XSLFTable> getAllTableFromSlide(XSLFSlide slide) {
        List<XSLFTable> tables = new ArrayList<>();
        for (XSLFShape shape : slide.getShapes()) {
            if (shape instanceof XSLFTable) {
                tables.add((XSLFTable) shape);
            }
        }
        return tables;
    }

    /**
     * 替换段落内的标签文本
     * @Author Nile (QQEmail:576109623)
     * @Date 16:55 2022/11/5
     * @param paragraph 段落
     * @param paramMap 参数Map
     * @param start 替换位置索引
     * @return void
     */
    public void replaceTagInParagraph(XSLFTextParagraph paragraph, Map<String, String> paramMap, int start) {
        String paraText = paragraph.getText();
        // 正则匹配,循环匹配替换
        String regEx = "\\$\\{.+?\\}";
        Pattern pattern = Pattern.compile(regEx);
        Matcher matcher = pattern.matcher(paraText);
        while (matcher.find()) {
            StringBuilder keyWord = new StringBuilder();
            // 获取占位符起始位置所在run的索引
            int s = getRunIndex(paragraph, "${", start);
            if (s < start) {
                // 重复递归,直接返回
                return;
            }
            // 获取占位符结束位置所在run的索引
            int e = getRunIndex(paragraph, "}", start);
            // 存放标签
            String rs = matcher.group(0);
            // 存放 key
            keyWord.append(rs);
            // 获取标签所在 run 的全部文字
            String text = getRunsT(paragraph, s, e + 1);
            // 如果没在 paramMap,则不做替换
            String v = nullToDefault(paramMap.get(keyWord.toString()), keyWord.toString());
            // 没有找到这个标签所对应的值,那么就直接替换成标签的值(业务需求来着,找不到不替换)
            setText(paragraph.getTextRuns().get(s), text.replace(rs, v));
            // 存在 ${ 和 } 不在同一个CTRegularTextRun内的情况,将其他替换为空字符
            for (int i = s + 1; i < e + 1; i++) {
                setText(paragraph.getTextRuns().get(i), "");
            }
            start = e + 1;
        }
    }

    /**
     * 解析一个shape内的所有段落
     * @Author Nile (QQEmail:576109623)
     * @Date 16:56 2022/11/5
     * @param shape shape
     * @return 文本段落列表
     */
    public List<XSLFTextParagraph> parseParagraph(XSLFShape shape) {
        if (shape instanceof XSLFAutoShape) {
            XSLFAutoShape autoShape = (XSLFAutoShape) shape;
            return autoShape.getTextParagraphs();
        } else if (shape instanceof XSLFTextShape) {
            XSLFTextShape textShape = (XSLFTextShape) shape;
            return textShape.getTextParagraphs();
        } else if (shape instanceof XSLFFreeformShape) {
            XSLFFreeformShape freeformShape = (XSLFFreeformShape) shape;
            return freeformShape.getTextParagraphs();
        } else if (shape instanceof TextBox) {
            TextBox textBox = (TextBox) shape;
            return textBox.getTextParagraphs();
        }
        return new ArrayList<>();
    }

    /**
     * 获取段落下特定索引的textRun的值
     * @Author Nile (QQEmail:576109623)
     * @Date 17:17 2022/11/5
     * @param paragraph 段落
     * @param start 起始位置
     * @param end 终止位置
     * @return run值
     */
    private String getRunsT(XSLFTextParagraph paragraph, int start, int end) {
        List<XSLFTextRun> textRuns = paragraph.getTextRuns();
        StringBuilder t = new StringBuilder();
        for (int i = start; i < end; i++) {
            t.append(textRuns.get(i).getRawText());
        }
        return t.toString();
    }

    /**
     * 设置run的值
     * @Author Nile (QQEmail:576109623)
     * @Date 17:18 2022/11/5
     * @param run run
     * @param t run值
     * @return void
     */
    private void setText(XSLFTextRun run, String t) {
        run.setText(t);
    }

    /**
     * 获取word在段落中出现第一次的run的索引
     * @Author Nile (QQEmail:576109623)
     * @Date 17:19 2022/11/5
     * @param paragraph 段落
     * @param word 目标值
     * @param start 索引
     * @return void
     */
    private int getRunIndex(XSLFTextParagraph paragraph, String word, int start) {
        List<CTRegularTextRun> rList = paragraph.getXmlObject().getRList();
        for (int i = (Math.max(start, 0)); i < rList.size(); i++) {
            String text = rList.get(i).getT();
            if (text.contains(word)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * toString方法,空则返回默认值
     * @Author Nile (QQEmail:576109623)
     * @Date 17:20 2022/11/5
     * @param o 对象
     * @param defaultStr 默认值
     * @return toString
     */
    private String nullToDefault(Object o, String defaultStr) {
        if (ObjectUtils.isEmpty(o)) {
            return defaultStr;
        }
        return o.toString();
    }
}

3. 测试

3.1 模板准备

占位符替换测试,测试文字和表格

占位符

3.2 替换结果

占位符替换结果

4. 一点分析

debug,做下简单分析。

4.1 parseParagraph

pptCommentHandle方法:

// 1. 替换段落占位符
// 1.1 获取所有的shape,并解析为文本段落
List<XSLFShape> shapes = slide.getShapes();
List<XSLFTextParagraph> paragraphsFromSlide = new ArrayList<>();
for (XSLFShape shape : shapes) {
    List<XSLFTextParagraph> textParagraphs = powerPointUtil.parseParagraph(shape);
    paragraphsFromSlide.addAll(textParagraphs);
}
// 1.2 替换文本段落中的占位符
for (XSLFTextParagraph paragraph : paragraphsFromSlide) {
    powerPointUtil.replaceTagInParagraph(paragraph, paramMap, -1);
}

debug查看paragraphsFromSlide

paragraphsFromSlide
可以看到,通过PowerPointUtil.parseParagraph方法解析幻灯片,可以获取到所有的文本段落,然后逐段解析处理。

4.2 getRunIndex

PowerPointUtil.replaceTagInParagraph方法,正则匹配成功后,会进入处理逻辑。

这里先说明下getRunIndex方法:

private int getRunIndex(XSLFTextParagraph paragraph, String word, int start) {
    List<CTRegularTextRun> rList = paragraph.getXmlObject().getRList();
    // debug查看rList不方便截图,for循环打印输出
    for (int i = 0; i < rList.size(); i++) {
        String text = rList.get(i).getT();
        System.out.println(text);
    }
    for (int i = (Math.max(start, 0)); i < rList.size(); i++) {
        String text = rList.get(i).getT();
        if (text.contains(word)) {
            return i;
        }
    }
    return -1;
}

输出结果

今天是
${date}
,
${book}
快看完了,
${thought}
,冲了一杯
${drink}
,
${doing}
  1. XSLFTextParagraph.getXmlObject方法,这个名字起得好,见名知意。其实PPT文件底层可以理解为是一个xml文件,即Mark Language,使用xml对内容进行标记(内容、文字大小、样式、动画等等),PowerPoint软件的工作就是解析xml文件后展示给我们看。

    简单做法就是将一个PPT文件的后缀名改为.zip,然后再解压查看,目录如下:
    在这里插入图片描述
    (因此笔者认为遇到的所有问题肯定都是可以解决的,包括上一篇文章合并后母版和版式变为空白的问题,关键就是要去研究底层的xml文件喽,然后找到对应的标记内容)

  2. 一句输入的语句被解析成了不同的小段语句,如上面这个例子是11个CTRegularTextRun。(但这也埋下了一个坑,看4.3)

4.3 replaceTagInParagraph

将占位符替换为目标值

public void replaceTagInParagraph(XSLFTextParagraph paragraph, Map<String, String> paramMap, int start) {
    String paraText = paragraph.getText();
    // 正则匹配,循环匹配替换
    String regEx = "\\$\\{.+?\\}";
    Pattern pattern = Pattern.compile(regEx);
    Matcher matcher = pattern.matcher(paraText);
    while (matcher.find()) {
        StringBuilder keyWord = new StringBuilder();
        // 获取占位符起始位置所在run的索引
        int s = getRunIndex(paragraph, "${", start);
        if (s < start) {
            // 重复递归,直接返回
            return;
        }
        // 获取占位符结束位置所在run的索引
        int e = getRunIndex(paragraph, "}", start);
        // 存放标签
        String rs = matcher.group(0);
        // 存放 key
        keyWord.append(rs);
        // 获取标签所在 run 的全部文字
        String text = getRunsT(paragraph, s, e + 1);
        // 如果没在 paramMap,则不做替换
        String v = nullToDefault(paramMap.get(keyWord.toString()), keyWord.toString());
        // 没有找到这个标签所对应的值,那么就直接替换成标签的值(业务需求来着,找不到不替换)
        setText(paragraph.getTextRuns().get(s), text.replace(rs, v));
        // 存在 ${ 和 } 不在同一个CTRegularTextRunt内的情况,将其他替换为空字符
        for (int i = s + 1; i < e + 1; i++) {
            setText(paragraph.getTextRuns().get(i), "");
        }
        start = e + 1;
    }
}

通过getRunIndex方法来找到 ${} 所在rList的位置,来确定需要替换的区间,然后替换为目标值即可。以${date}为例,起始位置s和结束位置e都是1,所以将索引为1的textRun替换为目标值2022年11月13日

这里笔者在开发的时候遇到了一个特别现象,就是 ${}不在同一个CTRegularTextRun里面。也就是打印结果是类似这样的:

今天是
${da
te}

因此补充了这段逻辑:

// 存在 ${ 和 } 不在同一个CTRegularTextRun内的情况,将其他替换为空字符
for (int i = s + 1; i < e + 1; i++) {
    setText(paragraph.getTextRuns().get(i), "");
}

然而笔者开发的时候还担心 ${ 不在同一个CTRegularTextRun内的情况

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java输出PPT文件(二) - 占位符数据替换 的相关文章

  • 何时/为何使用/定义接口[重复]

    这个问题在这里已经有答案了 可能的重复 何时最好使用 java 中的接口 https stackoverflow com questions 2586389 when best to use an interface in java Hi
  • Javadoc 1.5 和 1.6 中缺少 enum.valueOf(String name)

    这可能是一个愚蠢的问题 但我正在使用该方法enum valueOf String name 那里没问题 只是当我检查 javadoc 以了解有关此方法的更多信息时 我找不到它 有javadoc用于valueOf Class
  • 静态方法的 Java 内存模型

    我来自操作系统和 C 语言背景 在代码编译时 世界很简单 需要处理和理解堆栈 堆文本部分等 当我开始学习 Java 时 我确实了解 JVM 和垃圾收集器 我对静态方法感到很有趣 根据我的理解 类的所有实例都会在堆中创建 然后被清理 但是 对
  • 如何识别 Java 中的不可变对象

    在我的代码中 我正在创建一个对象集合 这些对象将由各种线程以只有在对象不可变的情况下才安全的方式访问 当尝试将新对象插入到我的集合中时 我想测试它是否是不可变的 如果不是 我将抛出异常 我能做的一件事是检查一些众所周知的不可变类型 priv
  • firebase推送通知错误Spring Boot服务器端

    我正在尝试从 Spring Boot 服务器端发送通知到客户端 android 服务器运行良好 一切都很好 2020 09 01 08 13 07 691 INFO 18941 restartedMain e DevToolsPropert
  • RSA SignatureException:签名长度不正确

    我在签署 rsa 签名时遇到问题 我有一个用私钥加密的签名 然而 当我尝试使用公钥验证它时遇到问题 我得到以下异常 java security SignatureException Signature length not correct
  • 哈希码是否用于加速集合中的对象查找?

    IIUC 相同类型的两个不同对象可以存储在 HashSet 中 即使两个对象在以下情况下返回相同的值 hashCode 叫做 例如根据本文 https eclipsesource com blogs 2012 09 04 the 3 thi
  • 正确使用 JDBC 连接池 (Glassfish)

    我需要在 Java Web 服务中作为会话 bean 实现数据库连接 但我不确定我这样做是否正确 我创建了一个类 public final class SQLUtils private static DataSource m ds null
  • 用 java 编写解释器时的 switch 或 if 语句

    当前的作业需要我编写一个程序 以一种非常微小且基本的编程语言 行为有点像 FORTRAN 来读取包含指令的文件并执行这些指令 基本上它是我猜的语言的简单解释器 它是完全线性的 所有语句都是按顺序定义的 并且只有字符串和整数变量 我需要查找和
  • 如何将自定义日志处理程序添加到 Google App Engine?

    我正在尝试向我的 java 应用程序添加自定义日志处理程序 我已经实现了一个扩展 java util Logging Handler 类的 InnerLogger 类 在我的logging properties中声明为处理程序 handle
  • 打印 jasper 文件时执行报表 SQL 语句时出错

    我修改了一个旧项目 但无法确定这段代码有什么问题 使用下面的 jrxml它创造 jasper文件 当我打印 jasper 文件时 使用此代码JasperPrint jasperPrint JasperFillManager fillRepo
  • 不要模拟值对象:过于通用的规则,没有解释

    以下是 Mockito 单元测试框架的引用 不要模拟值对象 为什么有人会想要这样做呢 因为实例化对象太痛苦了 gt 无效 原因 如果创造新的装置太困难 那就是一个迹象 代码可能需要一些认真的重构 另一种方法是创建 价值对象的构建者 有一些工
  • Java:使用 Java.util.concurrent 线程访问读取线程串行端口

    我正在尝试编写一个 Java 串行设备驱动程序并想使用 对我来说是新的 java util concurrent包裹 我有一种发送数据包然后等待 ACK 的方法 我打算有炭 接收在不同的线程中运行 如果接收线程收到 ACK 它应该使用发送数
  • 如何从 Google Custom Search API 获取超过 100 个结果

    我正在尝试使用 Google Custom Search API 在 Java 中进行研究 因此 我需要为每个查询提供一个大的结果集 然而 我似乎仅限于前 100 个结果 这比我需要的要少得多 我使用这样的列表方法 list setStar
  • 如何通过子 POJO 的属性过滤复合 ManyToMany POJO?

    我有两个像这样的房间实体 Entity public class Teacher implements Serializable PrimaryKey autoGenerate true public int id ColumnInfo n
  • 是否可以为 azure blob 存储中的给定目录生成具有写入权限的 SAS(共享访问签名)

    我们的 blob 存储帐户结构 容器名称 simple 在这个容器内我们有 blob aa one zip aa two zip bb ss zip bb dd zip 是否可以生成对aa 目录 有写权限 但对bb 目录 没有访问权限的SA
  • 在Java中多次读取System.in会导致IOException?

    我正在尝试创建一个小命令行游戏来强化我在过去几个月中在 Java 中学到的一些东西 我正在尝试创建一个名为 readInput 的方法 它返回一个我可以一次又一次调用的字符串 第一次它工作正常 但第二次它会导致 IO Exception 如
  • scala中的协变类型参数需要在java接口中保持不变

    我有一个看起来像这样的特征 一些进一步的信息可以在我自己提出了这个相关问题 https stackoverflow com questions 3695990 inheritance and automatic type conversio
  • 方法签名中带或不带synchronized关键字的方法具有相同的字节码

    对于以下 2 个类 获得相同的 Java 字节码 java版本 java 版本 1 8 0 181 Java TM SE 运行时环境 构建 1 8 0 181 b13 Java HotSpot TM 64 位服务器 VM 内部版本 25 1
  • 我找不到 IntelliJ 快捷方式

    我使用 vim 一段时间 我知道有一个 intellij vim 插件 我很好奇内置的 IntelliJ 文本导航存在什么 如何打开实时模板来创建模板 如何查看以 tr 开头的现有模板列表 如何进行全局搜索并在当前文档中进行搜索 然后转到下

随机推荐

  • kettle 教程(一):简介及入门

    介绍 kettle 是纯 java 开发 开源的 ETL工具 用于数据库间的数据迁移 可以在 Linux windows unix 中运行 有图形界面 也有命令脚本还可以二次开发 kettle 的官网是 https community hi
  • HCIA笔记整理

    网络基础 什么是网络 网络就是由网络连接设备通过传输介质将网络终端设备连接起来 进行资源共享 信息传递的平台 交换机 交换机是按照通信两端传输信息的需要 用人工或设备自动完成的方法把要传输的信息送到符合要求的相应路由上的技术统称 交换机的作
  • element 表单动态获取性别

    element 动态获取性别 在前端页面里总是会有根据1和2显示相应的内容 我是小白刚接触这些就感觉无能为力 找了一些资料才有了解决方法 话不多说上代码
  • Postgresql时间处理技巧,每半天,每周,每月和每5分钟统计

    一 每半天 如果有张表log bus runinfo里有一个created date是timestamp类型 如何统计12点前的数据 在 PostgreSQL 中 您可以使用 DATE TRUNC 函数和 WHERE 子句来统计特定时间范围
  • opsForList().rightPushAll 是覆盖,还是添加

    opsForList rightPushAll 是添加 这个方法将给定的所有值添加到列表的最右端 它并不会覆盖列表中已有的任何值
  • while(++i)与 while(i++)

    1 while i 是先执行i 1 再进行判断 再执行循环体 2 while i 是先判断 再执行循环体 再 1 循环结束后 while i 执行完后 i 0 while i 执行完后 i 1 测试代码1 include
  • 正大国际琪貨:做股指期货需要多少保证金?

    股指之前是大户才有机会做 因为需要的条件太高了 一般人玩不来 为什么 看看国内的股指条件 股指的保证金比例是12 14 一手股指保证金大约18万元 啥 这是什么概念 怎么这么贵 哈哈 是不是已经把很多人吓跑了 但这东西 波动的一个点值也很大
  • LSTM简单例子(MATLAB code)

    最近在学习RNN和LSTM 1 http magicly me 2017 03 09 iamtrask anyone can code lstm 2 https zybuluo com hanbingtao note 581764 3 ht
  • GLTF中的Draco编译与测试

    1 GLTF Primitive primitive里面有什么属性 Draco压缩是跟GLTF Primitive primitive息息相关的 下面是 GLTF Primitive 中常见的属性 1 GLTF Accessor indic
  • 12C++11多线程编程之原子操作std::atomic

    1 原子操作std atomic相关概念 前言 原子操作 更小的代码片段 并且该片段必定是连续执行的 不可分割 1 1 原子操作std atomic与互斥量的区别 1 互斥量 类模板 保护一段共享代码段 可以是一段代码 也可以是一个变量 2
  • Docker镜像打包及解压(内外网)

    背景 在企业中往往出现了内网不能和外网相通 不能使用docker pull命令来拉取镜像 这个时候我们就可以考虑在有所需镜像的服务器上导出镜像 再将其上传到内网服务器上 有两种方法 一种是通过容器 一种是通过镜像 其实本质是一样的 容器的实
  • Tomcat配置出错:Using CATALINA_OPTS: ““&&Tomcat启动闪退问题解决

    文章目录 前言 一 问题描述 二 定位问题 1 CMD命令启动 2 解决方法 前言 本篇问题所处环境 Tomcat 9 Java11 Win 10 一 问题描述 在安装配置Tomcat过程中 通过startup bat脚本命令启动Tomca
  • javascript 清除字符串空格

    去除字符串前后的空格 function trim str return str replace s s g 去除字符串中所有空格 function removeAllSpace str return str replace s g 用法举例
  • 服务器散列值与文件,服务器计算的散列值和客户端安全

    服务器计算的散列值和客户端安全 内容精选 换一换 执行adc命令 系统内部通过ADC与运行环境上的ADA的交互 实现文件传输 设置日志级别 心跳检测等功能 在ADC与ADA交互时 涉及使用密钥证书实现ADA 作为服务端 和ADC 作为客户端
  • Mysql 显示替换 if or

    摘要 使用Mysql的进行sql查询过程中 经常会遇到对查询结果做一些显示的替换 方式一 select if value in 0 1 2 NO YES from table name 方式二 select if value 0 or va
  • spring事务的7种传播行为——详细介绍

    目录 事务传播行为 1 PROPAGATION REQUIRED 2 PROPAGATION SUPPORTS 3 PROPAGATION MANDATORY 4 PROPAGATION MANDATORY 5 PROPAGATION NO
  • js开发技巧-实用型

    目录 1 按位或 2 按位与 3 按位取反 4 按位异或 5 6 toString 7 gt 和 lt 8 Number EPSILON
  • 【SpringBoot学习】SpringBoot的自动配置

    SpringBoot自动配置 SpringBootApplication是一个复合注解 其中主要包含以下注解 SpringBootConfiguration 基本是属于替代品 Configuration EnableAutoConfigur
  • ROS 執行launch報錯 python2.7錯誤

    mjm mjm pc Desktop ros robot pro roslaunch ros urdf PK test launch Traceback most recent call last File opt ros melodic
  • Java输出PPT文件(二) - 占位符数据替换

    Java输出PPT文件 二 占位符数据替换 文章目录 Java输出PPT文件 二 占位符数据替换 0 前言 1 依赖 2 代码 3 测试 3 1 模板准备 3 2 替换结果 4 一点分析 4 1 parseParagraph 4 2 get