GeoJSON加载修复说明.md 7.3 KB

GeoJSON加载问题修复说明

问题描述

用户上传的自定义数据(SHP文件)转换为GeoJSON后,存放在 uploads/models/geojson/ 目录中。在开发环境下可以正常加载,但打包后无法加载,报错"加载GeoJSON失败"。

而同样在 uploads/models/ 目录下的模型文件(.glb)却可以正常加载。

问题原因

模型文件 vs GeoJSON文件加载方式对比

模型文件(可以正常加载)

加载方式: 通过后端API下载

代码位置: aside.vue 第734-735行

const baseURL = import.meta.env.VITE_APP_BASE_API || ''
const apiUrl = baseURL + "/common/download/resource?resource=" + encodeURIComponent(modelUrl)

实际请求路径:

/prod-api/common/download/resource?resource=uploads/models/xxx.glb

GeoJSON文件(打包后加载失败)

原加载方式: 直接使用文件路径

代码位置: layerManagement.js 第507行

const loadPromise = Cesium.GeoJsonDataSource.load(url, { ... });

实际请求路径:

/uploads/models/geojson/xxx.geojson

为什么打包后失败?

开发环境:

  • Vite开发服务器会代理所有请求到后端
  • 相对路径 /uploads/... 可以通过代理访问到后端文件

生产环境(打包后):

  • 前端和后端分离部署
  • 前端静态文件服务器(Nginx/IIS)找不到 /uploads/... 路径的文件
  • 需要通过后端API访问:/prod-api/common/download/resource?resource=uploads/...

解决方案

修改内容

修改了 layerManagement.js 文件:

1. 导入认证函数

import { getToken } from '@/utils/auth';

2. 修改 addGeoJsonLayer 函数

添加本地文件检测,自动使用API加载:

function addGeoJsonLayer(url, name, callback) {
    // ... 省略部分代码

    // 检查是否为本地文件路径(需要通过API加载)
    const isLocalPath = url.startsWith('/uploads/') || url.startsWith('uploads/') || url.startsWith('./uploads/');

    if (isLocalPath) {
        console.log('检测到本地GeoJSON文件,通过API加载:', url);
        loadGeoJsonViaApi(url, name, null, callback);
        return;
    }

    // 外部URL直接加载
    // ... 省略部分代码
}

3. 新增 loadGeoJsonViaApi 函数

专门处理本地GeoJSON文件的加载:

async function loadGeoJsonViaApi(url, name, style, callback) {
    // 1. 规范化URL
    let normalizedUrl = url.replace(/^\/+/, '').replace(/^\.\/+/, '');

    // 2. 构建API URL
    const baseURL = window.globalRequestConfig?.baseURL || import.meta.env.VITE_APP_BASE_API || '';
    const apiUrl = `${baseURL}/common/download/resource?resource=${encodeURIComponent(normalizedUrl)}`;

    // 3. 获取认证token
    const token = typeof getToken === 'function' ? 'Bearer ' + getToken() : '';

    // 4. 通过API下载文件
    const response = await fetch(apiUrl, {
        method: 'GET',
        headers: { 'Authorization': token }
    });

    // 5. 创建Blob URL
    const blob = await response.blob();
    const blobUrl = URL.createObjectURL(blob);

    // 6. 使用Cesium加载
    const loadPromise = Cesium.GeoJsonDataSource.load(blobUrl, { ... });

    // 7. 加载完成后释放Blob URL
    URL.revokeObjectURL(blobUrl);
}

4. 同样修改 addGeoJsonLayerWithStyle 函数

添加了相同的本地文件检测和API加载逻辑。

工作原理

加载流程对比

修改前(打包后失败)

GeoJSON URL: /uploads/models/geojson/xxx.geojson
      ↓
直接请求前端服务器
      ↓
404 Not Found(文件不存在)

修改后(打包后成功)

GeoJSON URL: /uploads/models/geojson/xxx.geojson
      ↓
检测为本地文件
      ↓
转换为API URL: /prod-api/common/download/resource?resource=uploads/models/geojson/xxx.geojson
      ↓
请求后端API下载文件
      ↓
创建Blob URL
      ↓
Cesium加载Blob URL
      ↓
加载成功

关键技术点

  1. 路径检测:自动识别本地文件路径(/uploads/ 开头)
  2. API调用:使用后端 /common/download/resource 接口下载文件
  3. 认证集成:自动添加 Authorization header
  4. Blob处理:将下载的文件转换为 Blob URL 供 Cesium 使用
  5. 内存管理:加载完成后自动释放 Blob URL

验证步骤

1. 重新打包

cd d:\Web\PlatformModel\RuoYi-Vue3
npm run build:prod

2. 查看控制台日志

成功加载时应该看到:

========== addGeoJsonLayer 开始执行 ==========
URL: uploads/models/geojson/xxx.geojson
Name: 自定义数据
检测到本地GeoJSON文件,通过API加载: uploads/models/geojson/xxx.geojson
========== loadGeoJsonViaApi 开始执行 ==========
原始URL: uploads/models/geojson/xxx.geojson
API URL: /prod-api/common/download/resource?resource=uploads%2Fmodels%2Fgeojson%2Fxxx.geojson
开始通过API下载GeoJSON文件...
API响应状态: 200
文件大小: 12345 bytes
创建Blob URL: blob:http://localhost/xxx-xxx-xxx
开始使用Cesium加载GeoJSON...
========== GeoJSON通过API加载成功 ==========
图层名称: 自定义数据

3. 检查网络请求

打开浏览器开发者工具 → Network 标签:

应该看到:

  • 请求URL:/prod-api/common/download/resource?resource=uploads%2Fmodels%2Fgeojson%2Fxxx.geojson
  • 状态:200 OK
  • 类型:application/octet-stream

支持的文件路径格式

修改后的代码支持以下格式的本地路径:

  • /uploads/models/geojson/xxx.geojson
  • uploads/models/geojson/xxx.geojson
  • ./uploads/models/geojson/xxx.geojson

注意事项

1. 后端API要求

确保后端提供了 /common/download/resource 接口,且:

  • 支持GeoJSON文件下载
  • 返回正确的文件内容
  • 支持认证

2. 文件权限

确保:

  • uploads 目录存在且可访问
  • geojson 文件有正确的读取权限

3. 外部URL不受影响

外部URL(如超图服务、在线GeoJSON)仍然直接加载,不通过API。

4. 内存管理

代码会自动释放Blob URL,无需手动管理。

相关文件

  • layerManagement.js - 主要修改文件
  • aside.vue - 参考模型加载方式
  • auth.js - 认证函数

常见问题

Q: 为什么模型文件可以加载,GeoJSON不行?

A: 模型文件通过后端API下载,GeoJSON直接使用文件路径。打包后前端静态服务器找不到文件。

Q: 修改后会影响性能吗?

A: 影响很小。多了一次API请求,但文件下载速度与直接访问相同。

Q: 外部URL也会通过API加载吗?

A: 不会。只有以 /uploads/ 开头的本地路径才会通过API加载。

Q: 需要修改数据库中的路径吗?

A: 不需要。数据库中的路径保持不变,代码会自动处理。

总结

通过让GeoJSON文件和模型文件使用相同的加载方式(通过后端API),解决了打包后无法加载本地GeoJSON文件的问题。代码会自动识别本地路径并进行相应处理,对用户透明。