PageOffice 开发者中心 PageOffice 开发者中心
首页
文档
  • 后端Java手册 (opens new window)
  • 后端.netcore手册 (opens new window)
  • 前端JavaScript手册 (opens new window)
下载
购买 (opens new window)
首页
文档
  • 后端Java手册 (opens new window)
  • 后端.netcore手册 (opens new window)
  • 前端JavaScript手册 (opens new window)
下载
购买 (opens new window)
  • 开始

  • 通用控制

  • Word

  • Excel

  • PDF

  • FileMaker

    • 后台生成单个Word文档
      • 后台批量生成Word文档
      • 后台生成单个PDF文档
      • 后台批量生成PDF文档
      • 批量转PDF文件
      • 批量生成并打印文件
      • 不打开文件的情况下修改文档指定区域内容
    • PPT

    • 更多

    目录

    后台生成单个Word文档

    # 后台生成单个Word文档

    • 查看本示例演示效果

    注意

    本文中展示的代码均为关键代码,复制粘贴到您的项目中,按照实际的情况,例如文档路径,用户名等做适当修改即可使用。

    在实际项目开发中经常会遇到一种场景,客户希望点击页面上的生成文件按钮,执行程序动态填充数据到Word模板,直接在后台生成Word文档,而无需显示Word文档。目前网上有一些针对此需求的方案,但每个方案都存在很多各自的问题。

    # 与其他方案对比

    采用 Jacob 生成Word文档方案动态生成的Word文档,与PageOffice一样,文档格式是最完美的,因为都是调用的Office原生接口生成的文件,所以生成的是原汁原味的Word文档,但是Jacob局限于 windows 平台,往往许多 Java 程序运行于 Linux 等其他操作系统,而且Jacob的代码复杂、运行稳定性差且不安全,因为调用Office的自动化接口需要服务器端安装Office软件,服务器自动化调用有很大的风险,容易导致Office进程死锁、页面无响应、阻塞Web服务进程,从而影响整个网站的吞吐量,如果再考虑到多个用户同时并发操作生成Word文档的情况,Jacob程序对服务器端造成的压力足以卡死整个网站,并且Web Server需配置交互账户权限。针对这个问题,微软在MSDN上公开声明Word、Excel不适宜运行在服务进程里,因为Word、Excel仅被设计为桌面运行的程序。而PageOffice在客户端运行,100%的标准托管代码,服务器端不用安装Office,也不用引入自动化类型库,所以运行安全稳定,不必担心Web服务崩溃的风险。另外服务器自动化调用的API接口复杂难用,参数传递繁琐;而PageOffice提供了简化的对象调用模型,所以调用代码简单,开发效率高,运行稳定可靠。服务器自动化编程对于定位Word、Excel要填充内容的位置和定位要读取内容的位置比较困难,而PageOffice的简易对象模型可以轻松定位,精确填充和读取文档内容。所以Jacob已经是一个十几年前就淘汰的技术,仅限于个人研究,无法应用于实际项目。

    再就是使用OpenXML SDK、POI、iText等开源库的方案。OpenXML SDK是Microsoft提供的一组库和工具,用于创建、修改和提取Office Open XML格式的文件,但是操作OpenXML SDK需要对Open XML文档结构有一定的了解,因此在处理Word文档时可能需要编写大量的代码,使用OpenXML SDK还需要学习Open XML标记语言和SDK的API,这可能需要一些时间和精力来掌握,并且由于 OpenXML SDK 是用 C# 编写的,因此在 Java 中直接调用 OpenXML SDK 是很困难的。而使用 POI 生成文档对服务器的压力很大,而且它的 Excel 处理勉强可以, Word 模块还局限于读取 Word 的文本内容,写 Word 文件的功能就更弱;另一个致命的问题是,处理 doc 格式和处理 docx 格式的类几乎完全不同,要分开针对不同的格式写不同的代码,这就意味着用户上传的 docx 格式文件如果使用了 doc 的扩展名,程序马上崩溃。目前已知POI用来解析.doc、.xls那部分的组件是残缺不全的并且也已经不再更新了。而且 POI 结构混乱,编码比较复杂,开发过程非常消耗时间和精力。从性能上看,POI使用的xml处理对象本身就消耗内存,它要把整个文档都加载到内存,加上其他开销,比实际Word、Excel文档还大,遇到打开较大的Word、Excel文档时,JVM很容易内存溢出。而iText是一个用于处理PDF文件的Java库,它是可以操作Word文档,但是iText主要是用来处理PDF文档的,不支持Excel,且对于Word支持很有限,iText 生成的 Word 文件在不同版本的 Word 软件中可能会出现排版或样式兼容性的问题。iText 也需要较大的学习曲线,特别是对于没有使用过该库的开发人员来说。总的来说,使用开源库方案存在调用代码复杂、中文乱码,功能较弱等许多问题,最大的问题还是在生成文件的格式、样式、排版等方面存在很大问题,由于这些方案不是直接调用原生Office接口操作文件内容的,所以即使已经有一个模板文档做基础了,但是生成的文档中字体、样式、段落等还是会出现错乱的情况,尤其是处理页眉页脚、表格等内容时,出现的排版格式问题会更大。

    所以针对这一系列的问题,PageOffice 开发了 FileMaker 组件,该组件完全符合 PageOffice 的架构设计,提供了最简单的对象模型,没有任何学习成本。FileMaker 在客户端后台填充数据到Office模板生成文档并自动上传到服务器,不会打开显示生成的文档。由于FileMaker是调用Office原生接口操作文档内容的,所以生成的是原汁原味的Office文档格式,而且由于FileMaker调用的是客户端电脑上的Office,所以服务器上无需安装Office软件,也不要求服务器必须是Windows平台,生成文档的工作不会对服务器端造成任何压力,更不存在并发问题,实现了完美生成文档的目的,且避免了上述的所有问题。

    FileMakerCtrl 和 PageOfficeCtrl 的区别

    FileMakerCtrl 本质上就是一个没有界面的 PageOfficeCtrl,也是调用客户端 Office 程序处理文件的,FileMakerCtrl和PageOfficeCtrl都可以实现对文档进行动态填充、动态转 PDF 等功能,唯一的区别就是 FileMakerCtrl 在线打开填充和转换文档的时候,Web页面不会打开显示文档内容,而 PageOfficeCtrl 会弹出窗口打开显示文档内容。

    # PageOffice的解决方案

    下面就以生成一份荣誉证书的效果为例,介绍一下如何使用FileMaker组件动态生成Word文档。

    1. 需求效果:用户点击生成word文件按钮,执行程序把某公司信息动态填充到荣誉证书模板中,生成一份荣誉证书文件。

    2. 荣誉证书模板如下图所示,为了简单起见,模板中只使用了公司名称来代表公司的所有信息,所以只用了一个数据区域“PO_company”来标记公司名称的位置。

    3. 点击按钮后,执行把公司信息动态填充到Word模板中生成荣誉证书的后台代码(比如:/FileMakerSingle),在服务器端文件夹下生成一份荣誉证书文件:maker.doc,文件内容如下图所示。

    # 后端代码

    1. 在后端编写代码实现文档动态填充(比如/FileMakerSingle),关键代码如下:
      // 获取id后可以根据id从数据库中查询公司信息,为简单起见,就不再演示
      String id = request.getParameter("id"); 
      FileMakerCtrl fmCtrl = new FileMakerCtrl(request);
      WordDocumentWriter doc = new WordDocumentWriter();
      //给数据区域赋值,即把数据填充到模板中相应的位置
      doc.openDataRegion("PO_company").setValue("北京卓正志远软件有限公司");
      fmCtrl.setWriter(doc);
      fmCtrl.fillDocument("doc/template.doc", DocumentOpenType.Word);
      out.print(fmCtrl.getHtml());
      
      // 获取id后可以根据id从数据库中查询公司信息,为简单起见,就不再演示
      string id = Request.Query["id"]; 
      PageOfficeNetCore.FileMakerCtrl fileMakerCtrl = new PageOfficeNetCore.FileMakerCtrl(Request);
      PageOfficeNetCore.Word.WordDocumentWriter doc = new PageOfficeNetCore.Word.WordDocumentWriter();
      //给数据区域赋值,即把数据填充到模板中相应的位置
      doc.OpenDataRegion("PO_company").Value = "北京卓正志远软件有限公司";
      fileMakerCtrl.SetWriter(doc);
      fileMakerCtrl.FillDocument("doc/template.doc", PageOfficeNetCore.DocumentOpenType.Word);
      ViewBag.FMCtrl = fileMakerCtrl.GetHtml();
      
      // Make sure to add code blocks to your code group

      2.保存文件:在SaveFilePage指向的地址接口中,创建FileSaver对象保存文件。

        FileSaver fs = new FileSaver(request, response);
        String fileName = "maker" + fs.getFileExtName();
        fs.saveToFile(request.getSession().getServletContext().getRealPath("FileMakerSingle/doc") + "/" + fileName);
        fs.setCustomSaveResult("{\"msg\":\"ok\"}");//用于给前端页面返回数据
        fs.close();
        
        PageOfficeNetCore.FileSaver fs = new PageOfficeNetCore.FileSaver(Request, Response);
        await fs.LoadAsync();
        string webRootPath = _webHostEnvironment.WebRootPath;
        fs.SaveToFile(webRootPath + "/FileMakerSingle/doc/" + "maker" + fs.FileExtName);
        fs.CustomSaveResult = "{\"msg\":\"ok\"}";//用于给前端页面返回数据
        fs.Close();
        
        // Make sure to add code blocks to your code group

        # 前端代码

        编写前端网页代码,调用执行后端生成文件代码,并实现生成文件进度条的效果。

        <script setup>
        import request from '@/utils/request';
        import { ref, onMounted } from 'vue'
        import { filemakerctrl } from 'js-pageoffice'
        const titleText = ref('');
        const buttonDisabled = ref(false);
        const progressBar = ref(null);
        
        onMounted(async () => {
          try {
            const response = await request({
              url: '/index',
              method: 'get',
            });
            titleText.value = response;
          } catch (error) {
            console.error('Failed to fetch title:', error);
          }
        });
        
        function ConvertFile() {
          buttonDisabled.value = true;
          // 设置用于保存文件的服务器端controller地址,该地址需从"/"开始,指向服务器端根目录
          /** 如果想要给SaveFilePage传递参数,建议使用new URLSearchParams方式,例如:
        * let saveFileUrl = "/FileMakerSingle/save";
        * let paramValue = new URLSearchParams({id:1,name:"张三"});
        * filemakerctrl.SaveFilePage = `${saveFileUrl}?${paramValue.toString()}`;
        */
          filemakerctrl.SaveFilePage = "/FileMakerSingle/save";
        
          filemakerctrl.CallFileMaker({
            // url:指向服务器端FileMakerCtrl打开文件的controller地址,该地址需从"/"开始,指向服务器端根目录  
            url: "/FileMakerSingle/FileMakerSingle",
            success: (res) => {//res:获取服务器端fs.setCustomSaveResult设置的保存结果
              console.log(res);
              console.log("completed successfully.");
              setProgress(100);
              buttonDisabled.value = false;
            },
            progress: (pos) => {
              console.log("running " + pos + "%");
              setProgress(pos);
            },
            error: (msg) => {
              console.log("error occurred: " + msg);
            },
          });
        }
        function setProgress(percent) {
          progressBar.value.style.width = percent + "%";
          progressBar.value.innerText = percent + "%";
        }
        </script>
        
        <template>
          <div class="Word">
            <input id="Button1" type="button" :disabled="buttonDisabled" value="生成Word文件" @click="ConvertFile()" />
            <div id="progressBarContainer">
                <div id="progressBar" ref="progressBar"></div>
            </div>
          </div>
        </template>
        
        <style scoped>
        #progressBarContainer {
          width: 500px;
          background-color: #e0e0e0;
          border-radius: 5px;
          padding: 3px;
          margin: 10px auto;
        }
        #progressBar {
          height: 20px;
          width: 0%;
          background-color: #76b900;
          border-radius: 5px;
          text-align: center;
          line-height: 20px;
          color: white;
        }
        </style>
        
        上次更新: 2024/11/20, 16:35:49
        PageOffice | Copyright © 2013-2025 卓正软件 京ICP备12010902号-2 京公网安备 11010502019270号
        • 跟随系统
        • 浅色模式
        • 深色模式
        • 阅读模式