Browse Source

断点续传

xiaoqiao 3 months ago
parent
commit
3218b7ef40

BIN
3.pdf


+ 80 - 1
src/main/java/com/bowintek/smartsearch/controller/WellInfoController.java

@@ -198,7 +198,7 @@ public class WellInfoController {
         return RespGenerstor.success(wellInfoService.selectoilWaterDailyList(commonWellNameList));
     }
 
-    @GetMapping("/downFile")
+    /*@GetMapping("/downFile")
     public void downFile(HttpServletResponse response, Integer isShow, String filePath, String fileName) throws Exception {
         Map<String, String> getParams = new HashMap<>();
         getParams.put("fileName", fileName);
@@ -233,6 +233,85 @@ public class WellInfoController {
             os.close();
         }
         log.info("下载完成~~~~");
+    }*/
+    @GetMapping("/downFile")
+    public void downFile(HttpServletResponse response,@RequestHeader(value = "Range", required = false) String range, Integer isShow, String filePath, String fileName) throws Exception {
+        Map<String, String> getParams = new HashMap<>();
+        getParams.put("fileName", fileName);
+        getParams.put("filePath", filePath);
+        String watermarkText = accountService.getUserByUserID(accountService.getLoginUserID()).getName() + " " + dateUtils.dateToStr(new Date());
+        getParams.put("isShow", "0");//(isShow != null && 1 == isShow) ? "1":"0");
+        getParams.put("watermarkText", watermarkText);
+        System.out.println("downFile getParams:" + getParams);
+
+        String reData =test2();
+        byte[] bytes = Base64.getMimeDecoder().decode(reData);
+
+        if (isShow != null && 1 == isShow) {
+            //如果是预览需要把doc转docx,xls转xlsx,前端预览插件不支持这两种格式
+            if (fileName.toLowerCase().endsWith(".doc")) {
+                bytes = doc2Docx(bytes);
+            } else if (fileName.toLowerCase().endsWith(".xls")) {
+                bytes = xls2pdf(bytes);
+            }
+        }
+        // 解析 Range 请求头
+        int fileSize = bytes.length;
+        String[] ranges = range.substring(6).split("-");
+        int start = Integer.parseInt(ranges[0]);
+        int end = ranges.length > 1 && !ranges[1].isEmpty() ? Integer.parseInt(ranges[1]) : fileSize - 1;
+
+        if (end > fileSize - 1) {
+            end = fileSize - 1;
+        }
+        bytes =getByteRange(bytes,start,end);
+        response.setContentType("multipart/form-data;charset=UTF-8");
+        response.addHeader("Content-Disposition",
+                "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));// 设置文件名
+        response.setHeader("Content-Length", String.valueOf(bytes.length));
+        response.setHeader("content-range", "bytes " + start + "-" + end + "/" + fileSize);
+
+        OutputStream os = response.getOutputStream();
+        os.write(bytes);
+
+        if (null != os) {
+            os.flush();
+            os.close();
+        }
+        log.info("下载完成~~~~");
+    }
+    public  byte[] getByteRange(byte[] data, int start, int end) {
+
+        // 创建新数组以存储结果
+        int length = end - start + 1;
+        byte[] result = new byte[length];
+
+        // 复制数据到新数组
+        System.arraycopy(data, start, result, 0, length);
+
+        return result;
+    }
+    public String test2() throws Exception {
+        String filePath = System.getProperty("user.dir") + File.separator + "3.pdf"; // 替换为你的文件路径
+        File file = new File(filePath);
+        long fileSize = file.length();
+        if (fileSize > Integer.MAX_VALUE) {
+            System.out.println("file too big...");
+            return null;
+        }
+        FileInputStream fi = new FileInputStream(file);
+        byte[] buffer = new byte[fi.available()];
+        int offset = 0;
+        int numRead = 0;
+        while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
+            offset += numRead;
+        }
+        // 确保所有数据均被读取
+        if (offset != buffer.length) {
+            throw new IOException("Could not completely read file " + file.getName());
+        }
+        fi.close();
+        return Base64.getMimeEncoder().encodeToString(buffer);
     }
 
     @GetMapping("/downFileImage")

+ 64 - 9
vue/src/components/basic/file-preview/index.vue

@@ -21,7 +21,7 @@
 </template>
 <script lang="ts">
 import {defineComponent, ref} from 'vue';
