目录

Vue-采用blob下载后端返回的pdf流或者excel流文件乱码问题解决方案

Vue 采用blob下载后端返回的pdf流或者excel流文件乱码问题解决方案

流文件乱码问题解决方案
    • 问题介绍:

      打开或者预览全是乱码。预览pdf如下图:

      https://i-blog.csdnimg.cn/blog_migrate/24febba6e4a38fffb53889338a223539.png

      解决办法:

      1. 后端接口返回的blob文件流,你下载下来的文件是乱码的?

      解决办法 :让你的后端设置流的编码为utf-8。请跟后端大佬说,一定要给blob格式的文件流。

      2. 后端返回的blob文件流,并且已经设置了utf-8,但是你接受的接口返回值,依然是乱码?

      解决办法: 肯定没有设置 responseType: “arraybuffer”。

      一、前端方式解决:

      预览pdf如下图:

    • https://i-blog.csdnimg.cn/blog_migrate/78b0f8e2ec3894c08e6e24ef0ccca605.png

      这个charset=utf-8一定要添加,不添加可能乱码,如果后台返回的格式里面有,那就没必要了!
      代码:
      const binaryData = []
      binaryData.push(res.data)
      // 获取blob链接
      this.pdfUrl = window.URL.createObjectURL(new Blob(binaryData, { type: ‘application/pdf;charset=utf-8’ }))
      window.open(this.pdfUrl)

      pdf下载如下图:

      https://i-blog.csdnimg.cn/blog_migrate/3379924b6864e5182f4e3d78680e89f3.png

      代码如下:
      this.pdfUrl = window.URL.createObjectURL(new Blob([res.data], { type: application/pdf;charset=utf-8 }))
      const fname = 合同 // 下载文件的名字
      const link = document.createElement(‘a’)
      console.log(this.pdfUrl)
      link.href = this.pdfUrl
      link.setAttribute(‘download’, fname)
      document.body.appendChild(link)
      link.click()
      代码:
      export default {
        name: 'pdf',
        async mounted () {
          this.pdfHeight = '100%'
          this.ewpId = this.$route.query.ewpId
          this.pdfUrl = await this.getPdf(this.baseUrl + '/rcgl/TalPolicy/onlinePreview?id=' + this.ewpId + '&BDSOFT-TOKEN=' + this.userToken)
        },
        data () {
          return {
            baseUrl: process.env.VUE_APP_BASE_API,
            pdfUrl: '',
            ewpId: '',
            pdfHeight: 0
          }
        },
        methods: {
          async getPdf (url) {
            // eslint-disable-next-line no-undef
            const data = await axios.get(url, {
              responseType: 'arraybuffer'
            })
            const blob = new Blob([data.data], { type: 'application/pdf' })
            return URL.createObjectURL(blob)
          }
        },
        computed: {
          ...mapState('global', {
            userToken: state => state.token,
            unitId: state => state.userInfo.b00
          })
        }
      }

      二、后端方式解决:

    • 因为有的文件可能含有中文,因此在文件传输过程中会涉及到编码问题。后台的代码需要将输出流的编码格式设置为UTF-8。

      response.setContentType("application/octet-stream;charset=UTF-8");

      另一种方式就是:(优先级最高)

      response.setCharacterEncoding("UTF-8"); // 设置文件流编码格式 不然中文会乱码

      这样前端接收到输出流的时候是以Blob类型接收的。

      代码:
       @Override
          public void onlinePreview(String filePath, HttpServletResponse response) throws Exception {
              //获取文件类型
              String[] str = filePath.split("\");
              if (str.length == 0) {
                  throw new Exception("文件格式不正确");
              }
              String suffix = str[str.length - 1];
              if (!suffix.equals("txt") && !suffix.equals("doc") && !suffix.equals("docx") && !suffix.equals("xls")
                      && !suffix.equals("xlsx") && !suffix.equals("ppt") && !suffix.equals("pptx")) {
                  throw new Exception("文件格式不支持预览");
              }
              InputStream in = FileConvertUtil.convertLocaleFile(filePath, suffix);
              response.setContentType("application/octet-stream;charset=UTF-8");
              OutputStream outputStream = response.getOutputStream();
              //创建存放文件内容的数组
              byte[] buff = new byte[1024];
              //所读取的内容使用n来接收
              int n;
              //当没有读取完时,继续读取,循环
              while ((n = in.read(buff)) != -1) {
                  //将字节数组的数据全部写入到输出流中
                  outputStream.write(buff, 0, n);
              }
              //强制将缓存区的数据进行输出
              outputStream.flush();
              //关流
              outputStream.close();
              in.close();
      
          }

      三、文件预览实现

      controller 代码

      @ApiOperation(value = "系统文件在线预览", notes = "系统文件在线预览")
          @GetMapping(Urls.TalPolicy.onlinePreview)
          public void onlinePreview(String id, HttpServletResponse  response) throws Exception {
              Assert.notNull(id, "用户id不能为空");
              TalPolicy Policy = TalPolicyService.getAllById(id);
              if (Policy != null) {
                  String fid = Policy.getFileid();
                  if (!StringUtils.isEmpty(fid)) {
                      SAttachmentFile sAttachmentFile = fileManagerService.getById(fid);
                      String filePath = sAttachmentFile.getFilepath();
                      TalPolicyService.onlinePreview(filePath, response);
                  }
              }
          }

      service 代码

      void onlinePreview(String filePath, HttpServletResponse  response) throws Exception;

      serviceimpl代码

       @Override
          public void onlinePreview(String filePath, HttpServletResponse response) throws Exception {
              //获取文件类型
              String[] str = filePath.split("\");
              if (str.length == 0) {
                  throw new Exception("文件格式不正确");
              }
              String suffix = str[str.length - 1];
              if (!suffix.equals("txt") && !suffix.equals("doc") && !suffix.equals("docx") && !suffix.equals("xls")
                      && !suffix.equals("xlsx") && !suffix.equals("ppt") && !suffix.equals("pptx")) {
                  throw new Exception("文件格式不支持预览");
              }
              InputStream in = FileConvertUtil.convertLocaleFile(filePath, suffix);
              response.setContentType("application/octet-stream;charset=UTF-8");
              OutputStream outputStream = response.getOutputStream();
              //创建存放文件内容的数组
              byte[] buff = new byte[1024];
              //所读取的内容使用n来接收
              int n;
              //当没有读取完时,继续读取,循环
              while ((n = in.read(buff)) != -1) {
                  //将字节数组的数据全部写入到输出流中
                  outputStream.write(buff, 0, n);
              }
              //强制将缓存区的数据进行输出
              outputStream.flush();
              //关流
              outputStream.close();
              in.close();
      
          }

      工具类及其他详情步骤参考:

      四、点击按钮打开新窗口预览

       <el-table-column
                label="操作"
                align="center"
                width="120px">
                <template slot-scope="scope">
                  <div style="line-height: 1; font-size: 0;">
                    <el-button size="mini" @click="prewelRow(scope.row)">查看</el-button>
                  </div>
                </template>
              </el-table-column>
      data () {
          return {
            baseUrl: process.env.VUE_APP_BASE_API
            }
            },
      computed: {
          ...mapState('global', {
            userToken: state => state.token,
            unitId: state => state.userInfo.b00
          })
        }
      methods: {
       prewelRow: async function (row) {
            const pdfUrl = await this.getPdf(this.baseUrl + '/rcgl/TalPolicy/onlinePreview?id=' + row.recordid + '&TOKEN=' +   	   		this.userToken)
            window.open(pdfUrl)
          },
      
      }