🛰️ dtSpaceMap - 实时卫星追踪 3D 可视化平台

基于 Three.js 构建的实时卫星追踪 3D 可视化 Web 平台,支持 30,000+ 卫星对象同时渲染,帧率 ≥30fps。提供星座管理、碰撞预警、过境预测、TLE 解析、摄影炸弹、坐标转换等专业工具链。
架构概览
分层架构 (Layered Architecture)

通信架构 (Communication Architecture)

核心业务流程
1. 卫星数据同步与加载流程
▼mermaid复制代码graph TB A[用户点击分类加载] --> B{fetchLiveCategoryData} B --> C[Step 1: POST /api/public/sync/groups] C --> D{后端检查 sync_tracking} D -->|6小时内已同步| E[跳过拉取] D -->|未同步或过期| F[从 CelesTrak 拉取 TLE] F --> G[解析 TLE 文本] G --> H[批量写入数据库] H --> I[更新 sync_tracking 记录] E --> J[Step 2: GET /api/public/satellites/with-tle-by-groups] I --> J J --> K[从数据库加载卫星数据] K --> L{数据是否足够?} L -->|是| M[填充 Pinia Store] L -->|否| N[Step 3: 前端直连 CelesTrak 回退] N --> M M --> O[VisualizerView 桥接] O --> P[loadRealSatellites] P --> Q[创建 GPU InstancedMesh] Q --> R[初始化 SGP4 Web Worker] R --> S[实时渲染循环]
定时任务补充: XXL-JOB 每天凌晨 02:00 自动执行增量同步,检查
sync_tracking表,跳过 6 小时内已同步的分组。用户再次加载同一分类时,命中sync_tracking记录直接返回数据库数据。
2. 用户认证与授权流程
▼mermaid复制代码graph TB A[用户访问受保护路由] --> B{Vue Router 导航守卫} B --> C{localStorage 有 accessToken?} C -->|否| D[重定向到 /login?redirect=原路径] C -->|是| E[放行进入页面] D --> F[用户填写登录表单] F --> G[POST /api/auth/login] G --> H{Spring Security 认证} H -->|失败| I[返回 401 + 错误信息] H -->|成功| J[生成 JWT accessToken + refreshToken] J --> K[返回令牌对] K --> L[前端存储到 localStorage] L --> M[重定向回原路径] N[Axios 请求拦截器] --> O{检测 token} O -->|存在| P[注入 Authorization Bearer 头] O -->|不存在| Q[放行匿名请求] R[Axios 响应拦截器] --> S{状态码 401?} S -->|是| T[清除本地 token] T --> U[跳转 /login] S -->|否| V[统一错误提示]
3. SGP4 轨道计算与 3D 渲染循环
▼mermaid复制代码graph TB subgraph 主线程 Main Thread A[requestAnimationFrame] --> B[计算帧间隔 dt] B --> C{时间是否播放?} C -->|是| D[推进仿真时间 simTime] C -->|否| E{自动旋转?} E -->|是| F[缓慢旋转地球] F --> G[updateSatellitePositions] D --> G G --> H[逐卫星计算轨道位置] H --> I[Billboard 朝向相机] I --> J[距离自适应缩放] J --> K[更新 InstancedMesh Matrix] K --> L{有选中卫星?} L -->|是| M[更新高亮环/波纹/探照灯动画] M --> N[更新拖尾轨迹] L -->|否| O[checkHover 射线检测] O --> P{命中卫星?} P -->|是| Q[显示 hover 光环 + 标签 + 轨道] P -->|否| R[清除 hover 特效] N --> S[renderer.render] R --> S Q --> S S --> A end subgraph SGP4 Worker 线程 W1[接收 init 消息] --> W2[twoline2satrec 解析 TLE] W2 --> W3[存储 satrec 对象] W3 --> W4[postMessage initialized] W4 --> W5{每秒接收 propagate 消息} W5 --> W6[sgp4 批量传播计算] W6 --> W7[ECI → 大地坐标转换] W7 --> W8[postMessage 位置结果] W8 --> W5 end subgraph 真实数据模式 T1[loadRealSatellites] --> T2[createRealSatellites] T2 --> T3[initSgp4Worker] T3 --> W1 T3 --> T4[usingRealData = true] T4 --> T5[每秒 requestWorkerPositions] T5 --> W5 W8 --> T6[updateRealSatPositions] T6 --> K end
4. 卫星交互操作流程
▼mermaid复制代码graph TB A[用户操作] --> B{操作类型} B -->|鼠标悬停| C[mousemove 事件] C --> D[更新 mouse 坐标] D --> E[checkHover 节流 35ms] E --> F[Raycaster 检测 allSatMeshes] F --> G{命中 InstancedMesh?} G -->|是| H[instanceToNorad 查找 satData] H --> I{与选中卫星相同?} I -->|否| J[显示 hover 光环 + 标签 + hover 轨道] I -->|是| K[保持选中高亮, 隐藏 hover] J --> K G -->|否| L[清除 hover 特效] B -->|鼠标点击| M[click 事件] M --> N[Raycaster 检测] N --> O{命中卫星?} O -->|是| P[设置 selectedSatellite] P --> Q[高亮轨道 activeOrbitLine] Q --> R[placeHighlight 多层脉冲环] R --> S[createRippleEffect 波纹扩散] S --> T[createSpotlightEffect 探照灯] T --> U[showLabelFor 名称标签] U --> V[聚焦动画 focusOnSatellite] V --> W[更新 Pinia Store] W --> X[弹出 SatelliteDetail 面板] O -->|否| Y[clearSelection 清除所有特效] B -->|空格键| Z[切换全局搜索面板] Z --> AA[输入关键词] AA --> AB[本地/后端搜索卫星] AB --> AC[选择卫星 → 触发点击流程]
技术栈
前端
| 技术 | 说明 | 版本 |
|---|---|---|
| Vue 3 | 渐进式框架 (Composition API) | ^3.4.27 |
| TypeScript | 类型安全 | ^5.4.5 |
| Vite | 构建工具 | ^5.2.0 |
| Pinia | 状态管理 | ^2.1.7 |
| Three.js | 3D 渲染引擎 | ^0.165.0 |
| Element Plus | UI 组件库 (暗色主题) | ^2.7.0 |
| ECharts | 数据可视化图表 | ^5.5.0 |
| satellite.js | SGP4/SDP4 轨道计算 | ^5.0.0 |
| ootk | 航天轨道计算库 | ^7.0.3 |
| Axios | HTTP 客户端 | ^1.7.2 |
| Vue Router | 路由管理 | ^4.3.2 |
| vue-i18n | 国际化 | ^9.13.0 |
后端
| 技术 | 说明 | 版本 |
|---|---|---|
| Spring Boot | 应用框架 | 3.2.5 |
| Java | 运行环境 | 17 |
| MyBatis Flex | ORM 框架 | 1.9.3 |
| PostgreSQL | 关系数据库 | 14+ |
| Redis | 缓存 | 7+ |
| Flyway | 数据库迁移 | 10.11.1 |
| Spring Security | 认证授权 | 6.x |
| JWT (jjwt) | 令牌认证 | 0.12.5 |
| XXL-JOB | 分布式定时调度 | 2.4.1 |
| Knife4j | API 文档 | 4.5.0 |
| Hutool | Java 工具库 | 5.8.28 |
| MapStruct | 对象映射 | 1.5.5 |
| Lombok | 代码简化 | 1.18.32 |
| Spring AI | AI 集成 | 1.0.0-M4 |
运维
| 技术 | 说明 |
|---|---|
| Docker | 容器化部署 |
| Docker Compose | 本地编排 (PostgreSQL + Redis) |
| GitHub Actions | CI/CD 流水线 |
| Prometheus + Grafana | 监控告警 |
| Spring Boot Actuator | 应用健康检查 |
快速开始
环境要求
- Node.js 20+
- Java 17+ (推荐 Temurin)
- PostgreSQL 14+
- Redis 7+
- Docker & Docker Compose (可选)
方式一:本地开发
▼bash复制代码# 1. 启动基础服务 (PostgreSQL + Redis) cd docker cp .env.example .env docker-compose up -d # 2. 启动后端 cd ../backend mvn spring-boot:run # 后端启动后 Flyway 会自动执行数据库迁移 # 3. 启动前端 cd ../frontend npm install npm run dev
- 🌐 前端访问:http://localhost:3000
- 🔌 后端 API:http://localhost:8080/api/health
- 📖 API 文档:http://localhost:8080/doc.html
方式二:Docker 全容器化
▼bash复制代码# 在 docker 目录下启动所有服务 cd docker docker-compose -f docker-compose.yml -f ../docker-compose.override.yml up -d
核心功能
3D 可视化引擎
- Three.js 3D 地球渲染:PBR 材质、程序化纹理、实时云图覆盖 (Matt Eason's Cloud Service)
- GPU 实例化渲染:30,000+ 卫星对象同时渲染,帧率保持 ≥30fps
- 倾角着色系统:按赤道/低/中/高/逆行倾角带使用不同颜色区分
- 星空背景:12,000 星点粒子系统 + 3,000 科技感动态粒子背景
- 多渲染风格:Classic / Map / 4K 切换
- 时间控制系统:暂停/加速/回溯,模拟时间推进
- 大气光晕:双层 ShaderMaterial 大气散射效果
- 经纬网格与赤道环:辅助空间定位
- 沉浸式模式:全屏无装饰浏览
卫星数据管理
- CelesTrak 数据同步:XXL-JOB 定时任务自动拉取 TLE 数据,增量/全量两种模式
- DB 优先加载策略:首次从 CelesTrak 获取后存入数据库,后续直接从数据库加载
- 六大分类加载:特殊兴趣、气象与地球资源、通信、北斗、导航、科学卫星
- 实时 SGP4 传播:Web Worker 分片计算(satellite.js v5),不阻塞主线程
- 卫星搜索与筛选:按名称/NORAD ID 搜索,按轨道类型过滤
- 卫星分类筛选:按倾角带过滤卫星显示
专业工具链
| 工具 | 说明 | 路由 |
|---|---|---|
| TLE 解析器 | 两行根数解析与轨道参数计算 | /tools/tle |
| 过境预测 | 基于用户经纬度的卫星过境时间预测 | /tools/transit |
| 碰撞预警 | 卫星间接近事件预警分析 | /tools/collision |
| 摄影炸弹 | 预测卫星过境拍摄窗口 | /tools/photo |
| 坐标转换 | 多坐标系之间的转换工具 | /tools/coord |
| 多源轨道可视化 | SP3/RINEX/OEM 文件上传与多源轨道对比 | /multi-source-orbit |
数据同步机制
系统采用 DB 优先 + CelesTrak 回退 的数据加载策略,具体流程详见上方「核心业务流程 → 卫星数据同步与加载流程」Mermaid 流程图。
关键策略要点:
- 同步间隔控制:
sync_tracking表记录每分组最后同步时间,6 小时间隔内不再重复拉取 - DB 优先:首次加载时后端从 CelesTrak 拉取 → 写入数据库 → 后续直接从 DB 加载
- 定时增量同步:XXL-JOB 每天凌晨 02:00 自动增量同步,跳过未过期分组
- 三级降级:后端同步 → 数据库加载 → 前端直连 CelesTrak(后端不可用时自动降级)
关键代码示例
1. Three.js 3D 引擎 — GPU 实例化卫星渲染
核心渲染引擎使用 THREE.InstancedMesh 实现数万颗卫星的高效渲染,按倾角带分组着色。
▼typescript复制代码// frontend/src/composables/useThreeScene.ts (简化) // 创建 GPU 实例化卫星(按倾角带分组) for (const [bandKey, band] of Object.entries(bands)) { // 可见卫星点 const visibleGeo = new THREE.CircleGeometry(0.01, 16) const visibleMat = new THREE.MeshBasicMaterial({ color: band.color, side: THREE.DoubleSide }) const visibleInstanced = new THREE.InstancedMesh(visibleGeo, visibleMat, typeCount) // 不可见的检测网格(用于射线拾取) const hitGeo = new THREE.SphereGeometry(0.04, 8, 8) const hitMat = new THREE.MeshBasicMaterial({ visible: false }) const hitInstanced = new THREE.InstancedMesh(hitGeo, hitMat, typeCount) const dummy = new THREE.Object3D() for (let i = 0; i < typeCount; i++) { // 根据轨道参数计算3D坐标 const x = alt * (Math.cos(ra) * Math.cos(ma) - Math.sin(ra) * Math.sin(ma) * Math.cos(inc)) const y = alt * Math.sin(ma) * Math.sin(inc) const z = alt * (Math.sin(ra) * Math.cos(ma) + Math.cos(ra) * Math.sin(ma) * Math.cos(inc)) dummy.position.set(x, y, z) dummy.updateMatrix() visibleInstanced.setMatrixAt(i, dummy.matrix) hitInstanced.setMatrixAt(i, dummy.matrix) } scene.add(visibleInstanced) scene.add(hitInstanced) }
2. 大气散射 Shader — 边缘光晕效果
使用自定义 ShaderMaterial 实现菲涅尔效应的大气光晕,增强视觉真实感。
▼glsl复制代码// vertexShader varying vec3 vNormal; varying vec3 vWorldPos; void main() { vec4 worldPos = modelMatrix * vec4(position, 1.0); vWorldPos = worldPos.xyz; vNormal = normalize(mat3(modelMatrix) * normal); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } // fragmentShader varying vec3 vNormal; varying vec3 vWorldPos; uniform vec3 uSunDir; void main() { vec3 viewDir = normalize(cameraPosition - vWorldPos); vec3 normal = normalize(vNormal); float fresnel = 1.0 - abs(dot(viewDir, normal)); fresnel = pow(fresnel, 3.0); float sunFac = dot(normal, normalize(uSunDir)) * 0.5 + 0.5; vec3 glowColor = mix(vec3(0.2, 0.5, 1.0), vec3(0.1, 0.7, 1.0), fresnel); float alpha = fresnel * 0.5 * (0.3 + sunFac * 0.7); gl_FragColor = vec4(glowColor, alpha); }
3. CelesTrak TLE 数据服务 — 多分组拉取与解析
支持从多个 CelesTrak 分组拉取 TLE 数据,去重后提取轨道参数供 SGP4 计算。
▼typescript复制代码// frontend/src/services/satelliteService.ts (简化) export async function fetchAllSatellites(): Promise<SatelliteBasic[]> { const groups = ['active', 'stations', 'visual', 'weather', 'starlink', 'oneweb', 'gps', 'beidou', 'galileo', 'cubesat', 'geo'] const results: SatelliteBasic[] = [] const seenNoradIds = new Set<number>() for (const group of groups) { const records = await fetchTleData(group) for (const sat of records.map(extractSatInfo)) { if (!seenNoradIds.has(sat.noradId)) { seenNoradIds.add(sat.noradId) results.push(sat) } } } return results } // 从 TLE 行解析轨道参数 export function extractSatInfo(record: TleRecord): SatelliteBasic { return { noradId: parseInt(record.noradId), name: record.name, inclination: parseFloat(record.line2.substring(8, 16)), // 轨道倾角 raan: parseFloat(record.line2.substring(17, 25)), // 升交点赤经 eccentricity: parseFloat('0.' + record.line2.substring(26, 33)), // 偏心率 argPerigee: parseFloat(record.line2.substring(34, 42)), // 近地点幅角 meanAnomaly: parseFloat(record.line2.substring(43, 51)), // 平近点角 meanMotion: parseFloat(record.line2.substring(52, 63)), // 每天圈数 // ... 更多参数 } }
页面路由一览
| 路径 | 页面 | 描述 |
|---|---|---|
/ | VisualizerView | 3D 可视化主视图 |
/login | LoginView | 用户登录 |
/register | RegisterView | 用户注册 |
/dashboard | DashboardView | 数据仪表盘(需认证) |
/constellations | ConstellationListView | 星座列表 |
/constellations/:id | ConstellationDetailView | 星座详情 |
/tools | ToolView | 专业工具入口 |
/tools/collision | CollisionWarningView | 碰撞预警 |
/tools/transit | TransitPredictionView | 过境预测 |
/tools/tle | TleParserView | TLE 解析器 |
/tools/photo | PhotoBombView | 摄影炸弹 |
/tools/coord | CoordConvertView | 坐标转换 |
/multi-source-orbit | MultiSourceOrbitView | 多源数据轨道可视化 |
/settings | UserSettingsView | 用户设置(需认证) |
/admin/users | AdminUsersView | 用户管理(需认证) |
/info | InfoView | 关于项目 |
/credits | CreditsView | 致谢名单 |
API 概览
认证接口 (/api/auth)
| 端点 | 方法 | 说明 |
|---|---|---|
/auth/login | POST | 登录 (返回 JWT) |
/auth/register | POST | 注册 |
/auth/refresh | POST | 刷新令牌 |
/auth/me | GET | 当前用户信息及权限 |
受保护接口 (/api/satellites, /api/user, /api/tools, /api/orbit)
需携带 Authorization: Bearer <token> 头访问。
用户接口 (/api/user)
| 端点 | 说明 |
|---|---|
/user/preferences | 用户偏好设置 (GET/PUT) |
/user/bookmarks | 卫星书签管理 (GET/POST/DELETE) |
/user/profile | 个人资料 (GET/PUT) |
/user/admin/* | 管理员用户管理接口 |
工具接口 (/api/tools)
| 端点 | 说明 |
|---|---|
/tools/collisions | 碰撞事件列表 (分页) |
/tools/collisions/satellite/{noradId} | 指定卫星碰撞事件 |
/tools/pass-predictor | 过境预测计算 |
多源轨道接口 (/api/orbit)
| 端点 | 说明 |
|---|---|
/orbit/all | 预置模拟轨道列表 |
/orbit/kepler | 开普勒轨道生成 |
/orbit/state_vector_custom | 自定义状态向量生成 |
/orbit/determine | IOD 轨道确定 |
/orbit/upload/sp3 | SP3 文件上传解析 |
/orbit/upload/rinex | RINEX 文件上传解析 |
/orbit/upload/tle | TLE 文本上传解析 |
Docker 部署
基础设施
▼yaml复制代码# docker-compose.yml (核心) services: postgres: # PostgreSQL 14, 端口 5432 redis: # Redis 7, 端口 6379
构建镜像
▼bash复制代码# 后端 docker build -t dtspacemap-backend ./backend # 前端 (Nginx 静态服务) docker build -t dtspacemap-frontend ./frontend
CI/CD (GitHub Actions)
流水线包含三个阶段:
- Backend Build & Test:JDK 17 + Maven 编译和测试
- Frontend Build & Lint:Node.js 20 + ESLint 检查 + TypeScript 编译
- Build Docker Images:main 分支合并后自动构建镜像
开发规范
- Git 提交:遵循 Conventional Commits (
feat:,fix:,refactor:) - 代码风格:前端 ESLint + Prettier,后端遵循阿里 Java 规范
- API 设计:RESTful 规范,统一
Result<T>响应格式 - 数据库变更:通过 Flyway 迁移脚本管理,禁止手动修改
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
内容推荐
AI应用开发中的流式输出:从协议原理到工程实战的完整指南
38
第1章 LearnWise AI项目介绍
5
Spring Boot 如何处理跨域请求(CORS):深度调研报告
3
【入职求助贴】萌新刚入职某大厂做后端开发,目前还在试用期。最近遇到一个棘手的问题,想向大家求助一下。入职不久,leader 给我派了一个任务。跟我说是0.5天就可以解决,我刚毕业入职,做了一个星期没有做出来。实现一个收集定时成功任务的案例。听起来好像不复杂,但我自己摸索着做了一整个星期,到现在还没达到预期效果。这一周我基本是“边学边做”的状态,遇到卡点也会每天主动找 leader 沟通进度和疑问。
2
#字节内推# 实习、校招、社招均有岗位
4
