From 246515b43e21f3dd458b6858ca5eed66ace9c332 Mon Sep 17 00:00:00 2001 From: liu <362165265@qq.com> Date: Fri, 30 Jan 2026 00:45:04 +0800 Subject: [PATCH] Update API and WebSocket base URLs to use environment variables for better configuration management --- .dockerignore | 42 +++++++++++ .../com/music/config/SpaForwardConfig.java | 34 +++++++++ docker/Dockerfile | 44 +++++++++++ docker/README.md | 75 +++++++++++++++++++ docker/docker-compose.yml | 16 ++++ docker/start.bat | 35 +++++++++ docker/start.sh | 29 +++++++ docker/stop.bat | 15 ++++ docker/stop.sh | 14 ++++ frontend/src/api/request.ts | 2 +- frontend/src/composables/useWebSocket.ts | 6 +- 11 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 .dockerignore create mode 100644 backend/src/main/java/com/music/config/SpaForwardConfig.java create mode 100644 docker/Dockerfile create mode 100644 docker/README.md create mode 100644 docker/docker-compose.yml create mode 100644 docker/start.bat create mode 100644 docker/start.sh create mode 100644 docker/stop.bat create mode 100644 docker/stop.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..607f3df --- /dev/null +++ b/.dockerignore @@ -0,0 +1,42 @@ +# Git +.git +.gitignore +.gitattributes + +# 文档 +README.md +LICENSE +开发文档/ + +# IDE +.vscode/ +.idea/ +*.iml +*.swp +*.swo + +# 构建产物(Docker 内会重新构建) +frontend/node_modules/ +frontend/dist/ +backend/target/ +*.jar +*.war + +# 日志 +*.log +npm-debug.log* +yarn-debug.log* + +# 系统文件 +.DS_Store +Thumbs.db +Desktop.ini + +# Docker 相关(避免递归) +docker/ +.dockerignore + +# 其他 +*.local +.cache/ +coverage/ diff --git a/backend/src/main/java/com/music/config/SpaForwardConfig.java b/backend/src/main/java/com/music/config/SpaForwardConfig.java new file mode 100644 index 0000000..9ce63ef --- /dev/null +++ b/backend/src/main/java/com/music/config/SpaForwardConfig.java @@ -0,0 +1,34 @@ +package com.music.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.resource.PathResourceResolver; + +import java.io.IOException; + +/** + * 生产环境:前端 SPA 由 Spring Boot 托管时,未匹配到的路径回退到 index.html。 + */ +@Configuration +public class SpaForwardConfig implements WebMvcConfigurer { + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/**") + .addResourceLocations("classpath:/static/") + .resourceChain(true) + .addResolver(new PathResourceResolver() { + @Override + protected Resource getResource(String resourcePath, Resource location) throws IOException { + Resource resource = location.createRelative(resourcePath); + if (resource.exists() && resource.isReadable()) { + return resource; + } + // SPA 路由回退到 index.html + return location.createRelative("index.html"); + } + }); + } +} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..28327d3 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,44 @@ +# MangTool 前后端单容器构建 +# 阶段1:构建前端 +FROM node:20-alpine AS frontend-builder +WORKDIR /app/frontend + +COPY frontend/package.json frontend/package-lock.json ./ +RUN npm ci --ignore-scripts + +COPY frontend/ ./ +# 生产环境使用相对路径,与后端同源 +ENV VITE_API_BASE_URL= +RUN npm run build + +# 阶段2:构建后端(含前端静态资源) +FROM maven:3.8-eclipse-temurin-8-alpine AS backend-builder +WORKDIR /app + +# 复制后端源码 +COPY backend/pom.xml ./ +RUN mvn dependency:go-offline -B + +COPY backend/ ./ +# 从阶段1 复制前端构建产物到 Spring Boot 静态目录 +COPY --from=frontend-builder /app/frontend/dist ./src/main/resources/static + +RUN mvn package -DskipTests -B + +# 阶段3:运行镜像 +FROM eclipse-temurin:8-jre-alpine +WORKDIR /app + +RUN apk add --no-cache tzdata wget \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +COPY --from=backend-builder /app/target/*.jar app.jar + +EXPOSE 8080 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD wget --quiet --tries=1 --spider http://localhost:8080/api/health || exit 1 + +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..b85ad5a --- /dev/null +++ b/docker/README.md @@ -0,0 +1,75 @@ +# MangTool Docker 部署 + +前后端单容器部署:拉代码后进入 `docker` 目录,执行启动脚本即可。 + +## 环境要求 + +- Docker +- Docker Compose(v2 推荐:`docker compose`) + +## 部署步骤 + +### 1. 拉取代码 + +```bash +git clone <仓库地址> +cd MyTool +``` + +### 2. 启动服务 + +**Linux / macOS:** + +```bash +cd docker +chmod +x start.sh +./start.sh +``` + +**Windows:** + +在资源管理器中进入 `docker` 目录,双击运行 `start.bat`;或在终端执行: + +```cmd +cd docker +start.bat +``` + +或直接使用 docker compose: + +```bash +cd docker +docker compose up -d --build +``` + +### 3. 访问应用 + +浏览器打开:**http://localhost:8080** + +前端与后端由同一服务提供,无需单独配置 API 地址。 + +## 常用命令 + +| 操作 | 命令 | +|------------|------------------------------| +| 后台启动 | `docker compose up -d --build` | +| 查看日志 | `docker compose logs -f` | +| 停止并删除 | `docker compose down` | +| 仅重新构建 | `docker compose build --no-cache` | +| 查看状态 | `docker compose ps` | +| 健康检查 | `docker compose exec mangtool wget -q -O- http://localhost:8080/api/health` | + +## 端口与数据 + +- **端口**:宿主机 `8080` 映射容器 `8080`,可在 `docker-compose.yml` 中修改左侧端口,例如 `"8888:8080"`。 +- **数据**:工具读写路径在容器内;若需挂载宿主机目录(如音乐库、输入输出目录),在 `docker-compose.yml` 中取消 `volumes` 注释并改为实际路径。 + +## 构建说明 + +- **Dockerfile**:多阶段构建 + 1. 使用 Node 20 构建前端(Vite),产出到 `dist` + 2. 使用 Maven + JDK 8 构建后端,并将前端 `dist` 拷贝到 `src/main/resources/static` + 3. 运行阶段使用 `eclipse-temurin:8-jre-alpine`,仅运行打包好的 Spring Boot jar + 4. 内置健康检查(每 30 秒检查 `/api/health` 端点) +- 生产环境前端 API/WebSocket 使用相对路径,与后端同源,无需再配 CORS。 +- 已配置 `.dockerignore` 优化构建上下文,加快构建速度。 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..d97a491 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,16 @@ +version: "3.8" + +services: + mangtool: + build: + context: .. + dockerfile: docker/Dockerfile + image: mangtool:latest + container_name: mangtool + ports: + - "8080:8080" + restart: unless-stopped + # 如需挂载本地目录给工具读写,可取消注释并修改路径 + # volumes: + # - /path/on/host/Input:/app/data/Input + # - /path/on/host/Library_Final:/app/data/Library_Final diff --git a/docker/start.bat b/docker/start.bat new file mode 100644 index 0000000..56050a8 --- /dev/null +++ b/docker/start.bat @@ -0,0 +1,35 @@ +@echo off +chcp 65001 >nul +cd /d "%~dp0" + +echo 检查 Docker 状态... +docker info >nul 2>&1 +if errorlevel 1 ( + echo ❌ 错误: Docker 未运行,请先启动 Docker Desktop + pause + exit /b 1 +) + +echo. +echo ^>^>^> MangTool Docker 启动中... +docker compose up -d --build + +if errorlevel 1 ( + echo. + echo ❌ 启动失败,请检查日志: docker compose logs + pause + exit /b 1 +) + +echo. +echo ✅ 启动完成! +echo. +echo 📌 访问地址: http://localhost:8080 +echo 📌 查看日志: docker compose logs -f +echo 📌 停止服务: docker compose down +echo. +echo 等待服务就绪中... +timeout /t 3 /nobreak >nul +docker compose ps +echo. +pause diff --git a/docker/start.sh b/docker/start.sh new file mode 100644 index 0000000..0578efd --- /dev/null +++ b/docker/start.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# MangTool 一键启动脚本(拉代码后在此目录执行) +set -e +cd "$(dirname "$0")" + +# 检查 Docker 是否运行 +if ! docker info > /dev/null 2>&1; then + echo "❌ 错误: Docker 未运行,请先启动 Docker" + exit 1 +fi + +echo ">>> MangTool Docker 启动中..." +docker compose up -d --build + +if [ $? -eq 0 ]; then + echo "" + echo "✅ 启动完成!" + echo "" + echo "📌 访问地址: http://localhost:8080" + echo "📌 查看日志: docker compose logs -f" + echo "📌 停止服务: docker compose down" + echo "" + echo "等待服务就绪中..." + sleep 3 + docker compose ps +else + echo "❌ 启动失败,请检查日志: docker compose logs" + exit 1 +fi diff --git a/docker/stop.bat b/docker/stop.bat new file mode 100644 index 0000000..9258938 --- /dev/null +++ b/docker/stop.bat @@ -0,0 +1,15 @@ +@echo off +chcp 65001 >nul +cd /d "%~dp0" + +echo 正在停止 MangTool 容器... +docker compose down + +if errorlevel 1 ( + echo ❌ 停止失败 + pause + exit /b 1 +) + +echo ✅ 已停止并删除容器 +pause diff --git a/docker/stop.sh b/docker/stop.sh new file mode 100644 index 0000000..5d70414 --- /dev/null +++ b/docker/stop.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# MangTool Docker 停止脚本 +set -e +cd "$(dirname "$0")" + +echo ">>> 正在停止 MangTool 容器..." +docker compose down + +if [ $? -eq 0 ]; then + echo "✅ 已停止并删除容器" +else + echo "❌ 停止失败" + exit 1 +fi diff --git a/frontend/src/api/request.ts b/frontend/src/api/request.ts index 3de1a3d..994419e 100644 --- a/frontend/src/api/request.ts +++ b/frontend/src/api/request.ts @@ -2,7 +2,7 @@ import axios from 'axios'; import { ElMessage } from 'element-plus'; const request = axios.create({ - baseURL: 'http://localhost:8080', + baseURL: import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:8080', timeout: 30000, headers: { 'Content-Type': 'application/json' diff --git a/frontend/src/composables/useWebSocket.ts b/frontend/src/composables/useWebSocket.ts index 3ebdcfd..fd86320 100644 --- a/frontend/src/composables/useWebSocket.ts +++ b/frontend/src/composables/useWebSocket.ts @@ -30,7 +30,11 @@ export function useWebSocket(taskId: string | null, onMessage: (msg: ProgressMes } try { - const socket = new SockJS('http://localhost:8080/ws'); + const wsBase = + import.meta.env.VITE_WS_BASE_URL !== undefined && import.meta.env.VITE_WS_BASE_URL !== '' + ? import.meta.env.VITE_WS_BASE_URL + : (typeof window !== 'undefined' ? window.location.origin : 'http://localhost:8080'); + const socket = new SockJS(`${wsBase}/ws`); stompClient = Stomp.over(socket); // 禁用调试日志