精华内容
下载资源
问答
  • 2021-03-03 12:49:33

    java读取word文档时,虽然网上介绍了很多插件poi、java2Word、jacob、itext等等,poi无法读取格式(新的API估计行好像还在处于研发阶段,不太稳定,做项目不太敢用);java2Word、jacob容易报错找不到注册,比较诡异,我曾经在不同的机器上试过,操作方法完全一致,有的机器不报错,有的报错,去他们论坛找高人解决也说不出原因,项目部署用它有点玄;itxt好像写很方便但是我查了好久资料没有见到过关于读的好办法。经过一番选择还是折中点采用rtf最好,毕竟rtf是开源格式,不需要借助任何插件,只需基本IO操作外加编码转换即可。rtf格式文件表面看来和doc没啥区别,都可以用word打开,各种格式都可以设定。

    ----- 实现的功能:读取rtf模板内容(格式和文本内容),替换变化部分,形成新的rtf文档。

    ----- 实现思路:模板中固定部分手动输入,变化的部分用$info$表示,只需替换$info$即可。

    1、采用字节的形式读取rtf模板内容

    2、将可变的内容字符串转为rtf编码

    3、替换原文中的可变部分,形成新的rtf文档

    主要程序如下:

    /**

    * 将制定的字符串转换为rtf编码

    */

    public String bin2hex(String bin) {

    char[] digital = "0123456789ABCDEF".toCharArray();

    StringBuffer sb = new StringBuffer("");

    byte[] bs = bin.getBytes();

    int bit;

    for (int i = 0; i < bs.length;i++) {

    bit = (bs[i] & 0x0f0) >> 4;

    sb.append("\\'");

    sb.append(digital[bit]);

    bit = bs[i] & 0x0f;

    sb.append(digital[bit]);

    }

    return sb.toString();

    }

    /**

    * 字节形式读取rtf模板内容

    */

    public String readByteRtf(InputStream ins, String path){

    String sourcecontent = "";

    try{

    ins = new FileInputStream(path);

    byte[] b = new byte[1024];

    if (ins == null) {

    System.out.println("源模板文件不存在");

    }

    int bytesRead = 0;

    while (true) {

    bytesRead = ins.read(b, 0, 1024); // return final read bytes counts

    if(bytesRead == -1) {// end of InputStream

    System.out.println("读取模板文件结束");

    break;

    }

    sourcecontent += new String(b, 0, bytesRead); // convert to string using bytes

    }

    }catch(Exception e){

    e.printStackTrace();

    }

    }

    以上为核心代码,剩余部分就是替换,从新组装java中的String.replace(oldstr,newstr);方法可以实现,在这就不贴了。源代码部分详见附件。运行源代码前提:

    c盘创建YQ目录,将附件中"模板.rtf"复制到YQ目录之下,运行OpreatorRTF.java文件即可,就会在YQ目录下生成文件名如:21时15分19秒_cheney_记录.rtf 的文件。。。。。文件名是在程序中指定的呵呵。由于是由商业软件中拆分出的demo所以只是将自己原来的写的程序分离,合并在一个java文件中,所以有的方法在示例程序中看似多余,没有必要那么麻烦。

    对于替换部分需要循环的特例程序,我不好拆分,里面很容易暴露商业软件的东西,所以就不贴了,有需要的话可以加我QQ或者MSN,一起讨论呵呵。附件传了半天也没有传上去,没有办法只有这样搞了呵呵。模板文件附件无法存放,需要的直接联系呵呵。其实直接看以下的java程序部分,就会明白

    /**

    * 以下部分是java源代码

    */

    package com;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.FileWriter;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.PrintWriter;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    public class OperatorRTF {

    /**

    * 字符串转换为rtf编码

    * @param content

    * @return

    */

    public String strToRtf(String content){

    char[] digital = "0123456789ABCDEF".toCharArray();

    StringBuffer sb = new StringBuffer("");

    byte[] bs = content.getBytes();

    int bit;

    for (int i = 0; i < bs.length; i++) {

    bit = (bs[i] & 0x0f0) >> 4;

    sb.append("\\'");

    sb.append(digital[bit]);

    bit = bs[i] & 0x0f;

    sb.append(digital[bit]);

    }

    return sb.toString();

    }

    /**

    * 替换文档的可变部分

    * @param content

    * @param replacecontent

    * @param flag

    * @return

    */

    public String replaceRTF(String content,String replacecontent,int flag){

    String rc = strToRtf(replacecontent);

    String target = "";

    /*if(flag==0){

    target = content.replace("$time$",rc);

    }*/

    if(flag==0){

    target = content.replace("$timetop$",rc);

    }

    if(flag==1){

    target = content.replace("$info$",rc);

    }

    if(flag==2){

    target = content.replace("$idea$",rc);

    }

    if(flag==3){

    target = content.replace("$advice$",rc);

    }

    if(flag==4){

    target = content.replace("$infosend$",rc);

    }

    return target;

    }

    /**

    * 获取文件路径

    * @param flag

    * @return

    */

    public String getSavePath() {

    String path = "C:\\YQ";

    File fDirecotry = new File(path);

    if (!fDirecotry.exists()) {

    fDirecotry.mkdirs();

    }

    return path;

    }

    /**

    * 半角转为全角

    */

    public String ToSBC(String input){

    char[] c = input.toCharArray();

    for (int i = 0; i < c.length; i++){

    if (c[i] == 32){

    c[i] = (char) 12288;

    continue;

    }

    if (c[i] < 127){

    c[i] = (char) (c[i] + 65248);

    }

    }

    return new String(c);

    }

    public void rgModel(String username, String content) {

    // TODO Auto-generated method stub

    /*  构建生成文件名 targetname:12时10分23秒_username_记录.rtf */

    Date current=new Date();

    SimpleDateFormat sdf=new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    String targetname = sdf.format(current).substring(11,13) + "时";

    targetname += sdf.format(current).substring(14,16) + "分";

    targetname += sdf.format(current).substring(17,19) + "秒";

    targetname += "_" + username +"_记录.rtf";

    /* 字节形式读取模板文件内容,将结果转为字符串 */

    String strpath = getSavePath();

    String sourname = strpath+"\\"+"模板.rtf";

    String sourcecontent = "";

    InputStream ins = null;

    try{

    ins = new FileInputStream(sourname);

    byte[] b = new byte[1024];

    if (ins == null) {

    System.out.println("源模板文件不存在");

    }

    int bytesRead = 0;

    while (true) {

    bytesRead = ins.read(b, 0, 1024); // return final read bytes counts

    if(bytesRead == -1) {// end of InputStream

    System.out.println("读取模板文件结束");

    break;

    }

    sourcecontent += new String(b, 0, bytesRead); // convert to string using bytes

    }

    }catch(Exception e){

    e.printStackTrace();

    }

    /* 修改变化部分 */

    String targetcontent = "";

    /**

    * 拆分之后的数组元素与模板中的标识符对应关系

    * array[0]:timetop

    * array[1]:info

    * array[2]:idea

    * array[3]:advice

    * array[4]:infosend

    */

    String array[] = content.split("~");

    /**

    * 2008年11月27日:更新模板之后时间无需自动填充

    */

    /*String nowtime = sdf.format(current).substring(0,4) + "年";

    nowtime += sdf.format(current).substring(5,7) + "月";

    nowtime += sdf.format(current).substring(8,10) + "日";*/

    for(int i=0;i

    /*if(i==0){

    targetcontent = documentDoc.replaceRTF(sourcecontent,nowtime,i);

    }else{

    targetcontent = documentDoc.replaceRTF(targetcontent,array[i-1],i);

    }*/

    if(i==0){

    targetcontent = replaceRTF(sourcecontent, array[i], i);

    }else{

    targetcontent = replaceRTF(targetcontent, array[i], i);

    }

    }

    /* 结果输出保存到文件 */

    try {

    FileWriter fw = new FileWriter(getSavePath()+"\\" + targetname,true);

    PrintWriter out = new PrintWriter(fw);

    if(targetcontent.equals("")||targetcontent==""){

    out.println(sourcecontent);

    }else{

    out.println(targetcontent);

    }

    out.close();

    fw.close();

    System.out.println(getSavePath()+"  该目录下生成文件" + targetname + " 成功");

    } catch (IOException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    OperatorRTF oRTF = new OperatorRTF();

    /**

    * 被替换内容以"~"符号分割,处理的时候将其拆分为数组即可

    */

    String content = "2008年10月12日9时-2008年10月12日6时~我们参照检验药品的方法~我们参照检验药品的方法~我们参照检验药品的方法~我们参照检验药品的方法";

    oRTF.rgModel("cheney",content);

    }

    }

    更多相关内容
  • thinkphp5.0集成phpword,生成word文档并下载-附件资源
  • 打开word中的"段落"--"多级列表"--"定义新多级列表"--"单击要修改的级别"中选1--“将级别链接到样式”选择“标题1”(此步骤是将该级别和样式进行链接)--“在库中显示的级别”为“级别1”; 在“此级别的编号样式...

    [版权申明] 非商业目的注明出处可自由转载
    博文地址:https://blog.csdn.net/cdpxc/article/details/109001412
    出自:cdpxc

    步骤1:设置一级标题。

    1. 打开word中的"段落"--"多级列表"--"定义新多级列表"--"单击要修改的级别"中选1--“将级别链接到样式”选择“标题1”(此步骤是将该级别和样式进行链接)--“在库中显示的级别”为“级别1”;
    2. 在“此级别的编号样式”选择想要的编号样式(如,一、二、三(简)...)——在"输入编号的格式"会处会显示当前设置的样式(如,一),而且可以在格式的前后添加文字(如,第一章);
    3.  

     

    步骤2:设置二级标题。

    1. 打开word中的"段落"--"多级列表"--"定义新多级列表"--"单击要修改的级别"中选2--“将级别链接到样式”选择“标题2”(此步骤是将该级别和样式进行链接)--“在库中显示的级别”为“级别2”;
    2. 如果一级标题有大写“一”——选中“正规形式编号”,但不能删除“输入编号的格式”——直接点击“确定”即可,(如,1.1);
    3. 如果一级标题没有大写“一”——无需选择“正规形式编号”,可以删除“输入编号的格式”处的内容——“包含的级别编号来自”选择“级别1”——输入“.”——“此级别的编号样式”选择想要的格式——观察“输入编号的格式”处,会显示当前级别的编号格式,同样,可以在编号前后添加文字(如,第1.1条);

       

     

    步骤3:设置三级标题。

    1. 打开word中的"段落"--"多级列表"--"定义新多级列表"--"单击要修改的级别"中选3--“将级别链接到样式”选择“标题3”(此步骤是将该级别和样式进行链接)--“在库中显示的级别”为“级别3”
    2. 如果一级标题有大写“一”——选中“正规形式编号”,但不能删除“输入编号的格式”处的内容——直接“确定”即可,(如,1.1.1);
    3. 如果一级标题没有大写“一”——无需选择“正规形式编号”,可以删除“输入编号的格式”处的内容——“包含的级别编号来自”选择“级别1”——输入“.”——“包含的级别编号来自”选择“级别2”——输入“.”——“此级别的编号样式”选择想要的格式——观察“输入编号的格式”处,会显示当前级别的编号格式,同样,可以在编号前后添加文字(如,第1.1.1条);

       

    相关说明:

    1. 步骤三中黄圈中的部分,一般情况下,都是将这个格式“更改应用于“设置为整个列表”,而“起始编号”和“重新开始列表的间隔”是自动变化的,不明白的话不要擅自修改;
    2. 步骤二和三中删除“输入编号的格式”处的内容,又重新选择一次的原因是,有时候word排版链接出错,不过几率比较少,一般将“级别链接到样式”和“要在库中显示的级别”没问题,“输入编号的格式”也会按照级别显示。
    3. 结果呈现的自动编号形式如下图,样式也可以看到标题1,2,3的例子,当然,没有设置编号的段落格式(如制表符、缩进等),没有设置标题样式的格式,因此,段落和字体都是默认的。

       

     

     

    展开全文
  • Java使用Freemarker生成各类型Word文档大合集 前言-Freemarker简单介绍 近期项目工作中需要编写大量格式相同但数据不同的Word文档,需要实现自动生成文档的效果,但是通过网上冲浪和官方文档搜索,相对来说,没有...

    前言-Freemarker简单介绍

    • 近期项目工作中需要编写大量格式相同但数据不同的Word文档,需要实现自动生成文档的效果,但是通过网上冲浪和官方文档搜索,相对来说,没有分类整理的文档,因此自己抽空简要分类整理了一下,如果错误,还请各位reader尽情指出。

    0 环境准备

    • 这里提供一个基础SpringBoot项目,后续的每个环节的代码都将一步步以这个为基础构建,如果你也打算从头开始挨个实操一遍,可以下载并导入之后同步我的后续操作,文末也会提供一份完整的代码
    • 链接:https://www.aliyundrive.com/s/iXoQuRZh9pf
    • 环境配置说明
      • IDEA2019.3
      • JDK1.8
      • SpringBoot2.3.7.RELEASE
      • Freemarker 2.3.28
    • 目录结构介绍
      • image-20210811093443996
      • image-20210811094444943
      • src下存储主要的代码,这里划分了六个包,分别是text(普通文本)、object(对象)、picture(图片)、table(表格)、attachment(附件)、utils(工具类),之所以将每个不同类型的操作分开,是因为考虑到看到此篇文章的reader都有各自不同的需求,这样就可以直接定位到自己需要的模块,如果需要不同类型的组合,只需要弄清楚每一块的数据存储和映射就可以做到自己按需拼凑了。建议看一下处理普通文本模块,里面一些内容在后续其他模块不会重复赘述
      • resource下面也针对五大类型设置了五个文件夹,其中每个文件的名字和src下的包名是对应的,其中template文件夹存储模板文件(doc、xml、ftl文件),generate保存根据对应模板生成的最终文件
      • pom.xml中没有比较特别的,引入了Freemarker的依赖

    1 处理普通文本

    • 准备Word文档

      • 在resources/freemarker/text/template文件夹下,创建一个text.doc文件,文件内容如下
      • image-20210811095108274
    • 保存为xml格式

      • doc文档编写完成之后,使用另存为,保存为xml格式(WPS)
      • image-20210811095204583
      • 保存的时候需要注意以下两点
        • 保存位置,我这里都是存储在template同样目录下
        • 保存格式选择
          • image-20210811095305475
    • 转换为ftl格式

      • 使用一些强大的文本编辑工具(这里使用EditPlus),打开xml文件,进行格式化
        • 格式化xml工具:https://blog.csdn.net/qq_41649001/article/details/119595800
      • 格式化前后对比
        • image-20210811095759194
        • image-20210811095810795
        • 如果格式化后,出现${}形式的占位符中的内容被分隔开了,如下面情况,那么我们需要手动删除掉中间内容即可
          • image-20210811100512417
          • image-20210811100527529
      • 我们可以使用ctrl+f就可以搜索到我们在doc文档中填写的${}形式的占位符,后续Freemarker会识别占位符,然后进行替换
      • image-20210811100058977
      • 然后另存为为ftl格式文件即可
        • image-20210811100137986
      • 到现在为止,我们的模板文件已经准备好了(ftl),其他两个文件可以看做是过渡文件
    • 编写代码

      • 编写一个Freemarker生成Word文档的工具类,减少代码冗余,以后的一些生成操作直接调用即可,放在src中utils包中
      package com.fc.fcleverutils.freemarker.utils;
      
      import freemarker.template.Configuration;
      import freemarker.template.Template;
      import freemarker.template.Version;
      
      import java.io.*;
      import java.util.Map;
      
      /**
       * @ClassName WordUtil
       * @Description     使用Freemarker生成Word文档工具类
       * @Author Fclever
       * @Date 2021/8/11 10:06
       **/
      public class WordUtil {
      
      
        /**
           * 使用Freemarker自动生成Word文档
           * @param dataMap   保存Word文档中所需要的数据
           * @param templatePath  模板文件的绝对路径
           * @param templateFile  模板文件的名称
           * @param generateFile  生成文件的路径+名称
           * @throws Exception
           */
        public static void generateWord(Map<String, Object> dataMap, String templatePath,String templateFile, String generateFile) {
          // 设置FreeMarker的版本
          Configuration configuration = new Configuration(new Version("2.3.28"));
          // 设置Freemarker的编码格式
          configuration.setDefaultEncoding("UTF-8");
          Writer out = null;
          try{
            // 设置FreeMarker生成Word文档所需要的模板的路径
            configuration.setDirectoryForTemplateLoading(new File(templatePath));
            // 设置FreeMarker生成Word文档所需要的模板名称
            Template t = configuration.getTemplate(templateFile, "UTF-8");
            // 创建一个Word文档的输出流
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(generateFile)), "UTF-8"));
            //FreeMarker使用Word模板和数据生成Word文档
            t.process(dataMap, out);
          } catch (Exception e) {
            e.printStackTrace();
          }
          if (out != null) {
            try {
              out.flush();
              out.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }
      }
      
      
      • 然后在启动类中,编写获取数据代码和调用生成Word文档的工具方法
      package com.fc.fcleverutils;
      
      import com.fc.fcleverutils.freemarker.utils.WordUtil;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      import java.util.HashMap;
      import java.util.Map;
      
      @SpringBootApplication
      public class FcleverUtilsApplication {
      
        public static void main(String[] args) {
          SpringApplication.run(FcleverUtilsApplication.class, args);
          // 1. 使用Freemarker生成Word文档(普通文本)
          WordUtil.generateWord(getTextData(),
                                "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\text\\template\\",
                                "text.ftl", "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\text\\generate\\text.doc");
        }
      
        /**
           * 获取生成普通文本所需数据
           * @return
           */
        private static Map<String, Object> getTextData() {
          /*
               * 创建一个Map对象,将Word文档需要的数据都保存到该Map对象中
               */
          Map<String, Object> dataMap = new HashMap<>();
          dataMap.put("name", "小白");
          dataMap.put("freemarker", "Freemarker");
          dataMap.put("content", "普通文本");
          return dataMap;
        }
      
      }
      
      
    • 运行测试

      • 运行启动类,在生成路径中可以看到已经生成了text.doc
      • image-20210811102333522
      • image-20210811102939010
      • OK,测试通过

    2 处理对象类型数据

    • 准备Word文档

      • 在resources/freemarker/object/template下创建一个object.doc文件
      • image-20210811105442090
    • 保存为xml格式

      • image-20210811110331388
    • 转换为ftl格式

      • image-20210811110532698
      • image-20210811110555961
    • 编写代码

      • 对于对象类型的数据和普通文本处理差不多,只需要修改代码中的数据即可

      • 编写实体类

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public class User {
        
          private String name;
          private String sex;
          private String birthday;
        }
        
      • 修改启动类

        package com.fc.fcleverutils;
        
        import com.fc.fcleverutils.freemarker.object.User;
        import com.fc.fcleverutils.freemarker.utils.WordUtil;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        
        import java.util.HashMap;
        import java.util.Map;
        
        @SpringBootApplication
        public class FcleverUtilsApplication {
        
          public static void main(String[] args) {
            SpringApplication.run(FcleverUtilsApplication.class, args);
            // 2. 使用Freemarker生成Word文档(对象)
            WordUtil.generateWord(getObjectData(),
                                  "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\object\\template\\",
                                  "object.ftl", "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\object\\generate\\object.doc");
          }
        
          /**
             * 获取生成对象所需数据
             * @return
             */
          private static Map<String, Object> getObjectData() {
            /*
                 * 创建一个Map对象,将Word文档需要的数据都保存到该Map对象中
                 */
            Map<String, Object> dataMap = new HashMap<>();
            User user = new User();
            user.setName("小白");
            user.setSex("男");
            user.setBirthday("2021-101-10");
            dataMap.put("user", user);
            return dataMap;
          }
        
        }
        
        
    • 运行测试

      • 运行启动类
      • image-20210811112147497
      • 测试通过

    3 处理表格数据

    • 准备Word文档

      • resources\freemarker\table\template创建一个table.doc
    • 保存为xml格式

      • 注意xml格式和保存路径

      • image-20210811121845012

      • 最好先进行格式化,对于表格内容,需要特殊处理

      • 首先,我们可以搜索表头内容和${}的内容找到表头

        • image-20210811122102128
        • image-20210811122118183
        • 这里尤其需要注意一下,查找到的内容是否是准确。
      • 对于表格的处理, 表头所在行保留即可,表格中的数据是需要循环遍历生成的,因此我们需要使用下面个标签

        <#list userList as user>
        </#list>
        
        • userList与代码中Map对象的Key保持一致
        • as表示起别名的作用,和SQL语句别名可以类别
        • user表示别名,这样在xml中就可以使用别名进行处理
      • 在xml中,我们可以找到存在${user.name}这样我们自定义的占位符是在<w:tr></w:tr>这样的标签中保存的,因为doc中我们写了三行数据,所以会找到三个这样的标签(这个需要细心查找一下)

        • image-20210811122729391
        • 对标签进行折叠,三对标签对应三行数据
        • image-20210811122749152
      • 这里我们只需要保留一行即可,然后其余两对标签删除掉,然后在<w:tr>标签外,嵌套一层<#list>,效果如下:

        • image-20210811123228587
        • 需要强调的是,别名可以不写,如果起了别名,那么在<w:tr>标签中获取值的时候,就应该与别名保持一致
        • image-20210811123331535
      • 后续对表格处理比较熟悉之后,就只需要在doc中设置表头和一行用于定位标识的第一行内容即可

    • 转换为ftl格式

      • image-20210811123346887
    • 编写代码

      • 同样也是修改启动类中获取数据的代码即可
      package com.fc.fcleverutils;
      
      import com.fc.fcleverutils.freemarker.pojo.User;
      import com.fc.fcleverutils.freemarker.utils.WordUtil;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      import java.util.HashMap;
      import java.util.LinkedList;
      import java.util.List;
      import java.util.Map;
      
      @SpringBootApplication
      public class FcleverUtilsApplication {
      
        public static void main(String[] args) {
          SpringApplication.run(FcleverUtilsApplication.class, args);
          // 3. 使用Freemarker生成Word文档(表格)
          WordUtil.generateWord(getTableData(),
                                "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\table\\template\\",
                                "table.ftl", "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\table\\generate\\object.doc");
        }
      
      
        /**
           * 获取生成表格所需数据
           * @return
           */
        private static Map<String, Object> getTableData() {
          /*
               * 创建一个Map对象,将Word文档需要的数据都保存到该Map对象中
               */
          Map<String, Object> dataMap = new HashMap<>();
      
          List<User> userList = new LinkedList<>();
          userList.add(new User("张三", "男", "1999-01-01"));
          userList.add(new User("李四", "女", "2000-02-02"));
          userList.add(new User("王五", "男", "2021-02-03"));
          dataMap.put("userList",userList);
          return dataMap;
        }
      
      }
      
      
    • 运行测试

      • image-20210811124103257
      • 测试通过

    4 处理图片数据

    • 准备Word文档

      • resources\freemarker\picture\template下创建picture.doc,此外还需要准备几张图片做占位

    • 保存为xml格式

      • image-20210811131447105
      • 将xml格式化,对于图片内容的替换还是比较容易的,在浏览xml文件的时候,可以看到一些一大段的字符如下,其实这个就是图片的base64编码值
        • image-20210811131612739
      • 我们将这些base64编码值都删除掉(这些值都在<pkg:binaryData>标签中),然后将base64编码值所在的<pkg:part>标签都折叠起来,可以看到如下效果
        • image-20210811132359819
        • 这里有6个图片的base64值,是因为doc文档中我放了6个图片,但是我只删除3个(删除<pkg:name 是image1、image2、image3的),因为后面3个图片是期望效果里面的图片
      • 特别注意
        • 做占位的图片,不能重复复制一张图片,不然在转换xml的时候,会因为图片一样,而直接使用同一个base64值
        • 可以看到pkg:name很有特点,它的值都是image1.jpeg、image2.jpeg。。。是有序的,而且这个编号顺序与doc文档中从上到下的图片顺序是一致的,利用好这一点,我们就可以很容易的定位图片
      • 现在开始使用占位符替换
        • image-20210811132650562
      • 后面要做的就很明显了,我们需要将我们要插入的图片,生成base64值,然后保存到Map中进行Freemarker生成即可
    • 转换为ftl格式

      • image-20210811132809754
    • 编写代码

      • 将图片生成Base64值工具类

        package com.fc.fcleverutils.freemarker.utils;
        
        import org.springframework.util.StringUtils;
        import sun.misc.BASE64Encoder;
        
        import java.io.File;
        import java.io.FileInputStream;
        import java.io.IOException;
        import java.io.InputStream;
        
        /**
         * @ClassName ImageUtil
         * @Description 生成指定图片的base64值
         * @Author Fclever
         * @Date 2021/8/11 13:29
         **/
        public class ImageUtil {
        
          /**
             * 将图片内容转换成Base64编码的字符串
             *
             * @param imageFile 图片文件的全路径名称
             * @return 转换成Base64编码的图片内容字符串
             */
          public static String getImageBase64String(String imageFile) {
            if (StringUtils.isEmpty(imageFile)) {
              return "";
            }
            File file = new File(imageFile);
            if (!file.exists()) {
              return "";
            }
            InputStream is = null;
            byte[] data = null;
            try {
              is = new FileInputStream(file);
              data = new byte[is.available()];
              is.read(data);
              is.close();
            } catch (IOException e) {
              e.printStackTrace();
            }
        
            BASE64Encoder encoder = new BASE64Encoder();
            return encoder.encode(data);
          }
        }
        
        
      • 修改启动类

        package com.fc.fcleverutils;
        
        import com.fc.fcleverutils.freemarker.pojo.User;
        import com.fc.fcleverutils.freemarker.utils.ImageUtil;
        import com.fc.fcleverutils.freemarker.utils.WordUtil;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        
        import java.util.HashMap;
        import java.util.LinkedList;
        import java.util.List;
        import java.util.Map;
        
        @SpringBootApplication
        public class FcleverUtilsApplication {
        
          public static void main(String[] args) {
            SpringApplication.run(FcleverUtilsApplication.class, args);
            // 4. 使用Freemarker生成Word文档(图片)
            WordUtil.generateWord(getPictureData(),
                                  "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\picture\\template\\",
                                  "picture.ftl", "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\picture\\generate\\picture.doc");
          }
        
        
          /**
             * 获取生成图片所需数据
             * @return
             */
          private static Map<String, Object> getPictureData() {
            /*
                 * 创建一个Map对象,将Word文档需要的数据都保存到该Map对象中
                 */
            Map<String, Object> dataMap = new HashMap<>();
        
            String picture1 = ImageUtil.getImageBase64String("G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\picture\\template\\1.jpg");
            String picture2 = ImageUtil.getImageBase64String("G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\picture\\template\\2.jpg");
            String picture3 = ImageUtil.getImageBase64String("G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\picture\\template\\3.jpg");
        
            dataMap.put("picture1",picture1);
            dataMap.put("picture2",picture2);
            dataMap.put("picture3",picture3);
            return dataMap;
          }
        
        }
        
        
    • 运行测试

      • image-20210811133433469
      • 从生成结果中还可以验证一件事,生成图片的宽高与原来占位符图片的宽高是一致的

    5 处理附件插入

    • 准备附件

      • 这里准备一个空白的Excel文件attachment.xls,插入到Word文档中做占位符
      • image-20210811152217926
    • 准备Word文档

      • 1
      • 插入刚刚创建的空白附件
        • image-20210811152246211
        • image-20210811152322809
        • image-20210811152327369
      • 后面我们要实现的就是,通过代码模拟一些数据,然后生成Excel文档,替换掉充当占位符的附件内容
    • 保存为xml格式

      • image-20210811152857538
      • 将xml格式化之后,可以看到里面有两串字符
        • image-20210811152922813
        • image-20210811152935476
        • 第一个图中的值就是占位符Excel内容转换成的Base64值
        • 第二个图示Word中插入Excel后,显示的小图标上图片的base64值
        • 我们这里只需要替换掉第一个值就可以实现改变附件内容了
      • 使用${}进行替换
        • image-20210811153131332
    • 转换为ftl格式

      • image-20210811153147629
    • 编写代码

      • 具体流程

        • 代码使用集合模拟数据,效果如下
          • image-20210811153406668
        • 然后使用EasyExcel技术,将模拟的数据填充到一个Excel模板中
        • 然后通过文件流的形式读取Excel
        • 最后将文件流转成Base64值,保存到Map中
        • 使用Freemarker输出文档
      • 项目引入EasyExcel依赖

        <!--EasyExcel-->
        <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>easyexcel</artifactId>
          <version>2.1.6</version>
        </dependency>
        
      • 实体

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public class User {
        
            private String name;
            private String sex;
            private String birthday;
        }
        
      • 创建EasyExcel填充的Excel模板

        • image-20210811154914663
        • 填充语法是依据EasyExcel的语法
        • 属性名和实体中变量名对应
        • 加.号表示为列表
      • 通过EasyExcel生成Excel

        /**
             * 通过EasyExcel生成Excel,并返回文件对象
             * @return
             */
        private static File templateToExcel() {
          // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
          // 填充list 的时候还要注意 模板中{.} 多了个点 表示list
          // 模板文件
          String templateFileName = "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\attachment\\template\\template.xls";
          // 输出文件路径
          String resultFileName = "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\attachment\\generate\\templateResult.xls";
          LinkedList<User> list = new LinkedList<>();
          list.add(new User("张三", "男", "1999-01-01"));
          list.add(new User("李四", "女", "2020-12-21"));
          list.add(new User("王五", "男", "1998-01-01"));
          // 这里 会填充到第一个sheet, 然后文件流会自动关闭
          EasyExcel.write(resultFileName).withTemplate(templateFileName).sheet().doFill(list);
          return new File(resultFileName);
        }
        
      • 将生成Excel转成Base64

        /**
             * 将文件转为Base64值
             *
             * @param file 文件对象
             * @return
             */
        public static String convertToBase64(File file) {
          byte[] fileBytes = null;
          FileInputStream fis = null;
          try {
            fis = new FileInputStream(file);
            fileBytes = new byte[(int) file.length()];
            fis.read(fileBytes);
            fis.close();
          } catch (Exception e) {
            e.printStackTrace();
          }
          return Base64.getEncoder().encodeToString(fileBytes);
        }
        
      • 使用Freemarker输出文档

        package com.fc.fcleverutils;
        
        import com.alibaba.excel.EasyExcel;
        import com.alibaba.excel.ExcelWriter;
        import com.alibaba.excel.write.metadata.WriteSheet;
        import com.fc.fcleverutils.freemarker.pojo.User;
        import com.fc.fcleverutils.freemarker.utils.FileToBase64;
        import com.fc.fcleverutils.freemarker.utils.ImageUtil;
        import com.fc.fcleverutils.freemarker.utils.WordUtil;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        
        import java.io.File;
        import java.util.HashMap;
        import java.util.LinkedList;
        import java.util.List;
        import java.util.Map;
        
        @SpringBootApplication
        public class FcleverUtilsApplication {
        
            public static void main(String[] args) {
                SpringApplication.run(FcleverUtilsApplication.class, args);
                // 5.  使用Freemarker生成Word文档(附件)
                WordUtil.generateWord(getAttachmentData(),
                        "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\attachment\\template\\",
                        "attachment.ftl", "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\attachment\\generate\\attachment.doc");
            }
        
            /**
             * 通过EasyExcel生成Excel,并返回文件对象
             * @return
             */
            private static File templateToExcel() {
                // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
                // 填充list 的时候还要注意 模板中{.} 多了个点 表示list
                // 模板文件
                String templateFileName = "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\attachment\\template\\template.xls";
                // 输出文件路径
                String resultFileName = "G:\\IdeaProjects\\FcleverUtils\\src\\main\\resources\\freemarker\\attachment\\generate\\templateResult.xls";
                LinkedList<User> list = new LinkedList<>();
                list.add(new User("张三", "男", "1999-01-01"));
                list.add(new User("李四", "女", "2020-12-21"));
                list.add(new User("王五", "男", "1998-01-01"));
                // 这里 会填充到第一个sheet, 然后文件流会自动关闭
                EasyExcel.write(resultFileName).withTemplate(templateFileName).sheet().doFill(list);
                return new File(resultFileName);
            }
        
        
            /**
             * 获取生成附件所需数据
             * @return
             */
            private static Map<String, Object> getAttachmentData() {
                /*
                 * 创建一个Map对象,将Word文档需要的数据都保存到该Map对象中
                 */
                Map<String, Object> dataMap = new HashMap<>();
        
                // 根据Excel模板生成Excel
                File file = templateToExcel();
                // 读取Excel转Base64值
                String base64 = FileToBase64.convertToBase64(file);
        
                dataMap.put("attachment", base64);
                return dataMap;
            }
        
        }
        
        
    • 运行测试

      • 运行启动类,查看结果
      • image-20210811155125101
      • 进入文档,双击打开附件之后,内容已经填充完毕
      • image-20210811155149485

    6 整个项目完整代码

    • 整理比较匆忙,还有很多可以改善的地方,大家根据情况发挥就好了
      private static Map<String, Object> getAttachmentData() {
      /*
      * 创建一个Map对象,将Word文档需要的数据都保存到该Map对象中
      */
      Map<String, Object> dataMap = new HashMap<>();

            // 根据Excel模板生成Excel
            File file = templateToExcel();
            // 读取Excel转Base64值
            String base64 = FileToBase64.convertToBase64(file);
      
            dataMap.put("attachment", base64);
            return dataMap;
        }
      

      }

      
      
    • 运行测试

      • 运行启动类,查看结果

      • 在这里插入图片描述

      • 进入文档,双击打开附件之后,内容已经填充完毕

      • 在这里插入图片描述

    • 整理比较匆忙,还有很多可以改善的地方,大家根据情况发挥就好了

    • 代码:https://www.aliyundrive.com/s/cnrDfnL6uUr

    分页符

    • 文档中先设置插入分页符号,需要打开段落标记才能看到

    • 在这里插入图片描述

    • 在这里插入图片描述

    • 在这里插入图片描述

    • 在这里插入图片描述

    展开全文
  • Vue-纯前端导出word文档

    千次阅读 2019-12-23 10:11:26
    本文将介绍如何在前端纯js实现word文档导出。 docxtemplater docxtemplater 使用 JSON 数据格式作为输入,可以处理docx 和 ppt模板。不像一些其它的工具,比如 docx.js, docx4j, python-docx 等,需要自己编写...

    在项目中,我们可以借助后端返回文件流实现文件下载。如果前端有数据,也可以借助前端框架进行下载。本文将介绍如何在前端纯js实现word文档导出。

    docxtemplater

    docxtemplater 使用 JSON 数据格式作为输入,可以处理docx 和 ppt模板。不像一些其它的工具,比如 docx.js, docx4j, python-docx 等,需要自己编写代码来生成文件,docxtemplater只需要用户通过标签的形式编写模板,就可以生成文件。

    贴一贴官网给的例子,我们将参考以下例子来实现。

    var PizZip = require('pizzip');
    var Docxtemplater = require('docxtemplater');
    
    var fs = require('fs');
    var path = require('path');
    
    //Load the docx file as a binary
    var content = fs
        .readFileSync(path.resolve(__dirname, 'input.docx'), 'binary');
    
    var zip = new PizZip(content);
    
    var doc = new Docxtemplater();
    doc.loadZip(zip);
    
    //set the templateVariables
    doc.setData({
        first_name: 'John',
        last_name: 'Doe',
        phone: '0652455478',
        description: 'New Website'
    });
    
    try {
        // render the document (replace all occurences of {first_name} by John, {last_name} by Doe, ...)
        doc.render()
    }
    catch (error) {
        var e = {
            message: error.message,
            name: error.name,
            stack: error.stack,
            properties: error.properties,
        }
        console.log(JSON.stringify({error: e}));
        // The error thrown here contains additional information when logged with JSON.stringify (it contains a property object).
        throw error;
    }
    
    var buf = doc.getZip()
                 .generate({type: 'nodebuffer'});
    
    // buf is a nodejs buffer, you can either write it to a file or do anything else with it.
    fs.writeFileSync(path.resolve(__dirname, 'output.docx'), buf);
    

    jszip-utils

    jszip-utils 提供一个getBinaryContent(path, data)接口,path即是文件的路径,支持AJAX get请求,data为读取的文件内容。下面是官网给的例子。

    // loading a file and add it in a zip file
    JSZipUtils.getBinaryContent("path/to/picture.png", function (err, data) {
       if(err) {
          throw err; // or handle the error
       }
       var zip = new JSZip();
       zip.file("picture.png", data, {binary:true});
    });
    
    

    file-saver

    file-saver是一款适合在客户端生成文件的工具,它提供的接口saveAs(blob, "1.docx")将会使用到。

    安装

    接下来就是安装以上工具

    -- 安装 docxtemplater
    cnpm install docxtemplater pizzip  --save
    
    -- 安装 jszip-utils
    cnpm install jszip-utils --save 
    
    -- 安装 jszip
    cnpm install jszip --save
    
    -- 安装 FileSaver
    cnpm install file-saver --save
    
    

    引入

    在需要用到的组件中引入以上工具

        import docxtemplater from 'docxtemplater'
        import PizZip from 'pizzip'
        import JSZipUtils from 'jszip-utils'
        import {saveAs} from 'file-saver'
        
    

    创建模板文件

    我们要先创建一个模板文件,事先定义好格式和内容。docxtemplater 之前介绍到是通过标签的形式来填充数据的,简单的数据我们可以使用{} + 变量名来实现简单的文本替换。

    • 简单的文本替换

    如果在模板中,定义

    hello {name}
    

    在设置数据时,定义

    {name:'John'}
    
    

    最终生成的文件,如下

    hello John
    

    有点像jsp中的变量解析。

    • 循环输出

    稍微复杂点的像表格,我们会传递一个数组。那这个表格标签实现起来挺简单的,例子如下:

    模板文件,定义如下:

    {#products}
        {name}, {price} €
    {/products}
    

    设置数据时,定义如下:

    {
        "products": [
            { name :"Windows", price: 100},
            { name :"Mac OSX", price: 200},
            { name :"Ubuntu", price: 0}
        ]
    }
    

    最终实现效果如下:

    Windows, 100 €
    Mac OSX, 200 €
    Ubuntu, 0€
    

    如果数组中的都是字符串,不是对象类型,比如数据结构如下

    {
       "products": [
           "Windows",
           "Mac OSX",
           "Ubuntu"
       ]
    }
    

    那么,模板文件中应该这样设置

    {#products} {.} {/products}
    

    最终的文件内容如下:

    Windows Mac OSX Ubuntu
    
    

    还有一些其它的复杂标签,比输支持条件判断,支持段落等等,笔者就不在这里一一赘述了。详情参考官网文档。笔者的要导出的比较简单,前端页面如下:

    前端

    模板如下,笔者放在了\static\model.docx路径下:

    注意:

    1.本文因为开发使用了前后端分离,前端使用VsCode,我放在了前端的public文件夹下,其他位置我没有成功。

    2.每当修改了模板,并重新替换掉原先模板后,需要把文件先移动到其他路径,再移回来,目的是让vue路径更新,否则更新不过去。(会提示找不到该文件,是否是zip文件之类的错误。如果发现替换后就更新过去了,便不必这样操作)。

    模板

    使用

    我们可以参照 docxtemplater 给出的例子, 来实现文件导出。

    1. 读取模板文件内容
    2. 装载到zip对象中
    3. 设置文件数据
    4. 生成文件
    5. 保存文件

    代码如下:

     // 点击导出word
      exportWord: function() {
        let that = this;
        // 读取并获得模板文件的二进制内容
        JSZipUtils.getBinaryContent("../../static/model.docx", function(error, content) {
          // model.docx是模板。我们在导出的时候,会根据此模板来导出对应的数据
          // 抛出异常
          if (error) {
            throw error;
          }
    
          // 创建一个PizZip实例,内容为模板的内容
          let zip = new PizZip(content);
          // 创建并加载docxtemplater实例对象
          let doc = new docxtemplater().loadZip(zip);
          // 设置模板变量的值
          doc.setData({
            table: that.videoParam.data
          });
    
          try {
            // 用模板变量的值替换所有模板变量
            doc.render();
          } catch (error) {
            // 抛出异常
            let e = {
              message: error.message,
              name: error.name,
              stack: error.stack,
              properties: error.properties
            };
            console.log(JSON.stringify({ error: e }));
            throw error;
          }
    
          // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
          let out = doc.getZip().generate({
            type: "blob",
            mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
          });
          // 将目标文件对象保存为目标类型的文件,并命名
          saveAs(out, "视频参数.docx");
        });
      }
    

    最终下载的效果如下

    image.png

    注意

    • docxtemplater 不支持jszip,会有报错,因此要使用PizZip
    • 注意模板的路径要写正确,不然会报错找不到文件

    总结

    本文简单的介绍了如何在前端使用已有的工具来实现前端导出word文档,希望对有类似需求的童鞋们有所帮助。

    参考文章:

    vue项目导出word - 简书

    展开全文
  • Jakarta POI 是一套用于访问微软格式文档的Java API。Jakarta POI有很多组件组成,其中有用于操作Excel格式文件的HSSF和用于操作Word的HWPF;一、前端使用get请求和post请求都可以get请求:window.location.href= ...
  • java向word中插入Excel附件

    千次阅读 2019-10-06 07:08:49
    编辑word,向word中插入图片、EXCEL、WORD附件,再将word保存为xml格式,通过XML查看工具打开xml格式的word的源码,通过对比源码, 可以发现平时我们在编辑word时,向word中插入插入图片,EXCEL,word附件时,...
  • word中插入Excel形式的文件附件

    千次阅读 2017-03-02 15:34:58
    分以下三步: 第一步: 在工具栏上单击插入选项中的对象,此时会弹出一个对话框; 第二步: 选择由文件创建,从下面浏览中找到文件后,再单击此对话框中...如果你只想在word里显示为图标,可以把旁边的“显示为图标”勾
  • 全国计算机等级考试(National Computer Rank ...以下是小编整理的2015年计算机一级考试技巧:Word文档保存为PDF文件,供大家参考和学习。计算机等级一级:Word文档保存为PDF文件在Word2007中,用户需要安装Micros...
  • POI生成word文档完整案例及讲解

    千次阅读 2018-11-05 16:53:10
    其实POI的生成Word文档的规则就是先把获取到的数据转成xml格式的数据,然后通过xpath解析表单式的应用取值,判断等等,然后在把取到的值放到word文档中,最后在输出来。 1.1,参考一 1、poi之word文档结构介绍之...
  • 应客户需求需要在用户创建简历后把简历以附件形式发送到其指定邮箱,所有想到 先把数据存储到数据库,然后把数据读取出来处理后保存为word文档,然后在以附件形式发送刚开始实现的方法是把内容写成html的形式...
  • //以注释的形式添加附件到PDF String filePath = "测试文档.docx";byte[] data =toByteArray(filePath); Dimension2D size=font.measureString(label); Rectangle2D bound= new Rectangle2D.Float((float) (x + size...
  • word中加入excel附件 excel单元格中插入图片 poi 制作 Excel , jxl 插入图片 压缩图片/宽高,动态控制单元格高度与宽度 1.word 需要模板 手动创建word excel .向word中插入excel附件并另存为 word xml 格式 替换符...
  • 导出数据到具体的word文档里面,word有一定的格式,需要保持不变这里使用freemarker来实现:①:设计好word文档格式,需要用数据填充的地方用便于识别的长字符串替换 如 aaaaaaaaaaaaaaaa②:将word文档另存为 2003 ...
  • 导出数据到具体的word文档里面,word有一定的格式,需要保持不变 这里使用freemarker来实现: ①:设计好word文档格式,需要用数据填充的地方用便于识别的长字符串替换 如 aaaaaaaaaaaaaaaa ②:将word文档另存...
  • PHPWord

    2021-04-15 21:01:25
    想导出word文档,将文本添加到文档的指定位置,比如前一段话的后面,而前一段话是循环生成的,该段后面又有循环生成的另一段话,而我想加入的文本不能放在循环里,只能在两次循环输出文本之后添加,这样的话我怎么...
  • 初级篇一、文档可打开并修复Microsoft Office Word 2003 和 Microsoft Word 2002 在检测到文件有问题时,它们会尝试自动恢复损坏的文档。您也可以在打开文档时,“强制”Word 尝试恢复文档。为此,请按照下列步骤...
  • } } //用POI读取word文档的内容,本程序中暂时没用上 public static String readDoc(String doc) throws Exception { // FileInputStream in = new FileInputStream(new File(doc)); POIFSFileSystem fs = new ...
  • 开发者可以在word文档中添加、修改和删除超链接。Spire.Doc for .NET支持在 word 到 PDF 的转换中保留或不保留超链接。本文将向您展示如何在 C# 中将 word 文档转换为 PDF 文件格式时保留超链接或禁用超链接 Spire....
  • 在这篇文章中,我将展示如何利用基于Empire的PowerShell来对Word文档进行“伪装”攻击,可能还有其它实现方法,我仅作个抛砖引玉。 创建Empire Listener 创建一个Empire Listener监听线程,可点此查看Empire的使用...
  • 第二种方法:双击WORD文档打开WORD。第三种方法:1、在桌面空白处,鼠标右键选择新建——Microsoft Office Word文档。2、然后双击新建的WORD文档,即可打开WORD软件。第四种方法:1、打开桌面上的计算机,依次打...
  • Java读取word文档,转换为网页

    千次阅读 2017-11-20 19:51:04
    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://shamrock.blog.51cto.com/2079212/833580       public class Test3...
  • 一,poi根据excel模板,修改内容导出新excel 文档(只支持HSSF)excel模板就存放在了静态文件夹下,然后拿到这个文档之后,通过poi对单元格的赋值进行创建。public class CreateExcel {public static void ma...
  • 修复文件相信很多小伙伴们都遇到过这么个尴尬事我们在进行文档的处理的时候突然停电了!让人抓狂的停电!现在可是互联网时代啊,没电怎么活?最重要的是自己辛辛苦苦码了半天的文件还没有保存!没保存啊!没保存!...
  • 你还在跟 TA 们反复确认最新文档附件有没有收到吗?​蓝湖「共享产品文档」功能,让产品文档分享更方便、管理更高效,了解一下? 蓝湖「共享产品文档」功能支持 :1. 自动共享文档,在线展示 Axure / Word / PDF / ...
  • 了解过docx文件转换为xml后,visio图一般是通过emf预览图和附件形式保存在段落中,可以根据xml结构,获取到vsdx文件和emf预览图,但是现在需要反向将visio图插入进word,尝试过使用poi将新的visio图插入到新的段落...
  • C#生成word文档 、word转pdf、合并pdf文件等 在系统开发中经常会有用户需求涉及到基于模板导出word文档、pdf文档,或者把几个文件合并成一个进行导出预览等,他们所说需求不一样,但在功能实现上却是相同的。由于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,726
精华内容 2,690
关键字:

word文档附件形式