vue项目中下载后台给的文件zip格式的文件

本文介绍了一个使用Axios进行文件下载的方法。通过构造特定的URL并设置请求头,实现了从服务器获取文件并保存到本地的功能。文章详细展示了如何处理下载过程中可能出现的问题,并提供了完整的代码示例。

引用axios

import axios from 'axios'

得到下载文件的地址 拼接参数contractUrl方法

contractUrl(url data) {
    return url + (url.indexOf('?') < 0 ? '?' : '&') + this.splitData(data)
  }
   // 拆分数据
  splitData(data) {
    let url = ''
    for (let k in data) {
      if (data.hasOwnProperty(k) && data[k] != undefined) {
        let value = data[k] || ''
        url = url + '&' + k + '=' + encodeURIComponent(value)
      } else {
        url = url
      }
    }
    return url ? url.substring(1) : ''
  }
    let URLs = url
    let URLe = that.contractUrl(URLs, listQuery)

    axios({
      // 用axios发送post请求
      method: 'get',
      url: URLe, // 请求地址
      data: data, // 参数
      headers: {
        token: localStorage.getItem('token'),
        'Content-Type': 'application/json',
      },
      responseType: 'blob', // 表明返回服务器返回的数类据型
    })
      .then((res) => {
      //获取后台下载失败返回的信息
        const fileReader = new FileReader()
        if (res.data.type === 'application/json') {
          // 说明是普通对象数据,读取信息
          const fileReader = new FileReader()
          fileReader.onloadend = () => {
            const jsonData = JSON.parse(fileReader.result)
            // 后台信息
            that.$message.error(jsonData.message)
            setTimeout(() => {
              this.tableState = true
            }, 1000)
          }
          fileReader.readAsText(res.data)
        } else {
          const link = document.createElement('a')
          let blob = new Blob([res.data], { type: 'application/zip' })
          link.style.display = 'none'
          link.href = URL.createObjectURL(blob)
          const date = currentTime('')
          link.setAttribute('download', 'xx记录' + date + '.zip')
          document.body.appendChild(link)
          link.click()
          document.body.removeChild(link)
          setTimeout(() => {
            this.tableState = true
          }, 1000)
        }
        console.log(res)
      })
      .catch((error) => {
        that.$message.warning('暂无数据')
        setTimeout(() => {
          this.tableState = true
        }, 1000)
      })
