开发环境下只需要能够生成Pdf文件就算实现了功能,但是部署之后,在生产环境中,我才发现情况是客户端需要拿到生成的Pdf,而不是仅仅在服务端生成一个Pdf文件就完了。

根据我自己的解决方法,写个笔记。

一、前端代码

// 导出PDF
    exportPDF() {
      //数据构建,后端用map<String, Object>接收
      //准备参数
      const ePatientInfo = this.ePatientInfo;
      const results = this.results;
      axios.post("/api/ePatientInfo/exportPDF", {'ePatientInfo': ePatientInfo, 'results': results}, 
          //ArrayBuffer 是 JavaScript 中的一种数据类型,它表示一段固定长度的原始二进制数据缓冲区。
          {responseType:"arraybuffer",}).then(resp => {
        // 处理下载 PDF 的逻辑

        // 创建一个Blob对象,将从网络请求响应中获取到的数据(resp.data)作为参数传递给Blob构造函数
        // 同时指定该Blob对象的MIME类型为'application/octet-stream',表示它是一个字节流形式的数据,可用于传输各种二进制文件
        const blob = new Blob([resp.data], { type: 'application/octet-stream' });

        // 在文档对象模型(DOM)中创建一个<a>标签元素,通常用于创建超链接
        const link = document.createElement('a');

        // 设置<a>标签的'download'属性,属性值是由患者信息中的姓名(ePatientInfo.name)和就诊序列号(ePatientInfo.visitSerialNumber)拼接后再加上".pdf"组成的字符串
        // 这样设置后,当用户点击这个链接进行下载时,下载的文件名将以此字符串命名
        link.setAttribute('download', ePatientInfo.name + ePatientInfo.visitSerialNumber + ".pdf");

        // 通过window.URL.createObjectURL方法为创建的Blob对象生成一个临时的可访问的URL地址,并将这个地址设置为<a>标签的'href'属性
        // 使得该<a>标签指向这个由Blob对象生成的临时URL,以便后续能够通过点击这个链接来访问和下载Blob对象所代表的文件内容
        link.href = window.URL.createObjectURL(blob);

        // 将创建好的<a>标签元素添加到文档的<body>部分,使其成为页面DOM结构中的一部分
        // 这样用户在浏览器页面中就能看到这个下载链接(虽然可能看不到具体的样式,具体样式可根据后续的CSS设置来展现)
        document.body.appendChild(link);

        // 模拟用户点击刚刚添加到页面中的<a>标签,触发下载操作
        // 当点击这个链接时,浏览器会根据之前设置的'download'属性值来命名下载的文件,并从通过'href'属性指定的临时URL地址获取文件内容进行下载
        link.click();
          messageTip("导出PDF成功", "success");
      }).catch(err=>{
        messageTip(err,"error")
      })
    },

二、Controller代码

 //导出PDF
    @PostMapping(value = "/api/ePatientInfo/exportPDF")
    public ResponseEntity<FileSystemResource> exportPDF(@RequestBody Map<String, Object> map) {
        //调用service方法
        String fileName =ePatientInfoService.exportPDF(map);
        //硬编码,后期需要修改
        String filePath="D:/pdf/"+fileName;
        //以统一的方式访问不同类型的资源,如文件系统中的文件、类路径下的资源等
        FileSystemResource file = new FileSystemResource(filePath);
        //请求头
        HttpHeaders headers = new HttpHeaders();
        //Content-Disposition:attachment 浏览器将服务器返回的内容作为附件进行下载,而不是在浏览器内显示。
        //filename=用于指定下载附件的文件名。
       headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
       //"Content-Type":"application/octet-stream",内容类型标识:表示传输的内容是一个字节流,接收方并不知道这个字节流具体代表什么类型的文件或数据,它只是将其作为一系列连续的字节来处理。
        //这种内容类型具有很强的通用性,因为它没有对所传输的字节流进行明确的类型定义。
       headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
        return ResponseEntity.ok().headers(headers).body(file);
    }

三、service方法 

    @Override
    public String exportPDF(Map<String, Object> map){
        //使用合适的 JSON 处理库(如 Jackson 或 Gson)来正确地将 JSON 数据反序列化为目标类型,而不是依赖于手动的类型转换。
        Gson gson = new Gson();
        EPatientInfo epi = gson.fromJson(gson.toJson(map.get("ePatientInfo")), EPatientInfo.class);
        //TypeToken是 Google 的 Gson 库中的一个类,用于解决 Java 泛型类型擦除带来的问题,以便在运行时获取和处理具体的泛型类型信息。
        List<EExamResults> list = gson.fromJson(gson.toJson(map.get("results")), new TypeToken<List<EExamResults>>() {
        }.getType());
        //调用本类的PDF处理方法
        String fileName = null;
        try {
            fileName=pDfHandle(epi, list);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //返回一个文件名,供给controller下载用
        return fileName;
    }

四、生成Pdf的方法

生成PDF方法基本与之前的ITEXT7生成PDF文件一样(参见itext7使用),增加了把生成的文件名返回给调用者。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