PDF预览、上传文件【springboot+vue3】

PDF开发

一、文件预览

1、业务需求

​ 一笔订单关联多个文件,要求点击查看按钮即可预览对应的文件

2、完整代码

前端代码:

  • templateonCheck点击事件,预览文件

    <template slot="actionSlot" slot-scope="text,record">
    	<div>
            <xxx-button
                @click="onCheck(record)"
                type="primary"
                size="small"
             >
                {{ $tt('table.check') }}
        	</xxx-button>
        </div>
    </template>
    
  • javascript:跳转浏览器预览文件

    export default class XXX extends Vue {
        //查看方法
        public onCheck(row:orderRelFile) {
        this.data.id = row.id;//获取选中行id(与影像文件关联的订单id)
        getDownloadFile(this.data).then((res) => {//axios请求后端
          const binaryData: any = [];
          binaryData.push(res.data);//响应的数据添加进数组中
          let str = row.fileName;//获取选中行的文件名
          let nameValue = '';
          let url = null;
          if (str.length > 1){
            nameValue = str.substring(str.length - 3);//截取文件名后三位字符串
            if (nameValue == 'pdf') {//判断文件是否为pdf格式
              if (window.URL.createObjectURL !== undefined) {//文件流转化为url地址,获取Blob连接
                url = window.URL.createObjectURL(
                  new Blob(binaryData, { type: 'application/pdf'})//Blob中的数组内容的MIME类型
                );
                window.open(url, 'blank');//浏览器跳转地址为url的新页面                        		 }
              }
            }
            if (nameValue == 'jpg' || nameValue == 'png') {//判断文件是否为图片格式
              if (window.URL.createObjectURL !== undefined) {
                url = window.URL.createObjectURL(
                  new Blob(binaryData, { type: 'image/jgeg'})
                );
                window.open(url, '_blank');
              }
            }
          }
        });
      }
    }
    
  • typescript:发送axios请求后端接口

    /**预览pdf */
    export const getDownloadFile = (params: any) => {
        return axiosIns.request({
            url: '/orderrelfile/downloadRelFile',
            method: 'post',
            params: params,
            headers: {
                'Content-Type': 'appliacation/json',
            },
            responseType: 'blob',
        });
    };
    

后端代码:从对象存储服务器读取文件,返回文件流