-import {message as $message} from "ant-design-vue/lib/components";
+//import {message as $message} from "ant-design-vue/lib/components";
 //引入VueOfficeDocx组件
 import VueOfficeDocx from '@vue-office/docx'
 import '@vue-office/docx/lib/index.css'
@@ -29,7 +29,10 @@ import VueOfficePdf from '@vue-office/pdf'
 //引入VueOfficeExcel组件
 import VueOfficeExcel from '@vue-office/excel'
 import '@vue-office/excel/lib/index.css'
-import {handleloadByGet} from "@/utils/downloadFile";
+//import {handleloadByGet} from "@/utils/downloadFile";
+import axios from 'axios';
+import {ACCESS_TOKEN_KEY} from "@/enums/cacheEnum";
+import {Storage} from '@/utils/Storage';
 
 export default defineComponent({
   name: 'b-file-preview',
@@ -50,17 +53,17 @@ export default defineComponent({
     const previewUrl = ref<any>();
     const fileSuffix = ref("");
 
-    function loadFile() {
-      let fileName = stripHtmlTags(props.fileName);
+    async function loadFile() {
+      /*let fileName = stripHtmlTags(props.fileName);
       let filePath = stripHtmlTags(props.filePath);
       fileSuffix.value = fileName?.substring(fileName?.lastIndexOf('.') + 1).toLowerCase();
 
       if (props.accept?.indexOf(fileSuffix.value) < 0) {
         $message.error("不支持预览的文件格式!");
         return;
-      }
+      }*/
       spinning.value = true;
-      handleloadByGet("/api/wellInfo/downFile", {
+      /*handleloadByGet("/api/wellInfo/downFile", {
         isShow: 1,
         fileName: fileName,
         filePath: filePath
@@ -80,9 +83,60 @@ export default defineComponent({
         //previewUrl.value = new Blob([res.data], {type: "application/octet-stream"});
         // previewUrl.value = res.data;
 
-      })
+      })*/
+      await downloadFileInChunks();
+    }
+
+    async function downloadFileInChunks(chunkSize = 1024 * 1024) {
+      let fileName = stripHtmlTags(props.fileName);
+      let filePath = stripHtmlTags(props.filePath);
+      fileSuffix.value = fileName?.substring(fileName?.lastIndexOf('.') + 1).toLowerCase();
+
+      let offset = 0;
+      let totalLength: any = chunkSize;
+      const chunks: any[] = [];
+      const token = Storage.get(ACCESS_TOKEN_KEY);
+      while (true) {
+        const headers = {Authorization: token};
+        headers['Range'] = `bytes=${offset}-${Math.min(offset + chunkSize - 1, totalLength - 1)}`;
+
+        try {
+          const response = await axios("/api/wellInfo/downFile", {
+            method: 'GET',
+            params: {
+              isShow: 1,
+              fileName: fileName,
+              filePath: filePath
+            },
+            responseType: 'arraybuffer',
+            headers,
+            timeout: 10000,
+            onDownloadProgress: (progressEvent) => {
+              console.log('Chunk download progress:', progressEvent);
+            }
+          });
+
+          const contentRange: string = response.headers['content-range'];
+          totalLength = response.headers['content-length'];
+          if (contentRange) {
+            totalLength = parseInt(contentRange.split('/').pop() || "0", 10);
+          }
+          chunks.push(response.data);
+          offset += chunkSize;
+
+          if (offset >= totalLength) break;
+        } catch (error) {
+          console.error('Error downloading chunk:', error);
+          throw error;
+        }
+      }
+
+      previewUrl.value = new Blob(chunks);
+      visible.value = true;
+      spinning.value = false;
     }
-   function  changeHandle(event) {
+
+    function changeHandle(event) {
       let file = event.target.files[0]
       let fileReader = new FileReader()
       fileReader.readAsArrayBuffer(file)
@@ -90,6 +144,7 @@ export default defineComponent({
         previewUrl.value = fileReader.result;
       }
     }
+
     function stripHtmlTags(htmlString: string): string {
       return htmlString.replace(/<[^>]+>/g, '');
     }
@@ -108,7 +163,7 @@ export default defineComponent({
       visible, fileSuffix,
       previewUrl,
       loadFile,
-      rendered, renderedError,changeHandle,
+      rendered, renderedError, changeHandle,
       spinning,
     };
   }