根据word模板生成word和PDF

根据word模板生成word和PDF

需求:有一个固定的合同模板,在vue前台填写指定的信息,替换合同模板指定的内容

我们使用的默认模板内容如图:

image-20230425111135868

我们在前端填写的字段就是合同名称、项目名称和项目金额,vue将这些内容填写到name、project、money字段,进行替换。

数据库表内容:(仅作为测试demo使用,需根据具体需求更改)

image-20230425111232459

前端界面:

路径字段不应该展示,这里只是为了演示方便
请添加图片描述

点击合同签订按钮,跳转字段填写界面
请添加图片描述

这里填写的信息会传递到后台,进行替换,并且把替换后的word以及pdf路径生成到wordpath和pdfpath字段里,进而实现下载功能。

前台代码:(基础信息查询界面不再展示,只展示)

<template>
  <div class="app-container">
    <el-card class="box-card">
<h1 style="text-align: center">生成合同信息</h1>
        <el-form ref="form" :model="form" :rules="rules" label-width="80px">
          <el-form-item label="名称" prop="hname">
            <el-input v-model="form.hname" placeholder="请输入名称" />
          </el-form-item>
          <el-form-item label="项目名" prop="project">
            <el-input v-model="form.project" placeholder="请输入项目名" />
          </el-form-item>
          <el-form-item label="金额" prop="money">
            <el-input v-model="form.money" placeholder="请输入金额" />
          </el-form-item>
          <el-form-item label="备注" prop="note">
            <el-input v-model="form.note" placeholder="请输入备注" />
          </el-form-item>
<div style=" text-align: right;">
    <el-button @click="updateForMation">提交信息</el-button>
  <el-button @click="wordxiazai">word下载</el-button>
  <el-button @click="pdfxiazai">pdf下载</el-button>
</div>
        </el-form>
    </el-card>
  </div>
</template>
<script>
  import { getClean, uploadFile,updateFile } from "@/api/module/gs/details";
  import {  listFilepdf, getFilepdf, delFilepdf, addFilepdf, updateFilepdf} from "@/api/project/filepdf";
  export default {
    data() {
      return {
        // 遮罩层
        loading: true,
        // 选中数组
        ids: [],
        // 非单个禁用
        single: true,
        // 非多个禁用
        multiple: true,
        // 显示搜索条件
        showSearch: true,
        // 总条数
        total: 0,
        // pdf信息表格数据
        filepdfList: [],
        // 弹出层标题
        title: "",
        // 是否显示弹出层
        open: false,
        // 查询参数
        queryParams: {
          pageNum: 1,
          pageSize: 10,
          hname: null,
          project: null,
          money: null,
          wordpath: null,
          pdfpath: null,
          note: null,
          note1: null,
          note2: null,
          note3: null,
          note4: null,
          note5: null,
          note6: null,
          note7: null,
          note8: null
        },
        // 表单参数
        form: { hname: '',
          project: '',
          money: '',
          wordpath: '',
          pdfpath: '',
          note: null,
          note1: null,
          note2: null,
          note3: null,
          note4: null,
          note5: null,
          note6: null,
          note7: null,
          note8: null},
        // 表单校验
        rules: {
        }
      };
    },
    created() {
      const id = this.$route.query.id;
      console.log(id)
      if (id) {
        // 获取表详细信息
        getFilepdf(id).then(response => {
          this.form = response.data;
        });
      }
    },
    methods: {
      /** 查询pdf信息列表 */
      getList() {
        this.loading = true;
        listFilepdf(this.queryParams).then(response => {
          this.filepdfList = response.rows;
          this.total = response.total;
          this.loading = false;
        });
      },
        //点击提交信息按钮将字段信息传递到后台
      updateForMation(){
        updateFile(this.form).then(response => {
        });
      },
      wordxiazai(){
         //下载功能:重点url就是word的路径的字段值
         var name = this.pdfpath;
          var url = this.form.wordpath;
        var suffix = url.substring(url.lastIndexOf("."), url.length);
          const a = document.createElement('a')
          a.setAttribute('download', name )
          a.setAttribute('target', '_blank')
          a.setAttribute('href', url)
          a.click()
      },
      pdfxiazai(){
          //下载功能:重点url就是pdf的路径的字段值
        var name = this.pdfpath;
        var url = this.form.pdfpath;
        var suffix = url.substring(url.lastIndexOf("."), url.length);
        const a = document.createElement('a')
        a.setAttribute('download', name )
        a.setAttribute('target', '_blank')
        a.setAttribute('href', url)
        a.click()

      }
    }
  }
</script>
//js连接后台路径,另一个"@/api/project/filepdf"不写了
export function updateFile(data) {
  return request({
    url: '/project/api/process/',
    method: 'post',
    data: data,
  })
}

后台代码:

这段代码的大致流程是:

  1. 接收前端传递过来的Filepdf对象,其中包含了Word文件的路径、姓名、项目名称和金额等信息。
  2. 将Word文件读取为XWPFDocument对象,遍历其中的所有段落,并判断是否包含需要替换的文本串,如果包含则进行文本替换。
  3. 将替换后的XWPFDocument写入到新的Word文件中(命名方式为"word_当前时间戳.docx")。
  4. 将新生成的Word文件读取为另一个XWPFDocument对象,然后将其转换为PDF格式,并将PDF输出到新的文件中(命名方式为"pdf_当前时间戳.pdf")。
  5. 将新生成的Word和PDF文件的访问路径(“http://127.0.0.1:9300/statics/具体名称”)分别设置到Filepdf对象的Wordpath和Pdfpath字段中。
  6. 更新Filepdf对象,并返回操作成功的信息。
 // 文件处理接口
    @PostMapping("/process")
    public AjaxResult processFile(@RequestBody Filepdf filepdf) throws IOException {


        //接收到前台传递过来的filepdf
        //把 filepdf的Wordpath字段设置为模板的路径
        filepdf.setWordpath("D:\\YinHe-Yqgbathe\\ruoyi-modules\\ruoyi-project\\src\\main\\java\\com\\ruoyi\\project\\module\\gs\\template.docx");
        //wordfilePath设置为模板的路径
        String wordfilePath = filepdf.getWordpath();
        //声明fis,以字节流的形式读取文件,fis 代表一个 FileInputStream 对象,它指向要读取的 Word 文件。
        FileInputStream fis = new FileInputStream(wordfilePath);
        //创建一个 XWPFDocument 实例,该实例与指定的 Word 文件建立了连接,XWPFDocument 是一个用于处理 .docx 文件的类
        XWPFDocument document = new XWPFDocument(fis);
        //使用 for 循环遍历 XWPFDocument 中的所有段落
        for (XWPFParagraph paragraph : document.getParagraphs()) {
        //使用 XWPFParagraph 类中的 getParagraphText() 方法来获取当前处理的段落中包含的文本内容
            String paragraphText = paragraph.getParagraphText();
            // 判断该段落中是否包含需要替换的文本串,因为我们要替换name,project,money,具体根据需求更改
            if (paragraphText.contains("name") || paragraphText.contains("project") || paragraphText.contains("money")) {
        //使用while是为了替换每一个,防止漏掉
                boolean foundMatch = true;
                while (foundMatch) {
                    foundMatch = false;
                    //使用 XWPFParagraph 类中的 getRuns() 方法获取当前处理的段落中包含的所有文本样式 Run
                    for (XWPFRun run : paragraph.getRuns()) {
                        //调用 getText(int pos) 方法可以获取该文本样式 Run 中从指定位置(pos)开始的所有文本信息,并将其作为一个字符串返回
                        String runText = run.getText(0);
                        //以下三个if是具体替换,eg.如果有name就替换为filepdf.getHname(),就是前端接受的内容
                        if (runText != null && runText.contains("name")) {
                            runText = runText.replaceFirst("name", filepdf.getHname());
                            run.setText(runText, 0);
                            foundMatch = true;
                        }
                        if (runText != null && runText.contains("project")) {
                            runText = runText.replaceFirst("project", filepdf.getProject());
                            run.setText(runText, 0);
                            foundMatch = true;
                        }
                        if (runText != null && runText.contains("money")) {
                            runText = runText.replaceFirst("money", filepdf.getMoney());
                            run.setText(runText, 0);
                            foundMatch = true;
                        }
                    }
                }
            }
        }
        //关闭FileInputStream
        fis.close();
        //设置path1为D:/ruoyi/uploadPath,因为若依默认存储为D:/ruoyi/uploadPath,可以根据配置文件进行更改
        String path = "D:/ruoyi/uploadPath";
        //拼接具体名称,按照时间命名,并且存储到相应位置
        String newwordFilePath = path + "/word_" + System.currentTimeMillis() + ".docx";
        FileOutputStream fos = new FileOutputStream(newwordFilePath);
        document.write(fos);
        fos.close();

        XWPFDocument doc = new XWPFDocument(new FileInputStream(newwordFilePath));// docx
        //转为pdf
        // 创建输出流,设置名称
        String newPdfFilePath = path + "/pdf_" + System.currentTimeMillis() + ".pdf";

        String outputPDFFiles = newPdfFilePath; // 输出的.pdf文件路径
        FileOutputStream foss = new FileOutputStream(outputPDFFiles);

        PdfOptions options = PdfOptions.create();
        // 将 .docx 转换为 .pdf
        PdfConverter.getInstance().convert(doc, foss, options);

        // 关闭输出流
        foss.close();

        System.out.println("转换完成");

        //因为前端不可以下载绝对路径,所以要拼接成http://127.0.0.1:9300/statics/***的形式,***为具体名称(D:/ruoyi/uploadPath后的名称)

        //设置wordpath字段
        int index = newwordFilePath.lastIndexOf("/");
        String q = newwordFilePath.substring(index);

        filepdf.setWordpath("http://127.0.0.1:9300/statics" + q);
        //设置pdfpath字段
        int index1 = newPdfFilePath.lastIndexOf("/");
        String q1 = newPdfFilePath.substring(index1);

        filepdf.setPdfpath("http://127.0.0.1:9300/statics" + q1);
        // 执行更新
        filepdfService.updateFilepdf(filepdf);
        return AjaxResult.success();

    }

注:需要在pom.xml中导入指定依赖,内容为:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.15</version>
</dependency>

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.13</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.15</version>
</dependency>

<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
    <version>1.0.6</version>
</dependency>

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>xmpbox</artifactId>
    <version>2.0.13</version>
</dependency>

<dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
    <version>1.0.6</version>
</dependency>

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>xmpbox</artifactId>
    <version>2.0.13</version>
</dependency>
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大高帅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值