@PostMapping(path = "/downloadRelFile")
@SysLogb
public void previewPdf(HttpServletRequest request, HttpServletResponse response,String id){
  //接收前端传参,选中行id
    OrderRelFile relFile = orderRelFileService.load(id);//查找订单id对应的文件
    String filePath = relFile.getFilePath();
    String fileName = relFile.getFileName();
    S3Object s3Objtect = null;
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try{
      s3Object = downloadService.readObject(bucketName, filePath);//从流中读取并返回该对象
      request.setCharacterEncoding("UTF-8");
      response.setContentType(request.getSession().getServletContext().getMimeType(fileName));
      bos = new BufferedOutputSream(response.getOutputStream());
      String agent = request.getHeader("user-agent");
      if (agent.contains("MSIE")){
          fileName = URLEncoder.encode(fileName,"utf-8");
          fileName = fileName.replace("+"," ");
      }else {
          String type = response.getHeader("use-down-type");
          if (type != null && agent.contains("Firefox")) {
              fileName = new String(fileName.getBytes("utf-8"), StandardCharsets.ISO_8859_1);
          }else {
              fileName = URLEncoder.encode(fileName, "utf-8");
          }
      }
        response.setHeader("Content-Disposition", "inline; filename=" + fileName);
        response.setContentType("application/pdf;charset=UTF-8");
        response.setHeader("Content-Length",String.valueOf(s3Object.getObjectMetadata().getContentLength()));
        bis = new BufferedInputStream(s3Object.getObjectContent());
        byte[] buff = new byte[204800];
        int bytesRead;
        while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
            bos.write(buff, 0, bytesRead);
        }
    }catch (IOException e){
        throw new ServiceException("SYSE305");
    }finally {
        try {
            if (null != s3Object) {
                s3Object.close();
            }
            if (bis != null) {
                bis.close();
            }
            if (bos != null) {
                bos.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
3、踩坑分析

问题:直接使用浏览器预览对象存储的文件,url会直接暴露在地址栏,泄露隐私造成安全隐患

解决:后端发送文件流,前端接收文件流并转化url地址获取Blob连接

二、文件导入

1、业务需求

​ 一笔订单关联多个影像文件,要求点击导入文件按钮即可导入对应的影像文件

2、完整代码

前端代码:

  • template:弹出上传操作弹窗
<xxx-modal
    title="上传文件"
    v-model="visibleuploadFile"//绑定visibleuploadFile控制是否显示弹窗
    @ok="onOkuploadFile"//弹窗确认按钮点击事件
>
    <xxx-upload-tool
        :format="['jpg','png','txt','xlsx','docx','doc','zip','7z']"//限制上传文件格式
        :uploadUrl="uploadData"//uploadData计算属性调用后端接口
        :multiple="true"
        maxSize="10000"
     ></xxx-upload-tool>
</xxx-modal>
  • javascript:上传文件同时携带参数
export default class XXX extends Vue {
    public visibleuploadFile = false;//设置弹窗默认不显示
	public orderId = '';
//导入弹窗
	public uploadFileModal() {
        try {
            this.selectedRowKeys.map((id) => {//获取选中行id
                this.orderId = id;
            });
        } catch (e) {
            console.log(e);
        }
        this.visibleuploadFile = true;//显示弹窗
	}
//导入弹窗确认
	public onOkuploadFile() {
    	location.reload();//刷新当前页面
	}
//自定义按钮
	get tableButtons():FormButton[] {
        return [
            {
                type:'primary',
                icon:'upload',
                clickFn: {
                    functionName:'uploadFileModal',//绑定操作uploadFileModal方法
                    componentName:this.$options.name,
                },
                text:'文件导入',
                disabled:this.selectedRowKeys.length === 0,//未选中数据按钮置灰
            },
        ];
	}
//返回后端接口url
	get uploadData() {
    	return 'orderinfo/upload?orderId=' + this.orderId;//请求后端接口并传入参数
	}
}

后端代码:本地上传文件到对象存储服务器,文件信息落库,重复信息更新

/**
* @description 导入文件
*/
@PostMapping(value = "/upload")
public List<Map<String,Object>> upLoad(HttpServletRequest request, @RequestParam("file"))MultipartFile file,@RequestParam(value = "orderId") String orderId) throws S3Exception,IOException {
    List<Map<String,Object>> list = new ArrayList<Map<String,Object>>()Map<String,Object> result = new HashMap<>();
    String fileName = file.getOriginalFilename();
    FileUploadValidator validator = FileUploadValidator.getInstance();
    File filePath = new File(videofilesParentPath + filename);
    if (!filePath.getParentFile().exists()) {
        filePath.getParentFile().mkdirs();
    }
    String key = filePath.getAbsolutePath();
    boolean validateFile = validator.isValidateFile(file.getBytes(),fileName,videofilesParentPath,1024 * 1024,null,request);
    if(validateFile) {
        file.transferTo(filePath.getAbsoluteFile());
        StopWatch stopWatch = new StopWatch("upLoadS3File:" + filePath);
        Map<String,String> userMetadataMap = new HashMap<String,String>();
        userMetadaMap.put("name",URLEncoder.encode("文件","UTF-8"));//自定义元数据
        logManager.MICROSERVICE_LOGGER.info("开始上传{}文件",filePath);
        stopWatch.start();
        try {
            s3UploadService.createLargeObjectWithKey(key,filePath,userMetadataMap);
        } catch (S3Exception s3Exception) {
            throw new SerciceException("SYSE302");
        }
        stopWatch.stop();
        logManager.MICROSERVICE_LOGGER.info("上传{}文件成功,耗时{}ms",filePath,stopWatch.getTotalTimeMillis());
        //上传对象存储服务器成功后,删除原来下载的目录
        boolean delete = filePath.delete();
        logManager.MICROSERVICE_LOGGER.info("删除{}文件是否成功{}",filePath,delete);
        
        //上传到对象存储服务器后,进行存储
        OrderInfo orderInfo = orderInfoService.load(orderId);
        String orderRelFileId = seqGeneratorUtil.getDateSequenceNo("BusiNo");
        String s3Url = s3Client.getAmazonS3Client().getUrl(s3Client.getBucketName(),key).toString();
        String orderNo = orderInfo.getOrderNo();
        OrderRelFile orderRelFile = OrderRelFile.builder()
            	.id(orderRelFileId)
            	.orderNo(orderNo)
            	.fileName(filename)
            	.filePath(key)//对象存储时路径相当于key值
            	.fullPath(s3Url)//直接可访问的http连接
            	.build();
        List<OrderRelFile> orderRelFiles = orderRelFilesService.findByOrderNo(orderInfo.getOrderNo());
        if (CollectionUtils.isEmpty(orderRelFiles)) {
            result.put("msg","该笔订单没有文件");
        }
        //存在重复数据即更新数据
        Boolean isDbHava = Booelean.FALSE;
        for(OrderRelFile relFile : orderRelFiles) {
            String relFileName = relFile.getFileName();
            if (relFileName.equals(fileName)) {
                isDbHava = Boolean.True;
                break;
            }
        }
        if (isDbHava) {
            orderRelFileService.update(orderRelFile);
        }else {
            orderRelFileService.update(orderRelFile);
        }
        logManager.MICROSERVICE_LOGGER.info("对象存储文件地址{}",s3Url);
        logManager.MICROSERVICE_LOGGER.info("存储{}文件成功",filePath);
        result.put("returnCode","success");
    }else {
        result.put("returnCode","fail");
        result.put("msg","文件检验失败");
    }
    list.add(result);
    return list;
}

@Value("${xxx.videofiles}")
public void setVideofilesParentPath(String vfPath) {
    videofilesParentPath = vfPath;
}
3、踩坑分析

问题:上传文件使用post请求无法携带参数

解决:上传组件中直接写uploadUrl请求后端接口无法携带参数,使用计算属性uploadData转化地址并传入参数,后端使用@RequestParam注解接收参数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring BootVue项目中实现PDF在线预览可以通过集成pdf.js库来实现。首先,您需要从官网下载pdf.js源码,并将其放入您的项目中。具体步骤如下: 1. 在官方网站下载pdf.js源码。 2. 将下载的源码放入您的Spring Boot项目中的某个目录中。 3. 打开viewer.html文件,您会注意到它会自动跳转到一个pdf文件。这个pdf文件是官方的示例文件。 4. 如果您只想打开一个特定的pdf文件,只需将官方示例文件替换为您自己的pdf文件。 5. 在viewer.js文件中搜索"defaultUrl",大约在第3500行左右。您可以找到类似上述代码的部分(注意:不同版本的pdf.js可能会略有差异)。 6. 只需更改"value"的值,即可实现预览您指定的pdf文件。 7. 如果您需要根据前端传递的不同值来响应不同的pdf文件,可以使用动态获取的方式来实现。 另外,如果希望使用浏览器自带的预览pdf功能,可以参考使用pdf.js的实现方式。但需要注意的是,某些浏览器可能不支持此功能,如360浏览器。您可以在我的博客中找到有关使用浏览器预览pdf的更多信息。 综上所述,您可以根据以上步骤在Spring BootVue项目中实现PDF在线预览。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [springboot+vue整合pdf.js实现预览pdf](https://blog.csdn.net/qq_14853853/article/details/111176085)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值