<think>我们将在Vue项目中实现从ZIP压缩中读取ShapeFile并解析为GeoJSON格式。主要步骤如下: 1. 使用文件输入控件让用户选择ZIP文件2. 使用JSZip库解压ZIP文件,获取其中的.shp、.dbf等文件。 3. 使用shapefile库(shapefile-js)将ShapeFile解析为GeoJSON。 步骤详细说明: 1. 安装依赖:我们需要安装jszip和shapefile(或者使用shpjs,它通常含在shapefile库中)。 在项目中运行: ```bash npm install jszip shpjs ``` 2.Vue组件中,创建一个文件输入元素,用于选择ZIP文件。 3. 当用户选择文件后,使用JSZip读取ZIP文件,并查找其中的.shp和.dbf文件(通常还需要.prj文件,但GeoJSON不需要投影信息,所以.prj可选)。 4. 使用shpjs库的shp.parseZip方法(注意:shpjs库可以直接解析含shapefile的ZIP)来解析成GeoJSON。 注意:shpjs库的parseZip方法要求传入一个ArrayBuffer。因此,我们需要将用户选择的ZIP文件读取为ArrayBuffer。 但是,根据shpjs的文档,它可以直接接受一个ZIP文件的二进制数据(ArrayBuffer)并解析。所以我们可以这样做: - 使用FileReader读取文件为ArrayBuffer。 - 将ArrayBuffer传递给shpjs的parseZip方法。 5. 解析完成后,我们可以得到GeoJSON对象,然后可以在控制台打印或者在地图上显示等。 示例代码: 在Vue组件的模板部分添加一个input元素: ```html <template> <div> <input type="file" accept=".zip" @change="onFileChange" /> </div> </template> ``` 在脚本部分: ```javascript import JSZip from 'jszip'; import shp from 'shpjs'; export default { methods: { onFileChange(event) { const file = event.target.files[0]; if (!file) { return; } // 使用FileReader读取文件为ArrayBuffer const reader = new FileReader(); reader.onload = (e) => { const arrayBuffer = e.target.result; // 使用shpjs解析ZIP中的shapefile shp(arrayBuffer).then((geojson) => { // 处理解析后的GeoJSON数据 console.log(geojson); // 这里可以将geojson数据保存到组件的data中,或者传递给其他方法 }).catch((error) => { console.error('解析失败:', error); }); }; reader.readAsArrayBuffer(file); } } }; ``` 注意:shpjs库的parseZip方法(通过shp函数)可以接受ArrayBuffer,并且会自动解压并查找ZIP中的.shp和.dbf文件进行解析。 但是,上述代码中我们直接使用了shpjs的shp函数,它实际上可以处理多种输入(ZIP的ArrayBuffer、shp的ArrayBuffer和dbf的ArrayBuffer等)。具体可参考shpjs文档。 另外,需要注意的是,shpjs库在解析较大的ShapeFile时可能会阻塞UI,因为它是在主线程中处理的。如果遇到性能问题,可以考虑使用Web Worker。 如果ZIP文件含多个ShapeFile(即多个.shp和对应的.dbf),那么shpjs会解析成一个FeatureCollection的数组,每个元素对应一个ShapeFile的GeoJSON。 但是,通常一个ZIP文件含一个ShapeFile(即一组.shp, .dbf等文件),所以解析后我们得到一个GeoJSON对象。 如果遇到ZIP文件含多个ShapeFile,并且我们希望分别解析,那么我们需要使用JSZip分别获取每个.shp和.dbf文件,然后分别解析。但是shpjs的parseZip方法会解析ZIP中所有的ShapeFile,并返回一个数组(每个ShapeFile对应一个GeoJSON对象)。因此,如果只有一个ShapeFile,那么返回的数组只有一个元素。 因此,我们可以修改上面的代码来处理多个ShapeFile的情况: ```javascript shp(arrayBuffer).then((result) => { // 如果ZIP中只有一个ShapeFile,则result是一个GeoJSON对象 // 如果有多个,则result是一个数组,含多个GeoJSON对象 if (Array.isArray(result)) { result.forEach((geojson, index) => { console.log(`ShapeFile ${index + 1}:`, geojson); }); } else { console.log('GeoJSON:', result); } }); ``` 但是,根据shpjs的文档,当传入ArrayBuffer(ZIP文件)时,它会返回一个数组,即使只有一个ShapeFile。所以我们需要按照数组来处理。实际上,我们查看shpjs的源码和示例,它返回的始终是一个数组,每个元素代表ZIP中的一个ShapeFile(根据.shp文件来确定的)。 所以,我们可以这样处理: ```javascript shp(arrayBuffer).then((geojsonArray) => { geojsonArray.forEach((geojson, i) => { console.log(`第${i+1}个GeoJSON:`, geojson); }); }); ``` 但是,请注意:shpjs的文档中示例是直接处理单个ShapeFile的,返回的是单个GeoJSON对象。而处理ZIP返回的是数组。实际上,在shpjs的README中,它说: ```javascript shp(zipArrayBuffer).then(function(geojson){ // geojson can be a single feature or an array of features depending on the input }); ``` 所以,它可能返回单个GeoJSON对象,也可能返回数组。因此,我们需要做判断。 为了安全,我们可以这样处理: ```javascript shp(arrayBuffer).then((data) => { if (Array.isArray(data)) { // 多个ShapeFile data.forEach((geojson, index) => { console.log(`ShapeFile ${index+1}:`, geojson); }); } else { // 单个ShapeFile console.log('GeoJSON:', data); } }); ``` 但是,根据实际使用,当传入ZIP文件时,shpjs返回一个数组,即使只有一个ShapeFile。所以最好按照数组处理。但是,如果传入的是单独的.shp文件的ArrayBuffer,那么返回的是单个GeoJSON对象。 因此,我们这里传入的是ZIP文件,所以应该返回数组。但为了代码健壮性,还是做判断。 最后,将解析得到的GeoJSON数据保存到组件的data中,以便在模板中显示或用于地图库(如Leaflet)的显示。 完整示例组件代码: ```vue <template> <div> <input type="file" accept=".zip" @change="onFileChange" /> <div v-if="geojsonData.length > 0"> <h3>解析结果:</h3> <div v-for="(geojson, index) in geojsonData" :key="index"> <h4>ShapeFile {{ index+1 }}</h4> <pre>{{ JSON.stringify(geojson, null, 2) }}</pre> </div> </div> </div> </template> <script> import shp from 'shpjs'; export default { data() { return { geojsonData: [] // 用于存储解析后的GeoJSON数据(数组) }; }, methods: { onFileChange(event) { const file = event.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = (e) => { const arrayBuffer = e.target.result; shp(arrayBuffer) .then((data) => { // 确保data是数组 const resultArray = Array.isArray(data) ? data : [data]; this.geojsonData = resultArray; }) .catch((error) => { console.error('解析失败:', error); this.geojsonData = []; }); }; reader.readAsArrayBuffer(file); } } }; </script> ``` 这样,我们就实现了在Vue项目中读取ZIP压缩中的ShapeFile并解析为GeoJSON的功能。 注意事项: 1. 由于ShapeFile可能很大,解析过程可能会消耗大量内存和CPU,导致页面卡顿。可以考虑使用Web Worker在后台线程解析。 2. 如果ZIP文件中没有含完整的ShapeFile(比如缺少.dbf文件),则解析会失败。 3. 如果需要.prj文件中的投影信息,那么需要额外处理,因为GeoJSON默认是WGS84坐标(EPSG:4326)。如果ShapeFile是其他投影,则需要使用proj4等库进行坐标转换。 相关问题: 1. 如何在Vue中使用Leaflet地图显示解析后的GeoJSON数据? 2. 如何处理大型ShapeFile的解析,避免页面卡顿? 3. 如果ShapeFile的投影不是WGS84,如何将其转换为GeoJSON支持的坐标系?</think>在 Vue 项目中读取 ZIP 压缩中的 ShapeFile 文件并解析为 GeoJSON 格式,可以通过以下步骤实现: ### 解决方案步骤 #### 1. 安装依赖库 ```bash npm install jszip shpjs proj4 # 或 yarn add jszip shpjs proj4 ``` - **jszip**:处理 ZIP 压缩文件 - **shpjs**:解析 ShapeFile 为 GeoJSON - **proj4**(可选):处理坐标系转换 #### 2. 创建文件上传组件 ```vue <template> <div> <input type="file" accept=".zip" @change="handleFileUpload" /> <div v-if="geojsonData"> <h3>解析结果:</h3> <pre>{{ geojsonData }}</pre> </div> </div> </template> <script> import JSZip from 'jszip'; import shp from 'shpjs'; export default { data() { return { geojsonData: null }; }, methods: { async handleFileUpload(event) { const file = event.target.files[0]; if (!file) return; try { // 步骤1:读取ZIP文件 const arrayBuffer = await this.readFileAsArrayBuffer(file); // 步骤2:解压并解析ShapeFile this.geojsonData = await this.parseZipToGeoJson(arrayBuffer); console.log("GeoJSON 解析成功:", this.geojsonData); } catch (error) { console.error("解析失败:", error); } }, readFileAsArrayBuffer(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result); reader.onerror = reject; reader.readAsArrayBuffer(file); }); }, async parseZipToGeoJson(arrayBuffer) { // 使用shpjs直接解析ZIP中的Shapefile return await shp(arrayBuffer); } } }; </script> ``` #### 3. 处理坐标系问题(可选) 如果 ShapeFile 使用非 WGS84 坐标系(如 CGCS2000),需添加坐标转换: ```javascript import proj4 from 'proj4'; async parseZipToGeoJson(arrayBuffer) { const geojson = await shp(arrayBuffer); // 示例:从CGCS2000转WGS84(根据实际.prj文件定义调整) proj4.defs("EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs"); geojson.features.forEach(feature => { feature.geometry.coordinates = this.convertCoordinates( feature.geometry.coordinates, "EPSG:4490", "EPSG:4326" // WGS84 ); }); return geojson; }, convertCoordinates(coords, fromProj, toProj) { if (Array.isArray(coords[0])) { return coords.map(subCoords => this.convertCoordinates(subCoords, fromProj, toProj)); } return proj4(fromProj, toProj, coords); } ``` #### 4. 处理大型文件优化 对于大文件,添加进度提示和错误处理: ```javascript handleFileUpload(event) { this.loading = true; // ...原有代码... finally { this.loading = false; } } ``` ### 关键点说明 1. **文件处理流程**: $$ \text{ZIP文件} \xrightarrow{\text{JSZip}} \text{ShapeFile二进制} \xrightarrow{\text{shpjs}} \text{GeoJSON} $$ 2. **坐标系转换**: - GeoJSON 标准使用 WGS84 坐标系(EPSG:4326) - 中国常用坐标系需转换:`EPSG:4490`(CGCS2000)→ `EPSG:4326` 3. **ShapeFile 组成**: - 必需文件:`.shp`(几何数据)、`.shx`(索引)、`.dbf`(属性数据) - 可选文件:`.prj`(坐标系定义) ### 示例GeoJSON输出 ```json { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { ... }, "geometry": { "type": "Polygon", "coordinates": [[ [115.737332, 28.640312], [115.73762, 28.640515], [115.73826, 28.639818], [115.737973, 28.639615], [115.737332, 28.640312] ]] } } ] } ``` ### 注意事项 1. 浏览器限制:大文件可能导致内存溢出,建议文件 < 100MB 2. 安全策略:前端处理敏感地理数据需考虑加密传输 3. 跨域问题:本地开发时可能需配置 `vue.config.js` 代理 4. 组件销毁时清理内存:在 `beforeUnmount` 中释放 ArrayBuffer > 前端发送 GeoJSON 字符串格式数据时,建议使用 `JSON.stringify()` 序列化,并通过 POST 请求发送到后端 API[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值