Springboot + Vue 下载Word、PDF文档并保留内部格式

相对于上传,下载时复杂的地方就是文件中文名称乱码

前端

            <el-button @click="clickCall('handleExport', scope,index)">导出el-button>
 // 文件下载操作
    handleExport(row) {
      axios
        .get(**********master/proj/exportContract?id=" + row.id, {
          responseType: "blob",
          headers: { Authorization: Cookie.get("**********") },
        })
        .then((response) => {

       // 获取后端返回的文件名
        const contentDisposition = response.headers["content-disposition"];
        const fileNameMatch = contentDisposition.match(/filename="(.+)"/);
        console.log(fileNameMatch[1])
        const fileName = this.binaryStringToString(fileNameMatch[1])
        // 创建URL并模拟点击下载链接
        const url = window.URL.createObjectURL(new Blob([response.data]));
        const link = document.createElement("a");
        link.href = url;
        link.setAttribute("download", fileName);
        document.body.appendChild(link);
        link.click();
        })
        .catch((err) => {
          this.$message.error(`数据导出失败,${err.message}`);
        });
    },
    binaryStringToString(binaryStr){
    	  const binaryBytes = binaryStr.split(" ");
 		 const bytes = binaryBytes.map(binaryByte => parseInt(binaryByte, 2));
 		 const utf8String = new TextDecoder().decode(new Uint8Array(bytes));
 		 return utf8String;
    },

后端

    @ApiOperation("导出合同文件")
    @GetMapping("exportContract")
    public ResponseEntity<Resource> exportData(@RequestParam(value="id")Integer id) throws Exception {
        return projectService.exportData(id);
    }
      @Override
    public ResponseEntity<Resource> exportData(Integer id) throws IOException {
        Project project = projectRepo.getById(Long.valueOf(id));
        if (project.getContactFile().isBlank()) {
            throw (new BizExceptEntityNotFound("文件不存在!"));
        }
        File file = new File(project.getContactFile());
        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

        String binaryString  = stringToBinary(project.getContactFile().split("/")[2]);
        System.out.println(project.getContactFile().split("/")[2]);
        System.out.println(binaryString );
        System.out.println(binaryToString(binaryString ));
        headers.setContentDisposition(ContentDisposition.parse("attachment; filename=" +binaryString  ));
        return new ResponseEntity<>(new FileSystemResource(file), headers, HttpStatus.OK);
    }

    /**
     * 字符串转8位一组的二进制字符串
     * @param inputString
     * @return
     */
    public static String stringToBinary(String inputString) {
        byte[] utf8Bytes = inputString.getBytes(StandardCharsets.UTF_8);
        StringBuilder binaryStr = new StringBuilder();
        for (byte b : utf8Bytes) {
            String binaryByte = String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');
            binaryStr.append(binaryByte).append(" ");
        }
        return binaryStr.toString().trim();
    }

        public static String binaryToString(String binaryStr) {
            StringBuilder result = new StringBuilder();
            String[] binaryBytes = binaryStr.split(" ");
            byte[] bytes = new byte[binaryBytes.length];
            for (int i = 0; i < binaryBytes.length; i++) {
                bytes[i] = (byte) Integer.parseInt(binaryBytes[i], 2);
            }
            result.append(new String(bytes, StandardCharsets.UTF_8));
            return result.toString();
        }

我采用的是把文件名转成二进制传输,再转化回去。最后没乱

Springboot + Vue 下载Word、PDF文档并保留内部格式_第1张图片

你可能感兴趣的:(spring,boot,vue.js,word)