From 129284dc1edfd3aaf5c8b6fea0c6c7b31e2385ce Mon Sep 17 00:00:00 2001 From: aiotagro Date: Thu, 11 Sep 2025 19:54:34 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E9=83=A8=E7=BD=B2=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/scripts/start-server.sh | 2 +- backend/start_server.bat | 266 ++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 backend/start_server.bat diff --git a/backend/scripts/start-server.sh b/backend/scripts/start-server.sh index 64b99d2..1daada9 100644 --- a/backend/scripts/start-server.sh +++ b/backend/scripts/start-server.sh @@ -8,7 +8,7 @@ set -e # 配置参数 APP_NAME="jiebanke-backend" -APP_DIR="/data/nodejsjiebanke" +APP_DIR="/data/nodejs/jiebanke" PORT="3310" LOG_DIR="$APP_DIR/logs" diff --git a/backend/start_server.bat b/backend/start_server.bat new file mode 100644 index 0000000..94b71e5 --- /dev/null +++ b/backend/start_server.bat @@ -0,0 +1,266 @@ +#!/bin/bash + +# 结伴客后端服务启动脚本 +# 用于启动Node.js后端服务 + +# 设置颜色变量 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# 显示脚本使用说明 +show_usage() { + echo "用法: $0 [选项]" + echo "选项:" + echo " start 启动后端服务" + echo " stop 停止后端服务" + echo " restart 重启后端服务" + echo " status 查看服务状态" + echo " help 显示帮助信息" +} + +# 检查是否安装了Node.js +check_node() { + if ! command -v node &> /dev/null; then + echo -e "${RED}错误: 未找到Node.js,请先安装Node.js${NC}" + exit 1 + fi + + NODE_VERSION=$(node -v) + echo -e "${GREEN}✓ Node.js版本: ${NODE_VERSION}${NC}" +} + +# 检查是否安装了npm +check_npm() { + if ! command -v npm &> /dev/null; then + echo -e "${RED}错误: 未找到npm,请先安装npm${NC}" + exit 1 + fi + + NPM_VERSION=$(npm -v) + echo -e "${GREEN}✓ npm版本: ${NPM_VERSION}${NC}" +} + +# 检查依赖是否已安装 +check_dependencies() { + if [ ! -d "node_modules" ]; then + echo -e "${YELLOW}警告: 未找到node_modules目录,正在安装依赖...${NC}" + npm install + if [ $? -ne 0 ]; then + echo -e "${RED}错误: 依赖安装失败${NC}" + exit 1 + fi + echo -e "${GREEN}✓ 依赖安装完成${NC}" + else + echo -e "${GREEN}✓ 依赖已安装${NC}" + fi +} + +# 启动服务 +start_service() { + # 检查服务是否已经在运行 + if pgrep -f "node.*server.js" > /dev/null; then + echo -e "${YELLOW}警告: 服务已在运行中${NC}" + exit 1 + fi + + echo -e "${GREEN}正在启动结伴客后端服务...${NC}" + + # 设置环境变量 + export NODE_ENV=production + export PORT=${PORT:-3200} + + # 启动服务并将其放到后台运行 + nohup npm start > server.log 2>&1 & + SERVER_PID=$! + + # 将PID保存到文件 + echo $SERVER_PID > server.pid + + # 等待几秒钟让服务启动 + sleep 3 + + # 检查服务是否成功启动 + if pgrep -f "node.*server.js" > /dev/null; then + echo -e "${GREEN}✓ 服务启动成功${NC}" + echo -e "${GREEN}✓ PID: ${SERVER_PID}${NC}" + echo -e "${GREEN}✓ 日志文件: server.log${NC}" + echo -e "${GREEN}✓ 访问地址: http://localhost:${PORT}${NC}" + else + echo -e "${RED}✗ 服务启动失败,请检查日志文件 server.log${NC}" + rm -f server.pid + exit 1 + fi +} + +# 停止服务 +stop_service() { + if [ ! -f server.pid ]; then + if pgrep -f "node.*server.js" > /dev/null; then + echo -e "${YELLOW}警告: 找到正在运行的服务,但PID文件不存在${NC}" + echo -e "${YELLOW}尝试查找并终止服务...${NC}" + pkill -f "node.*server.js" + sleep 2 + if pgrep -f "node.*server.js" > /dev/null; then + echo -e "${RED}✗ 无法终止服务${NC}" + exit 1 + else + echo -e "${GREEN}✓ 服务已终止${NC}" + fi + else + echo -e "${YELLOW}服务未在运行${NC}" + fi + else + SERVER_PID=$(cat server.pid) + if ps -p $SERVER_PID > /dev/null; then + echo -e "${GREEN}正在停止服务 (PID: ${SERVER_PID})...${NC}" + kill $SERVER_PID + sleep 3 + if ps -p $SERVER_PID > /dev/null; then + echo -e "${YELLOW}服务未响应,强制终止...${NC}" + kill -9 $SERVER_PID + fi + rm -f server.pid + echo -e "${GREEN}✓ 服务已停止${NC}" + else + echo -e "${YELLOW}PID文件存在但服务未在运行${NC}" + rm -f server.pid + fi + fi +} + +# 查看服务状态 +status_service() { + if [ -f server.pid ]; then + SERVER_PID=$(cat server.pid) + if ps -p $SERVER_PID > /dev/null; then + echo -e "${GREEN}✓ 服务正在运行 (PID: ${SERVER_PID})${NC}" + else + echo -e "${RED}✗ PID文件存在但服务未在运行${NC}" + fi + else + if pgrep -f "node.*server.js" > /dev/null; then + echo -e "${GREEN}✓ 服务正在运行${NC}" + else + echo -e "${YELLOW}服务未在运行${NC}" + fi + fi +} + +# 查看日志 +tail_logs() { + if [ -f server.log ]; then + tail -f server.log + else + echo -e "${RED}日志文件不存在${NC}" + fi +} + +# 主逻辑 +main() { + # 获取命令行参数 + ACTION=${1:-"start"} + + case "$ACTION" in + start) + check_node + check_npm + check_dependencies + start_service + ;; + stop) + stop_service + ;; + restart) + stop_service + sleep 2 + check_node + check_npm + check_dependencies + start_service + ;; + status) + status_service + ;; + logs) + tail_logs + ;; + help) + show_usage + ;; + *) + echo -e "${RED}未知选项: $ACTION${NC}" + show_usage + exit 1 + ;; + esac +} + +# 执行主逻辑 +main "$@" +``` +``` +@echo off +title 结伴客后端服务启动脚本 + +setlocal enabledelayedexpansion + +:: 设置颜色 +for /f "delims=" %%i in ('echo prompt $E^| cmd') do set "ESC=%%i" + +:: 检查Node.js是否安装 +echo 检查Node.js环境... +node -v >nul 2>&1 +if %errorlevel% neq 0 ( + echo %ESC%[91m错误: 未找到Node.js,请先安装Node.js%ESC%[0m + pause + exit /b 1 +) else ( + for /f %%i in ('node -v') do set NODE_VERSION=%%i + echo %ESC%[92m✓ Node.js版本: %NODE_VERSION%%ESC%[0m +) + +:: 检查npm是否安装 +echo 检查npm环境... +npm -v >nul 2>&1 +if %errorlevel% neq 0 ( + echo %ESC%[91m错误: 未找到npm,请先安装npm%ESC%[0m + pause + exit /b 1 +) else ( + for /f %%i in ('npm -v') do set NPM_VERSION=%%i + echo %ESC%[92m✓ npm版本: %NPM_VERSION%%ESC%[0m +) + +:: 检查依赖是否安装 +if not exist "node_modules" ( + echo %ESC%[93m警告: 未找到node_modules目录,正在安装依赖...%ESC%[0m + npm install + if !errorlevel! neq 0 ( + echo %ESC%[91m错误: 依赖安装失败%ESC%[0m + pause + exit /b 1 + ) + echo %ESC%[92m✓ 依赖安装完成%ESC%[0m +) else ( + echo %ESC%[92m✓ 依赖已安装%ESC%[0m +) + +:: 设置默认端口 +if "%PORT%"=="" set PORT=3200 + +:: 启动服务 +echo %ESC%[92m正在启动结伴客后端服务...%ESC%[0m +echo 服务将在端口 %PORT% 上运行 +echo 日志将输出到 server.log 文件 + +npm start > server.log 2>&1 + +if %errorlevel% equ 0 ( + echo %ESC%[92m✓ 服务启动成功%ESC%[0m +) else ( + echo %ESC%[91m✗ 服务启动失败,请检查日志文件 server.log%ESC%[0m +) + +pause From 67aef9a9eec8c6b4ce7af682f11241c08fe5c520 Mon Sep 17 00:00:00 2001 From: ylweng Date: Thu, 11 Sep 2025 23:59:19 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=8A=A8=E7=89=A9?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=E5=8F=8A?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend-java/PERFORMANCE_OPTIMIZATION.md | 326 ------------------ backend-java/README.md | 159 --------- backend-java/animal-service/pom.xml | 56 --- .../jiebanke/animal/AnimalApplication.java | 19 - .../animal/controller/AnimalController.java | 138 -------- .../com/jiebanke/animal/entity/Animal.java | 23 -- .../jiebanke/animal/mapper/AnimalMapper.java | 37 -- .../animal/service/AnimalService.java | 69 ---- .../service/impl/AnimalServiceImpl.java | 156 --------- .../src/main/resources/application.yml | 32 -- .../target/classes/application.yml | 32 -- .../jiebanke/animal/AnimalApplication.class | Bin 1085 -> 0 bytes .../animal/controller/AnimalController.class | Bin 3779 -> 0 bytes .../com/jiebanke/animal/entity/Animal.class | Bin 4940 -> 0 bytes .../jiebanke/animal/mapper/AnimalMapper.class | Bin 1230 -> 0 bytes .../animal/service/AnimalService.class | Bin 1498 -> 0 bytes .../service/impl/AnimalServiceImpl.class | Bin 7718 -> 0 bytes backend-java/auth-service/pom.xml | 96 ------ .../com/jiebanke/auth/AuthApplication.java | 26 -- .../auth/controller/AuthController.java | 187 ---------- .../java/com/jiebanke/auth/entity/User.java | 23 -- .../com/jiebanke/auth/mapper/UserMapper.java | 68 ---- .../auth/service/AuthRabbitMQService.java | 46 --- .../auth/service/AuthRedisService.java | 53 --- .../com/jiebanke/auth/service/AuthResult.java | 11 - .../jiebanke/auth/service/AuthService.java | 61 ---- .../auth/service/impl/AuthServiceImpl.java | 255 -------------- .../java/com/jiebanke/auth/util/JwtUtil.java | 107 ------ .../src/main/resources/application.yml | 36 -- .../auth/service/AuthRabbitMQServiceTest.java | 55 --- .../auth/service/AuthRedisServiceTest.java | 112 ------ .../target/classes/application.yml | 36 -- backend-java/build-services.sh | 44 --- backend-java/common/pom.xml | 36 -- .../jiebanke/common/config/FeignConfig.java | 22 -- .../common/config/RabbitMQConfig.java | 102 ------ .../jiebanke/common/config/RedisConfig.java | 20 -- .../jiebanke/common/entity/BaseEntity.java | 11 - .../common/exception/BusinessException.java | 23 -- .../exception/GlobalExceptionHandler.java | 20 -- .../com/jiebanke/common/vo/ApiResponse.java | 41 --- .../jiebanke/common/config/FeignConfig.class | Bin 1017 -> 0 bytes .../common/config/RabbitMQConfig.class | Bin 4809 -> 0 bytes .../jiebanke/common/config/RedisConfig.class | Bin 1155 -> 0 bytes .../jiebanke/common/entity/BaseEntity.class | Bin 2952 -> 0 bytes .../common/exception/BusinessException.class | Bin 2357 -> 0 bytes .../exception/GlobalExceptionHandler.class | Bin 1541 -> 0 bytes .../com/jiebanke/common/vo/ApiResponse.class | Bin 4861 -> 0 bytes backend-java/docker-compose.yml | 147 -------- backend-java/eureka-server/pom.xml | 32 -- .../eureka/EurekaServerApplication.java | 13 - .../src/main/resources/application.yml | 17 - .../target/classes/application.yml | 17 - .../eureka/EurekaServerApplication.class | Bin 808 -> 0 bytes backend-java/gateway-service/pom.xml | 54 --- .../jiebanke/gateway/GatewayApplication.java | 34 -- .../src/main/resources/application.yml | 38 -- .../target/classes/application.yml | 38 -- .../jiebanke/gateway/GatewayApplication.class | Bin 3944 -> 0 bytes backend-java/order-service/pom.xml | 56 --- .../com/jiebanke/order/OrderApplication.java | 19 - .../order/controller/OrderController.java | 140 -------- .../java/com/jiebanke/order/entity/Order.java | 18 - .../jiebanke/order/mapper/OrderMapper.java | 37 -- .../jiebanke/order/service/OrderService.java | 70 ---- .../order/service/impl/OrderServiceImpl.java | 159 --------- .../src/main/resources/application.yml | 32 -- .../target/classes/application.yml | 32 -- .../com/jiebanke/order/OrderApplication.class | Bin 1079 -> 0 bytes .../order/controller/OrderController.class | Bin 6892 -> 0 bytes .../com/jiebanke/order/entity/Order.class | Bin 3710 -> 0 bytes .../jiebanke/order/mapper/OrderMapper.class | Bin 1226 -> 0 bytes .../jiebanke/order/service/OrderService.class | Bin 1464 -> 0 bytes .../order/service/impl/OrderServiceImpl.class | Bin 7837 -> 0 bytes backend-java/pom.xml | 163 --------- backend-java/promotion-service/pom.xml | 56 --- .../promotion/PromotionApplication.java | 19 - .../controller/PromotionController.java | 175 ---------- .../promotion/entity/PromotionActivity.java | 22 -- .../promotion/entity/RewardRecord.java | 22 -- .../mapper/PromotionActivityMapper.java | 46 --- .../promotion/mapper/RewardRecordMapper.java | 38 -- .../promotion/service/PromotionService.java | 88 ----- .../service/impl/PromotionServiceImpl.java | 181 ---------- .../src/main/resources/application.yml | 32 -- .../target/classes/application.yml | 32 -- .../promotion/PromotionApplication.class | Bin 1103 -> 0 bytes .../controller/PromotionController.class | Bin 7717 -> 0 bytes .../promotion/entity/PromotionActivity.class | Bin 4830 -> 0 bytes .../promotion/entity/RewardRecord.class | Bin 4638 -> 0 bytes .../mapper/PromotionActivityMapper.class | Bin 1407 -> 0 bytes .../promotion/mapper/RewardRecordMapper.class | Bin 1322 -> 0 bytes .../promotion/service/PromotionService.class | Bin 1683 -> 0 bytes .../service/impl/PromotionServiceImpl.class | Bin 7222 -> 0 bytes backend-java/scripts/init-database.sql | 137 -------- backend-java/start-services.sh | 92 ----- backend-java/stop-services.sh | 29 -- backend-java/travel-service/pom.xml | 62 ---- .../jiebanke/travel/TravelApplication.java | 19 - .../controller/TravelPlanController.java | 115 ------ .../jiebanke/travel/entity/TravelPlan.java | 22 -- .../travel/mapper/TravelPlanMapper.java | 29 -- .../travel/service/TravelPlanService.java | 60 ---- .../jiebanke/travel/service/TravelStats.java | 14 - .../service/impl/TravelPlanServiceImpl.java | 148 -------- .../src/main/resources/application.yml | 32 -- .../target/classes/application.yml | 32 -- backend-java/user-service/pom.xml | 74 ---- .../com/jiebanke/user/UserApplication.java | 15 - .../user/client/AuthServiceClient.java | 14 - .../com/jiebanke/user/config/FeignConfig.java | 31 -- .../user/service/UserRabbitMQService.java | 44 --- .../user/service/UserRedisService.java | 44 --- .../src/main/resources/application.yml | 25 -- .../user/service/UserRabbitMQServiceTest.java | 53 --- .../user/service/UserRedisServiceTest.java | 92 ----- .../target/classes/application.yml | 25 -- 117 files changed, 5573 deletions(-) delete mode 100644 backend-java/PERFORMANCE_OPTIMIZATION.md delete mode 100644 backend-java/README.md delete mode 100644 backend-java/animal-service/pom.xml delete mode 100644 backend-java/animal-service/src/main/java/com/jiebanke/animal/AnimalApplication.java delete mode 100644 backend-java/animal-service/src/main/java/com/jiebanke/animal/controller/AnimalController.java delete mode 100644 backend-java/animal-service/src/main/java/com/jiebanke/animal/entity/Animal.java delete mode 100644 backend-java/animal-service/src/main/java/com/jiebanke/animal/mapper/AnimalMapper.java delete mode 100644 backend-java/animal-service/src/main/java/com/jiebanke/animal/service/AnimalService.java delete mode 100644 backend-java/animal-service/src/main/java/com/jiebanke/animal/service/impl/AnimalServiceImpl.java delete mode 100644 backend-java/animal-service/src/main/resources/application.yml delete mode 100644 backend-java/animal-service/target/classes/application.yml delete mode 100644 backend-java/animal-service/target/classes/com/jiebanke/animal/AnimalApplication.class delete mode 100644 backend-java/animal-service/target/classes/com/jiebanke/animal/controller/AnimalController.class delete mode 100644 backend-java/animal-service/target/classes/com/jiebanke/animal/entity/Animal.class delete mode 100644 backend-java/animal-service/target/classes/com/jiebanke/animal/mapper/AnimalMapper.class delete mode 100644 backend-java/animal-service/target/classes/com/jiebanke/animal/service/AnimalService.class delete mode 100644 backend-java/animal-service/target/classes/com/jiebanke/animal/service/impl/AnimalServiceImpl.class delete mode 100644 backend-java/auth-service/pom.xml delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/AuthApplication.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/controller/AuthController.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/entity/User.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/mapper/UserMapper.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthRabbitMQService.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthRedisService.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthResult.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthService.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/service/impl/AuthServiceImpl.java delete mode 100644 backend-java/auth-service/src/main/java/com/jiebanke/auth/util/JwtUtil.java delete mode 100644 backend-java/auth-service/src/main/resources/application.yml delete mode 100644 backend-java/auth-service/src/test/java/com/jiebanke/auth/service/AuthRabbitMQServiceTest.java delete mode 100644 backend-java/auth-service/src/test/java/com/jiebanke/auth/service/AuthRedisServiceTest.java delete mode 100644 backend-java/auth-service/target/classes/application.yml delete mode 100755 backend-java/build-services.sh delete mode 100644 backend-java/common/pom.xml delete mode 100644 backend-java/common/src/main/java/com/jiebanke/common/config/FeignConfig.java delete mode 100644 backend-java/common/src/main/java/com/jiebanke/common/config/RabbitMQConfig.java delete mode 100644 backend-java/common/src/main/java/com/jiebanke/common/config/RedisConfig.java delete mode 100644 backend-java/common/src/main/java/com/jiebanke/common/entity/BaseEntity.java delete mode 100644 backend-java/common/src/main/java/com/jiebanke/common/exception/BusinessException.java delete mode 100644 backend-java/common/src/main/java/com/jiebanke/common/exception/GlobalExceptionHandler.java delete mode 100644 backend-java/common/src/main/java/com/jiebanke/common/vo/ApiResponse.java delete mode 100644 backend-java/common/target/classes/com/jiebanke/common/config/FeignConfig.class delete mode 100644 backend-java/common/target/classes/com/jiebanke/common/config/RabbitMQConfig.class delete mode 100644 backend-java/common/target/classes/com/jiebanke/common/config/RedisConfig.class delete mode 100644 backend-java/common/target/classes/com/jiebanke/common/entity/BaseEntity.class delete mode 100644 backend-java/common/target/classes/com/jiebanke/common/exception/BusinessException.class delete mode 100644 backend-java/common/target/classes/com/jiebanke/common/exception/GlobalExceptionHandler.class delete mode 100644 backend-java/common/target/classes/com/jiebanke/common/vo/ApiResponse.class delete mode 100644 backend-java/docker-compose.yml delete mode 100644 backend-java/eureka-server/pom.xml delete mode 100644 backend-java/eureka-server/src/main/java/com/jiebanke/eureka/EurekaServerApplication.java delete mode 100644 backend-java/eureka-server/src/main/resources/application.yml delete mode 100644 backend-java/eureka-server/target/classes/application.yml delete mode 100644 backend-java/eureka-server/target/classes/com/jiebanke/eureka/EurekaServerApplication.class delete mode 100644 backend-java/gateway-service/pom.xml delete mode 100644 backend-java/gateway-service/src/main/java/com/jiebanke/gateway/GatewayApplication.java delete mode 100644 backend-java/gateway-service/src/main/resources/application.yml delete mode 100644 backend-java/gateway-service/target/classes/application.yml delete mode 100644 backend-java/gateway-service/target/classes/com/jiebanke/gateway/GatewayApplication.class delete mode 100644 backend-java/order-service/pom.xml delete mode 100644 backend-java/order-service/src/main/java/com/jiebanke/order/OrderApplication.java delete mode 100644 backend-java/order-service/src/main/java/com/jiebanke/order/controller/OrderController.java delete mode 100644 backend-java/order-service/src/main/java/com/jiebanke/order/entity/Order.java delete mode 100644 backend-java/order-service/src/main/java/com/jiebanke/order/mapper/OrderMapper.java delete mode 100644 backend-java/order-service/src/main/java/com/jiebanke/order/service/OrderService.java delete mode 100644 backend-java/order-service/src/main/java/com/jiebanke/order/service/impl/OrderServiceImpl.java delete mode 100644 backend-java/order-service/src/main/resources/application.yml delete mode 100644 backend-java/order-service/target/classes/application.yml delete mode 100644 backend-java/order-service/target/classes/com/jiebanke/order/OrderApplication.class delete mode 100644 backend-java/order-service/target/classes/com/jiebanke/order/controller/OrderController.class delete mode 100644 backend-java/order-service/target/classes/com/jiebanke/order/entity/Order.class delete mode 100644 backend-java/order-service/target/classes/com/jiebanke/order/mapper/OrderMapper.class delete mode 100644 backend-java/order-service/target/classes/com/jiebanke/order/service/OrderService.class delete mode 100644 backend-java/order-service/target/classes/com/jiebanke/order/service/impl/OrderServiceImpl.class delete mode 100644 backend-java/pom.xml delete mode 100644 backend-java/promotion-service/pom.xml delete mode 100644 backend-java/promotion-service/src/main/java/com/jiebanke/promotion/PromotionApplication.java delete mode 100644 backend-java/promotion-service/src/main/java/com/jiebanke/promotion/controller/PromotionController.java delete mode 100644 backend-java/promotion-service/src/main/java/com/jiebanke/promotion/entity/PromotionActivity.java delete mode 100644 backend-java/promotion-service/src/main/java/com/jiebanke/promotion/entity/RewardRecord.java delete mode 100644 backend-java/promotion-service/src/main/java/com/jiebanke/promotion/mapper/PromotionActivityMapper.java delete mode 100644 backend-java/promotion-service/src/main/java/com/jiebanke/promotion/mapper/RewardRecordMapper.java delete mode 100644 backend-java/promotion-service/src/main/java/com/jiebanke/promotion/service/PromotionService.java delete mode 100644 backend-java/promotion-service/src/main/java/com/jiebanke/promotion/service/impl/PromotionServiceImpl.java delete mode 100644 backend-java/promotion-service/src/main/resources/application.yml delete mode 100644 backend-java/promotion-service/target/classes/application.yml delete mode 100644 backend-java/promotion-service/target/classes/com/jiebanke/promotion/PromotionApplication.class delete mode 100644 backend-java/promotion-service/target/classes/com/jiebanke/promotion/controller/PromotionController.class delete mode 100644 backend-java/promotion-service/target/classes/com/jiebanke/promotion/entity/PromotionActivity.class delete mode 100644 backend-java/promotion-service/target/classes/com/jiebanke/promotion/entity/RewardRecord.class delete mode 100644 backend-java/promotion-service/target/classes/com/jiebanke/promotion/mapper/PromotionActivityMapper.class delete mode 100644 backend-java/promotion-service/target/classes/com/jiebanke/promotion/mapper/RewardRecordMapper.class delete mode 100644 backend-java/promotion-service/target/classes/com/jiebanke/promotion/service/PromotionService.class delete mode 100644 backend-java/promotion-service/target/classes/com/jiebanke/promotion/service/impl/PromotionServiceImpl.class delete mode 100644 backend-java/scripts/init-database.sql delete mode 100755 backend-java/start-services.sh delete mode 100755 backend-java/stop-services.sh delete mode 100644 backend-java/travel-service/pom.xml delete mode 100644 backend-java/travel-service/src/main/java/com/jiebanke/travel/TravelApplication.java delete mode 100644 backend-java/travel-service/src/main/java/com/jiebanke/travel/controller/TravelPlanController.java delete mode 100644 backend-java/travel-service/src/main/java/com/jiebanke/travel/entity/TravelPlan.java delete mode 100644 backend-java/travel-service/src/main/java/com/jiebanke/travel/mapper/TravelPlanMapper.java delete mode 100644 backend-java/travel-service/src/main/java/com/jiebanke/travel/service/TravelPlanService.java delete mode 100644 backend-java/travel-service/src/main/java/com/jiebanke/travel/service/TravelStats.java delete mode 100644 backend-java/travel-service/src/main/java/com/jiebanke/travel/service/impl/TravelPlanServiceImpl.java delete mode 100644 backend-java/travel-service/src/main/resources/application.yml delete mode 100644 backend-java/travel-service/target/classes/application.yml delete mode 100644 backend-java/user-service/pom.xml delete mode 100644 backend-java/user-service/src/main/java/com/jiebanke/user/UserApplication.java delete mode 100644 backend-java/user-service/src/main/java/com/jiebanke/user/client/AuthServiceClient.java delete mode 100644 backend-java/user-service/src/main/java/com/jiebanke/user/config/FeignConfig.java delete mode 100644 backend-java/user-service/src/main/java/com/jiebanke/user/service/UserRabbitMQService.java delete mode 100644 backend-java/user-service/src/main/java/com/jiebanke/user/service/UserRedisService.java delete mode 100644 backend-java/user-service/src/main/resources/application.yml delete mode 100644 backend-java/user-service/src/test/java/com/jiebanke/user/service/UserRabbitMQServiceTest.java delete mode 100644 backend-java/user-service/src/test/java/com/jiebanke/user/service/UserRedisServiceTest.java delete mode 100644 backend-java/user-service/target/classes/application.yml diff --git a/backend-java/PERFORMANCE_OPTIMIZATION.md b/backend-java/PERFORMANCE_OPTIMIZATION.md deleted file mode 100644 index 7102712..0000000 --- a/backend-java/PERFORMANCE_OPTIMIZATION.md +++ /dev/null @@ -1,326 +0,0 @@ -# 结伴客Java后端性能优化指南 - -## 1. JVM调优 - -### 1.1 堆内存设置 -``` -# 堆内存大小设置(根据服务器配置调整) --Xms512m --Xmx2g - -# 新生代大小设置 --Xmn256m - -# Metaspace大小设置 --XX:MetaspaceSize=256m --XX:MaxMetaspaceSize=512m -``` - -### 1.2 垃圾回收器选择 -``` -# G1垃圾回收器(适用于大堆内存) --XX:+UseG1GC --XX:MaxGCPauseMillis=200 --XX:G1HeapRegionSize=16m - -# 或者CMS垃圾回收器(适用于低延迟要求) --XX:+UseConcMarkSweepGC --XX:+UseCMSInitiatingOccupancyOnly --XX:CMSInitiatingOccupancyFraction=70 -``` - -## 2. 数据库连接池优化 - -### 2.1 HikariCP配置(在application.yml中) -```yaml -spring: - datasource: - hikari: - # 连接池大小 - maximum-pool-size: 20 - # 最小空闲连接数 - minimum-idle: 5 - # 连接超时时间 - connection-timeout: 30000 - # 空闲超时时间 - idle-timeout: 600000 - # 最大生命周期 - max-lifetime: 1800000 - # 连接测试查询 - connection-test-query: SELECT 1 -``` - -## 3. Redis性能优化 - -### 3.1 Redis连接池配置 -```yaml -spring: - redis: - lettuce: - pool: - # 最大连接数 - max-active: 20 - # 最大空闲连接数 - max-idle: 10 - # 最小空闲连接数 - min-idle: 5 - # 获取连接最大等待时间 - max-wait: 2000ms -``` - -### 3.2 Redis序列化优化 -```java -@Bean -public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); - - // 使用更高效的序列化方式 - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); - template.setHashKeySerializer(new StringRedisSerializer()); - template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); - - return template; -} -``` - -## 4. RabbitMQ性能优化 - -### 4.1 连接池配置 -```yaml -spring: - rabbitmq: - listener: - simple: - # 并发消费者数量 - concurrency: 5 - # 最大并发消费者数量 - max-concurrency: 20 - # 每个消费者预取的消息数量 - prefetch: 10 -``` - -## 5. Feign客户端优化 - -### 5.1 Feign配置 -```java -@Configuration -public class FeignConfig { - - @Bean - public Request.Options options() { - // 连接超时时间和读取超时时间 - return new Request.Options(5000, 10000); - } - - @Bean - public Retryer retryer() { - // 重试策略 - return new Retryer.Default(1000, 2000, 3); - } -} -``` - -## 6. 线程池优化 - -### 6.1 自定义线程池 -```java -@Configuration -public class ThreadPoolConfig { - - @Bean("taskExecutor") - public ExecutorService taskExecutor() { - return new ThreadPoolExecutor( - 10, // 核心线程数 - 20, // 最大线程数 - 60L, // 空闲线程存活时间 - TimeUnit.SECONDS, - new LinkedBlockingQueue<>(100), // 任务队列 - new ThreadFactoryBuilder().setNameFormat("task-pool-%d").build(), - new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略 - ); - } -} -``` - -## 7. 缓存策略优化 - -### 7.1 多级缓存设计 -```java -@Service -public class UserService { - - @Autowired - private RedisTemplate redisTemplate; - - // 本地缓存(Caffeine) - private Cache localCache = Caffeine.newBuilder() - .maximumSize(1000) - .expireAfterWrite(10, TimeUnit.MINUTES) - .build(); - - public User getUserById(Long userId) { - // 1. 先查本地缓存 - User user = (User) localCache.getIfPresent("user:" + userId); - if (user != null) { - return user; - } - - // 2. 再查Redis缓存 - user = (User) redisTemplate.opsForValue().get("user:" + userId); - if (user != null) { - localCache.put("user:" + userId, user); - return user; - } - - // 3. 最后查数据库 - user = userMapper.selectById(userId); - if (user != null) { - redisTemplate.opsForValue().set("user:" + userId, user, 30, TimeUnit.MINUTES); - localCache.put("user:" + userId, user); - } - - return user; - } -} -``` - -## 8. 数据库查询优化 - -### 8.1 MyBatis-Plus分页优化 -```java -@Configuration -public class MybatisPlusConfig { - - @Bean - public MybatisPlusInterceptor mybatisPlusInterceptor() { - MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); - // 分页插件 - interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); - // 乐观锁插件 - interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); - return interceptor; - } -} -``` - -### 8.2 索引优化建议 -```sql --- 用户表索引优化 -CREATE INDEX idx_user_phone ON users(phone); -CREATE INDEX idx_user_email ON users(email); -CREATE INDEX idx_user_status ON users(status); - --- 旅行表索引优化 -CREATE INDEX idx_travel_creator ON travels(creator_id); -CREATE INDEX idx_travel_status ON travels(status); -CREATE INDEX idx_travel_start_time ON travels(start_time); - --- 动物表索引优化 -CREATE INDEX idx_animal_shelter ON animals(shelter_id); -CREATE INDEX idx_animal_status ON animals(status); - --- 订单表索引优化 -CREATE INDEX idx_order_user ON orders(user_id); -CREATE INDEX idx_order_status ON orders(status); -CREATE INDEX idx_order_create_time ON orders(create_time); -``` - -## 9. API网关优化 - -### 9.1 限流配置 -```yaml -spring: - cloud: - gateway: - routes: - - id: user-service - uri: lb://user-service - predicates: - - Path=/api/users/** - filters: - - name: RequestRateLimiter - args: - redis-rate-limiter.replenishRate: 10 - redis-rate-limiter.burstCapacity: 20 -``` - -## 10. 监控和日志优化 - -### 10.1 Actuator配置 -```yaml -management: - endpoints: - web: - exposure: - include: health,info,metrics,httptrace - endpoint: - health: - show-details: always -``` - -### 10.2 日志配置优化 -```yaml -logging: - level: - com.jiebanke: INFO - org.springframework: WARN - org.mybatis: WARN - pattern: - console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" - file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" - file: - name: logs/application.log -``` - -## 11. Docker部署优化 - -### 11.1 JVM参数优化(Dockerfile) -```dockerfile -FROM openjdk:17-jdk-slim - -LABEL maintainer="jiebanke-team" - -WORKDIR /app - -COPY target/*.jar app.jar - -# JVM参数优化 -ENV JAVA_OPTS="-Xms512m -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200" - -EXPOSE 8080 - -ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] -``` - -## 12. 负载均衡优化 - -### 12.1 Ribbon配置 -```yaml -ribbon: - # 连接超时时间 - ConnectTimeout: 3000 - # 读取超时时间 - ReadTimeout: 10000 - # 是否启用重试 - OkToRetryOnAllOperations: false - # 切换实例重试次数 - MaxAutoRetriesNextServer: 1 - # 当前实例重试次数 - MaxAutoRetries: 0 -``` - -## 13. 性能测试建议 - -### 13.1 压力测试工具 -- JMeter:用于API接口压力测试 -- wrk:用于HTTP基准测试 -- ab (Apache Bench):简单的HTTP性能测试工具 - -### 13.2 监控工具 -- Prometheus + Grafana:系统指标监控 -- ELK Stack:日志分析 -- SkyWalking:分布式追踪 - -通过以上优化措施,可以显著提升结伴客Java后端服务的性能和稳定性。 \ No newline at end of file diff --git a/backend-java/README.md b/backend-java/README.md deleted file mode 100644 index bddd082..0000000 --- a/backend-java/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# 结伴客Java后端 - -结伴客Java微服务架构后端系统,基于Spring Boot和Spring Cloud实现。 - -## 系统架构 - -- **服务注册与发现**: Eureka Server -- **API网关**: Spring Cloud Gateway -- **认证服务**: Auth Service -- **用户服务**: User Service -- **旅行服务**: Travel Service -- **动物服务**: Animal Service -- **订单服务**: Order Service -- **推广服务**: Promotion Service - -## 环境要求 - -- **JDK**: Java 17 -- **构建工具**: Maven 3.6+ -- **数据库**: MySQL 8.0+ -- **缓存**: Redis 6.0+ -- **消息队列**: RabbitMQ 3.8+ - -## 环境安装 - -### 1. 安装Java 17 - -#### macOS (使用Homebrew) -```bash -brew install openjdk@17 -``` - -#### Ubuntu/Debian -```bash -sudo apt update -sudo apt install openjdk-17-jdk -``` - -#### CentOS/RHEL -```bash -sudo yum install java-17-openjdk-devel -``` - -### 2. 安装Maven - -#### macOS (使用Homebrew) -```bash -brew install maven -``` - -#### Ubuntu/Debian -```bash -sudo apt update -sudo apt install maven -``` - -#### CentOS/RHEL -```bash -sudo yum install maven -``` - -### 3. 验证安装 - -```bash -java -version -mvn -version -``` - -应该看到类似以下输出: -``` -openjdk version "17.0.8" 2023-07-18 -Apache Maven 3.8.6 -``` - -## 数据库配置 - -1. 安装MySQL 8.0+ -2. 创建数据库: - ```sql - CREATE DATABASE jiebanke CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - ``` -3. 执行初始化脚本: - ```bash - mysql -u root -p jiebanke < scripts/init-database.sql - ``` - -## 缓存和消息队列 - -1. 安装Redis 6.0+ -2. 安装RabbitMQ 3.8+ - -## 构建项目 - -```bash -# 进入项目目录 -cd backend-java - -# 清理并构建项目 -./build-services.sh -``` - -## 运行服务 - -### 方式一:使用启动脚本(推荐) - -```bash -# 进入项目目录 -cd backend-java - -# 启动所有服务 -./start-services.sh - -# 停止所有服务 -./stop-services.sh -``` - -### 方式二:手动启动 - -1. 启动Eureka Server: - ```bash - cd eureka-server - mvn spring-boot:run - ``` - -2. 等待Eureka启动完成后,依次启动其他服务: - ```bash - # 在新的终端窗口中启动Auth Service - cd auth-service - mvn spring-boot:run - - # 在新的终端窗口中启动User Service - cd user-service - mvn spring-boot:run - - # 以此类推启动其他服务... - ``` - -## 访问服务 - -- **Eureka Dashboard**: http://localhost:8761 -- **API Gateway**: http://localhost:8080 -- **API文档**: http://localhost:8080/doc.html - -## 服务端口 - -| 服务名称 | 端口 | -|---------|------| -| Eureka Server | 8761 | -| API Gateway | 8080 | -| Auth Service | 8081 | -| User Service | 8082 | -| Travel Service | 8083 | -| Animal Service | 8084 | -| Order Service | 8085 | -| Promotion Service | 8086 | - -## 性能优化 - -详细的性能优化指南请参考 [PERFORMANCE_OPTIMIZATION.md](PERFORMANCE_OPTIMIZATION.md) 文件。 \ No newline at end of file diff --git a/backend-java/animal-service/pom.xml b/backend-java/animal-service/pom.xml deleted file mode 100644 index f55fd0c..0000000 --- a/backend-java/animal-service/pom.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - animal-service - jar - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - com.baomidou - mybatis-plus-boot-starter - - - - - mysql - mysql-connector-java - - - - - com.jiebanke - common - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/backend-java/animal-service/src/main/java/com/jiebanke/animal/AnimalApplication.java b/backend-java/animal-service/src/main/java/com/jiebanke/animal/AnimalApplication.java deleted file mode 100644 index e3e4661..0000000 --- a/backend-java/animal-service/src/main/java/com/jiebanke/animal/AnimalApplication.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.jiebanke.animal; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDiscoveryClient -@EnableFeignClients -@MapperScan("com.jiebanke.animal.mapper") -@ComponentScan(basePackages = "com.jiebanke") -public class AnimalApplication { - public static void main(String[] args) { - SpringApplication.run(AnimalApplication.class, args); - } -} \ No newline at end of file diff --git a/backend-java/animal-service/src/main/java/com/jiebanke/animal/controller/AnimalController.java b/backend-java/animal-service/src/main/java/com/jiebanke/animal/controller/AnimalController.java deleted file mode 100644 index 76e8c23..0000000 --- a/backend-java/animal-service/src/main/java/com/jiebanke/animal/controller/AnimalController.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.jiebanke.animal.controller; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.jiebanke.animal.entity.Animal; -import com.jiebanke.animal.service.AnimalService; -import com.jiebanke.common.vo.ApiResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.Map; - -@RestController -@RequestMapping("/api/animals") -public class AnimalController { - - @Autowired - private AnimalService animalService; - - /** - * 搜索动物(公开接口) - */ - @GetMapping("/search") - public ApiResponse> searchAnimals( - @RequestParam(required = false) String keyword, - @RequestParam(required = false) String species, - @RequestParam(required = false) Double minPrice, - @RequestParam(required = false) Double maxPrice, - @RequestParam(defaultValue = "1") Integer page, - @RequestParam(defaultValue = "10") Integer pageSize) { - - IPage animals = animalService.searchAnimals(keyword, species, minPrice, maxPrice, page, pageSize); - - Map result = new HashMap<>(); - result.put("animals", animals.getRecords()); - result.put("pagination", Map.of( - "page", animals.getCurrent(), - "pageSize", animals.getSize(), - "total", animals.getTotal(), - "totalPages", animals.getPages() - )); - - return ApiResponse.success(result); - } - - /** - * 获取动物列表(商家) - */ - @GetMapping - public ApiResponse> getAnimals( - @RequestHeader("userId") Long merchantId, - @RequestParam(defaultValue = "1") Integer page, - @RequestParam(defaultValue = "10") Integer pageSize, - @RequestParam(required = false) String species, - @RequestParam(required = false) String status) { - - IPage animals = animalService.getAnimals(merchantId, page, pageSize, species, status); - - Map result = new HashMap<>(); - result.put("animals", animals.getRecords()); - result.put("pagination", Map.of( - "page", animals.getCurrent(), - "pageSize", animals.getSize(), - "total", animals.getTotal(), - "totalPages", animals.getPages() - )); - - return ApiResponse.success(result); - } - - /** - * 获取动物统计信息 - */ - @GetMapping("/stats") - public ApiResponse> getAnimalStatistics() { - Map statistics = animalService.getAnimalStatistics(); - return ApiResponse.success(statistics); - } - - /** - * 获取单个动物详情 - */ - @GetMapping("/{animalId}") - public ApiResponse getAnimal(@PathVariable Long animalId) { - Animal animal = animalService.getAnimalById(animalId); - return ApiResponse.success(animal); - } - - /** - * 创建动物信息 - */ - @PostMapping - public ApiResponse> createAnimal( - @RequestHeader("userId") Long merchantId, - @RequestBody Animal animal) { - - animal.setMerchantId(merchantId); - Long animalId = animalService.createAnimal(animal); - Animal createdAnimal = animalService.getAnimalById(animalId); - - Map result = new HashMap<>(); - result.put("animal", createdAnimal); - result.put("message", "动物信息创建成功"); - - return ApiResponse.success(result); - } - - /** - * 更新动物信息 - */ - @PutMapping("/{animalId}") - public ApiResponse> updateAnimal( - @PathVariable Long animalId, - @RequestBody Animal animal) { - - Animal updatedAnimal = animalService.updateAnimal(animalId, animal); - - Map result = new HashMap<>(); - result.put("animal", updatedAnimal); - result.put("message", "动物信息更新成功"); - - return ApiResponse.success(result); - } - - /** - * 删除动物信息 - */ - @DeleteMapping("/{animalId}") - public ApiResponse> deleteAnimal(@PathVariable Long animalId) { - boolean deleted = animalService.deleteAnimal(animalId); - - Map result = new HashMap<>(); - result.put("message", "动物信息删除成功"); - result.put("animalId", animalId); - - return ApiResponse.success(result); - } -} \ No newline at end of file diff --git a/backend-java/animal-service/src/main/java/com/jiebanke/animal/entity/Animal.java b/backend-java/animal-service/src/main/java/com/jiebanke/animal/entity/Animal.java deleted file mode 100644 index a080efe..0000000 --- a/backend-java/animal-service/src/main/java/com/jiebanke/animal/entity/Animal.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.jiebanke.animal.entity; - -import com.jiebanke.common.entity.BaseEntity; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.math.BigDecimal; -import java.time.LocalDate; - -@Data -@EqualsAndHashCode(callSuper = true) -public class Animal extends BaseEntity { - private Long merchantId; - private String name; - private String species; - private String breed; - private LocalDate birthDate; - private String personality; - private String farmLocation; - private BigDecimal price; - private Integer claimCount; - private String status; -} \ No newline at end of file diff --git a/backend-java/animal-service/src/main/java/com/jiebanke/animal/mapper/AnimalMapper.java b/backend-java/animal-service/src/main/java/com/jiebanke/animal/mapper/AnimalMapper.java deleted file mode 100644 index 6fe424e..0000000 --- a/backend-java/animal-service/src/main/java/com/jiebanke/animal/mapper/AnimalMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.jiebanke.animal.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.jiebanke.animal.entity.Animal; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; - -import java.util.List; - -@Mapper -public interface AnimalMapper extends BaseMapper { - - /** - * 根据商家ID获取动物列表 - * @param merchantId 商家ID - * @return 动物列表 - */ - @Select("SELECT * FROM animals WHERE merchant_id = #{merchantId} ORDER BY created_at DESC") - List selectByMerchantId(@Param("merchantId") Long merchantId); - - /** - * 根据物种获取动物列表 - * @param species 物种 - * @return 动物列表 - */ - @Select("SELECT * FROM animals WHERE species = #{species} ORDER BY created_at DESC") - List selectBySpecies(@Param("species") String species); - - /** - * 根据状态获取动物列表 - * @param status 状态 - * @return 动物列表 - */ - @Select("SELECT * FROM animals WHERE status = #{status} ORDER BY created_at DESC") - List selectByStatus(@Param("status") String status); -} \ No newline at end of file diff --git a/backend-java/animal-service/src/main/java/com/jiebanke/animal/service/AnimalService.java b/backend-java/animal-service/src/main/java/com/jiebanke/animal/service/AnimalService.java deleted file mode 100644 index 9b9d569..0000000 --- a/backend-java/animal-service/src/main/java/com/jiebanke/animal/service/AnimalService.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.jiebanke.animal.service; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.jiebanke.animal.entity.Animal; - -import java.util.List; -import java.util.Map; - -public interface AnimalService extends IService { - - /** - * 获取动物列表 - * @param merchantId 商家ID - * @param page 页码 - * @param pageSize 每页数量 - * @param species 物种 - * @param status 状态 - * @return 动物分页列表 - */ - IPage getAnimals(Long merchantId, Integer page, Integer pageSize, String species, String status); - - /** - * 获取单个动物详情 - * @param animalId 动物ID - * @return 动物信息 - */ - Animal getAnimalById(Long animalId); - - /** - * 创建动物 - * @param animal 动物信息 - * @return 创建的动物ID - */ - Long createAnimal(Animal animal); - - /** - * 更新动物信息 - * @param animalId 动物ID - * @param animal 更新的动物信息 - * @return 更新后的动物信息 - */ - Animal updateAnimal(Long animalId, Animal animal); - - /** - * 删除动物 - * @param animalId 动物ID - * @return 是否删除成功 - */ - boolean deleteAnimal(Long animalId); - - /** - * 获取动物统计信息 - * @return 统计信息 - */ - Map getAnimalStatistics(); - - /** - * 搜索动物 - * @param keyword 关键词 - * @param species 物种 - * @param minPrice 最低价格 - * @param maxPrice 最高价格 - * @param page 页码 - * @param pageSize 每页数量 - * @return 动物分页列表 - */ - IPage searchAnimals(String keyword, String species, Double minPrice, Double maxPrice, Integer page, Integer pageSize); -} \ No newline at end of file diff --git a/backend-java/animal-service/src/main/java/com/jiebanke/animal/service/impl/AnimalServiceImpl.java b/backend-java/animal-service/src/main/java/com/jiebanke/animal/service/impl/AnimalServiceImpl.java deleted file mode 100644 index 89b9559..0000000 --- a/backend-java/animal-service/src/main/java/com/jiebanke/animal/service/impl/AnimalServiceImpl.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.jiebanke.animal.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.jiebanke.animal.entity.Animal; -import com.jiebanke.animal.mapper.AnimalMapper; -import com.jiebanke.animal.service.AnimalService; -import com.jiebanke.common.exception.BusinessException; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@Service -public class AnimalServiceImpl extends ServiceImpl implements AnimalService { - - @Override - public IPage getAnimals(Long merchantId, Integer page, Integer pageSize, String species, String status) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - - if (merchantId != null) { - queryWrapper.eq("merchant_id", merchantId); - } - - if (species != null && !species.isEmpty()) { - queryWrapper.eq("species", species); - } - - if (status != null && !status.isEmpty()) { - queryWrapper.eq("status", status); - } - - queryWrapper.orderByDesc("created_at"); - - Page pageObj = new Page<>(page != null ? page : 1, pageSize != null ? pageSize : 10); - return this.page(pageObj, queryWrapper); - } - - @Override - public Animal getAnimalById(Long animalId) { - Animal animal = this.getById(animalId); - if (animal == null) { - throw new BusinessException("动物不存在"); - } - return animal; - } - - @Override - public Long createAnimal(Animal animal) { - this.save(animal); - return animal.getId(); - } - - @Override - public Animal updateAnimal(Long animalId, Animal animal) { - Animal existingAnimal = this.getById(animalId); - if (existingAnimal == null) { - throw new BusinessException("动物不存在"); - } - - // 更新字段 - if (animal.getName() != null) { - existingAnimal.setName(animal.getName()); - } - if (animal.getSpecies() != null) { - existingAnimal.setSpecies(animal.getSpecies()); - } - if (animal.getBreed() != null) { - existingAnimal.setBreed(animal.getBreed()); - } - if (animal.getBirthDate() != null) { - existingAnimal.setBirthDate(animal.getBirthDate()); - } - if (animal.getPersonality() != null) { - existingAnimal.setPersonality(animal.getPersonality()); - } - if (animal.getFarmLocation() != null) { - existingAnimal.setFarmLocation(animal.getFarmLocation()); - } - if (animal.getPrice() != null) { - existingAnimal.setPrice(animal.getPrice()); - } - if (animal.getStatus() != null) { - existingAnimal.setStatus(animal.getStatus()); - } - - this.updateById(existingAnimal); - return existingAnimal; - } - - @Override - public boolean deleteAnimal(Long animalId) { - return this.removeById(animalId); - } - - @Override - public Map getAnimalStatistics() { - // 获取动物总数 - int total = Math.toIntExact(this.count()); - - // 按物种统计 - QueryWrapper speciesWrapper = new QueryWrapper<>(); - speciesWrapper.select("species", "COUNT(*) as count"); - speciesWrapper.groupBy("species"); - List> speciesStats = this.listMaps(speciesWrapper); - - // 按状态统计 - QueryWrapper statusWrapper = new QueryWrapper<>(); - statusWrapper.select("status", "COUNT(*) as count"); - statusWrapper.groupBy("status"); - List> statusStats = this.listMaps(statusWrapper); - - // 构建返回结果 - Map statistics = new HashMap<>(); - statistics.put("total", total); - statistics.put("bySpecies", speciesStats); - statistics.put("byStatus", statusStats); - - return statistics; - } - - @Override - public IPage searchAnimals(String keyword, String species, Double minPrice, Double maxPrice, Integer page, Integer pageSize) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("status", "available"); - - if (keyword != null && !keyword.isEmpty()) { - queryWrapper.and(wrapper -> wrapper - .like("name", keyword) - .or() - .like("personality", keyword) - .or() - .like("species", keyword)); - } - - if (species != null && !species.isEmpty()) { - queryWrapper.eq("species", species); - } - - if (minPrice != null) { - queryWrapper.ge("price", minPrice); - } - - if (maxPrice != null) { - queryWrapper.le("price", maxPrice); - } - - queryWrapper.orderByDesc("created_at"); - - Page pageObj = new Page<>(page != null ? page : 1, pageSize != null ? pageSize : 10); - return this.page(pageObj, queryWrapper); - } -} \ No newline at end of file diff --git a/backend-java/animal-service/src/main/resources/application.yml b/backend-java/animal-service/src/main/resources/application.yml deleted file mode 100644 index 4566c3e..0000000 --- a/backend-java/animal-service/src/main/resources/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8084 - -spring: - application: - name: animal-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/animal-service/target/classes/application.yml b/backend-java/animal-service/target/classes/application.yml deleted file mode 100644 index 4566c3e..0000000 --- a/backend-java/animal-service/target/classes/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8084 - -spring: - application: - name: animal-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/animal-service/target/classes/com/jiebanke/animal/AnimalApplication.class b/backend-java/animal-service/target/classes/com/jiebanke/animal/AnimalApplication.class deleted file mode 100644 index 521b0e6015608c6e019ee2f71cdec14ad99fa44a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1085 zcma)5+iuf95S>kvCNY78&<5IaaSMph2k#5wfkLG;v=WlJs40<9pVrRC-NfFt*6Toj zgkM1d3EufA#MnucLLUKYxAw4gfFUK^Y1J9{MVxBf&i;$DA@LA{Nq4 z?mBTC3ZEIFWEqMC8Y4DgG-NWMZ@m%s4T06?LJG4_V5R-IPoUUU173zIf%+o$P-~?t zaD~9<_fqpjg%duo@!42}Ik+8b<%K*-p4nFQ%>EbKEavh{4UXwF1J;F0@ZRo%miMNCKnt@i1% zcPr2$u>J3yms0(;kx|�B?iQGKkmFb!F`eX*;%x099KmjcG3~_9ea6@tN~E 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 XbW*eeJjLu3U^muht^a#y?*se~S|B|p diff --git a/backend-java/animal-service/target/classes/com/jiebanke/animal/mapper/AnimalMapper.class b/backend-java/animal-service/target/classes/com/jiebanke/animal/mapper/AnimalMapper.class deleted file mode 100644 index b403f10800d32bca38c75b10f1843449453d728c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1230 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 Xs8plXST# - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - auth-service - jar - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - org.springframework.cloud - spring-cloud-starter-openfeign - - - - - com.baomidou - mybatis-plus-boot-starter - - - - - mysql - mysql-connector-java - - - - - io.jsonwebtoken - jjwt-api - - - io.jsonwebtoken - jjwt-impl - runtime - - - io.jsonwebtoken - jjwt-jackson - runtime - - - - - org.springframework.security - spring-security-crypto - - - - - org.springframework.boot - spring-boot-starter-data-redis - - - - - org.springframework.boot - spring-boot-starter-amqp - - - - - com.jiebanke - common - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/AuthApplication.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/AuthApplication.java deleted file mode 100644 index 319862b..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/AuthApplication.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.jiebanke.auth; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; - -@SpringBootApplication -@EnableDiscoveryClient -@EnableFeignClients -@MapperScan("com.jiebanke.auth.mapper") -@ComponentScan(basePackages = "com.jiebanke") -public class AuthApplication { - public static void main(String[] args) { - SpringApplication.run(AuthApplication.class, args); - } - - @Bean - public BCryptPasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/controller/AuthController.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/controller/AuthController.java deleted file mode 100644 index cdda871..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/controller/AuthController.java +++ /dev/null @@ -1,187 +0,0 @@ -package com.jiebanke.auth.controller; - -import com.jiebanke.auth.service.AuthRedisService; -import com.jiebanke.common.vo.ApiResponse; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/api/auth") -public class AuthController { - - @Autowired - private AuthService authService; - - @Value("${jwt.secret}") - private String jwtSecret; - - @Autowired - private AuthRedisService authRedisService; - - /** - * 用户注册 - */ - @PostMapping("/register") - public ApiResponse register(@RequestBody RegisterRequest request) { - User user = new User(); - user.setUsername(request.getUsername()); - user.setEmail(request.getEmail()); - user.setPhone(request.getPhone()); - user.setRealName(request.getNickname()); - - AuthResult result = authService.register(user, request.getPassword()); - return ApiResponse.success(result); - } - - /** - * 用户登录 - */ - @PostMapping("/login") - public ApiResponse login(@RequestBody LoginRequest request) { - AuthResult result = authService.login(request.getUsername(), request.getPassword()); - return ApiResponse.success(result); - } - - /** - * 获取当前用户信息 - */ - @GetMapping("/me") - public ApiResponse getCurrentUser(@RequestHeader("userId") Long userId) { - User user = authService.getCurrentUser(userId); - return ApiResponse.success(user); - } - - /** - * 更新用户个人信息 - */ - @PutMapping("/profile") - public ApiResponse updateProfile( - @RequestHeader("userId") Long userId, - @RequestBody User user) { - User updatedUser = authService.updateProfile(userId, user); - return ApiResponse.success(updatedUser); - } - - /** - * 修改密码 - */ - @PutMapping("/password") - public ApiResponse> changePassword( - @RequestHeader("userId") Long userId, - @RequestBody ChangePasswordRequest request) { - boolean success = authService.changePassword(userId, request.getCurrentPassword(), request.getNewPassword()); - - Map result = new HashMap<>(); - result.put("message", success ? "密码修改成功" : "密码修改失败"); - return ApiResponse.success(result); - } - - /** - * 微信登录/注册 - */ - @PostMapping("/wechat") - public ApiResponse wechatLogin(@RequestBody WechatLoginRequest request) { - AuthResult result = authService.wechatLogin(request.getCode(), request.getUserInfo()); - return ApiResponse.success(result); - } - - /** - * 管理员登录 - */ - @PostMapping("/admin/login") - public ApiResponse adminLogin(@RequestBody LoginRequest request) { - AuthResult result = authService.adminLogin(request.getUsername(), request.getPassword()); - return ApiResponse.success(result); - } - - @GetMapping("/validate") - public ApiResponse validateToken(@RequestHeader("Authorization") String token) { - try { - // 移除 "Bearer " 前缀 - if (token.startsWith("Bearer ")) { - token = token.substring(7); - } - - // 解析JWT令牌 - Claims claims = Jwts.parserBuilder() - .setSigningKey(jwtSecret.getBytes()) - .build() - .parseClaimsJws(token) - .getBody(); - - // 从Redis中获取用户登录状态 - Long userId = authRedisService.getUserLoginStatus(token); - if (userId != null && userId.equals(claims.get("userId", Long.class))) { - return ApiResponse.success(true); - } - - return ApiResponse.success(false); - } catch (Exception e) { - return ApiResponse.success(false); - } - } - - // 请求体类 - static class RegisterRequest { - private String username; - private String password; - private String nickname; - private String email; - private String phone; - - // Getters and setters - public String getUsername() { return username; } - public void setUsername(String username) { this.username = username; } - - public String getPassword() { return password; } - public void setPassword(String password) { this.password = password; } - - public String getNickname() { return nickname; } - public void setNickname(String nickname) { this.nickname = nickname; } - - public String getEmail() { return email; } - public void setEmail(String email) { this.email = email; } - - public String getPhone() { return phone; } - public void setPhone(String phone) { this.phone = phone; } - } - - static class LoginRequest { - private String username; - private String password; - - // Getters and setters - public String getUsername() { return username; } - public void setUsername(String username) { this.username = username; } - - public String getPassword() { return password; } - public void setPassword(String password) { this.password = password; } - } - - static class ChangePasswordRequest { - private String currentPassword; - private String newPassword; - - // Getters and setters - public String getCurrentPassword() { return currentPassword; } - public void setCurrentPassword(String currentPassword) { this.currentPassword = currentPassword; } - - public String getNewPassword() { return newPassword; } - public void setNewPassword(String newPassword) { this.newPassword = newPassword; } - } - - static class WechatLoginRequest { - private String code; - private Object userInfo; - - // Getters and setters - public String getCode() { return code; } - public void setCode(String code) { this.code = code; } - - public Object getUserInfo() { return userInfo; } - public void setUserInfo(Object userInfo) { this.userInfo = userInfo; } - } -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/entity/User.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/entity/User.java deleted file mode 100644 index a0258a8..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/entity/User.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.jiebanke.auth.entity; - -import com.jiebanke.common.entity.BaseEntity; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -@Data -@EqualsAndHashCode(callSuper = true) -public class User extends BaseEntity { - private String username; - private String password; - private String email; - private String phone; - private String realName; - private String idCard; - private String status; - private BigDecimal balance; - private Integer creditScore; - private LocalDateTime lastLogin; -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/mapper/UserMapper.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/mapper/UserMapper.java deleted file mode 100644 index 6a50446..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/mapper/UserMapper.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.jiebanke.auth.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.jiebanke.auth.entity.User; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; -import org.apache.ibatis.annotations.Update; - -@Mapper -public interface UserMapper extends BaseMapper { - - /** - * 根据用户名查找用户 - * @param username 用户名 - * @return 用户 - */ - @Select("SELECT * FROM users WHERE username = #{username}") - User selectByUsername(@Param("username") String username); - - /** - * 根据邮箱查找用户 - * @param email 邮箱 - * @return 用户 - */ - @Select("SELECT * FROM users WHERE email = #{email}") - User selectByEmail(@Param("email") String email); - - /** - * 根据手机号查找用户 - * @param phone 手机号 - * @return 用户 - */ - @Select("SELECT * FROM users WHERE phone = #{phone}") - User selectByPhone(@Param("phone") String phone); - - /** - * 检查用户名是否存在 - * @param username 用户名 - * @return 是否存在 - */ - @Select("SELECT COUNT(*) FROM users WHERE username = #{username}") - int existsByUsername(@Param("username") String username); - - /** - * 检查邮箱是否存在 - * @param email 邮箱 - * @return 是否存在 - */ - @Select("SELECT COUNT(*) FROM users WHERE email = #{email}") - int existsByEmail(@Param("email") String email); - - /** - * 检查手机号是否存在 - * @param phone 手机号 - * @return 是否存在 - */ - @Select("SELECT COUNT(*) FROM users WHERE phone = #{phone}") - int existsByPhone(@Param("phone") String phone); - - /** - * 更新最后登录时间 - * @param id 用户ID - * @return 更新记录数 - */ - @Update("UPDATE users SET last_login = NOW(), updated_at = NOW() WHERE id = #{id}") - int updateLastLogin(@Param("id") Long id); -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthRabbitMQService.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthRabbitMQService.java deleted file mode 100644 index cb55afe..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthRabbitMQService.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.jiebanke.auth.service; - -import com.jiebanke.common.config.RabbitMQConfig; -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.Map; - -@Service -public class AuthRabbitMQService { - - @Autowired - private RabbitTemplate rabbitTemplate; - - // 发送登录成功消息 - public void sendLoginSuccessMessage(Long userId, String username, String ip) { - Map message = new HashMap<>(); - message.put("userId", userId); - message.put("username", username); - message.put("ip", ip); - message.put("eventType", "USER_LOGIN_SUCCESS"); - - rabbitTemplate.convertAndSend( - RabbitMQConfig.EXCHANGE_NAME, - RabbitMQConfig.USER_ROUTING_KEY, - message - ); - } - - // 发送登录失败消息 - public void sendLoginFailureMessage(String username, String ip, String reason) { - Map message = new HashMap<>(); - message.put("username", username); - message.put("ip", ip); - message.put("reason", reason); - message.put("eventType", "USER_LOGIN_FAILURE"); - - rabbitTemplate.convertAndSend( - RabbitMQConfig.EXCHANGE_NAME, - RabbitMQConfig.USER_ROUTING_KEY, - message - ); - } -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthRedisService.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthRedisService.java deleted file mode 100644 index 79935f7..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthRedisService.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.jiebanke.auth.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.util.concurrent.TimeUnit; - -@Service -public class AuthRedisService { - - @Autowired - private RedisTemplate redisTemplate; - - // 缓存验证码 - public void cacheVerificationCode(String phone, String code) { - redisTemplate.opsForValue().set("verification:code:" + phone, code, 5, TimeUnit.MINUTES); - } - - // 获取缓存的验证码 - public String getCachedVerificationCode(String phone) { - return (String) redisTemplate.opsForValue().get("verification:code:" + phone); - } - - // 删除缓存的验证码 - public void removeCachedVerificationCode(String phone) { - redisTemplate.delete("verification:code:" + phone); - } - - // 缓存登录失败次数 - public void cacheLoginFailures(String identifier, Integer failures) { - redisTemplate.opsForValue().set("login:failures:" + identifier, failures, 1, TimeUnit.HOURS); - } - - // 获取登录失败次数 - public Integer getLoginFailures(String identifier) { - return (Integer) redisTemplate.opsForValue().get("login:failures:" + identifier); - } - - // 增加登录失败次数 - public void incrementLoginFailures(String identifier) { - Integer failures = getLoginFailures(identifier); - if (failures == null) { - failures = 0; - } - redisTemplate.opsForValue().set("login:failures:" + identifier, failures + 1, 1, TimeUnit.HOURS); - } - - // 清除登录失败次数 - public void clearLoginFailures(String identifier) { - redisTemplate.delete("login:failures:" + identifier); - } -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthResult.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthResult.java deleted file mode 100644 index 3ee6a58..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthResult.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.jiebanke.auth.service; - -import com.jiebanke.auth.entity.User; -import lombok.Data; - -@Data -public class AuthResult { - private User user; - private String token; - private String message; -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthService.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthService.java deleted file mode 100644 index fa87491..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/AuthService.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.jiebanke.auth.service; - -import com.jiebanke.auth.entity.User; - -public interface AuthService { - - /** - * 用户注册 - * @param user 用户信息 - * @return 注册后的用户信息和Token - */ - AuthResult register(User user, String password); - - /** - * 用户登录 - * @param username 用户名/邮箱/手机号 - * @param password 密码 - * @return 登录后的用户信息和Token - */ - AuthResult login(String username, String password); - - /** - * 获取当前用户信息 - * @param userId 用户ID - * @return 用户信息 - */ - User getCurrentUser(Long userId); - - /** - * 更新用户信息 - * @param userId 用户ID - * @param user 更新的用户信息 - * @return 更新后的用户信息 - */ - User updateProfile(Long userId, User user); - - /** - * 修改密码 - * @param userId 用户ID - * @param currentPassword 当前密码 - * @param newPassword 新密码 - * @return 是否修改成功 - */ - boolean changePassword(Long userId, String currentPassword, String newPassword); - - /** - * 微信登录/注册 - * @param code 微信授权码 - * @param userInfo 微信用户信息 - * @return 登录后的用户信息和Token - */ - AuthResult wechatLogin(String code, Object userInfo); - - /** - * 管理员登录 - * @param username 用户名/邮箱/手机号 - * @param password 密码 - * @return 登录后的管理员信息和Token - */ - AuthResult adminLogin(String username, String password); -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/impl/AuthServiceImpl.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/impl/AuthServiceImpl.java deleted file mode 100644 index 1e69b31..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/service/impl/AuthServiceImpl.java +++ /dev/null @@ -1,255 +0,0 @@ -package com.jiebanke.auth.service.impl; - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.jiebanke.auth.entity.User; -import com.jiebanke.auth.mapper.UserMapper; -import com.jiebanke.auth.service.AuthResult; -import com.jiebanke.auth.service.AuthService; -import com.jiebanke.auth.util.JwtUtil; -import com.jiebanke.common.exception.BusinessException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.stereotype.Service; - -@Service -public class AuthServiceImpl extends ServiceImpl implements AuthService { - - @Autowired - private UserMapper userMapper; - - @Autowired - private JwtUtil jwtUtil; - - @Autowired - private BCryptPasswordEncoder passwordEncoder; - - @Override - public AuthResult register(User user, String password) { - // 检查用户名是否已存在 - if (userMapper.existsByUsername(user.getUsername()) > 0) { - throw new BusinessException("用户名已存在"); - } - - // 检查邮箱是否已存在 - if (user.getEmail() != null && userMapper.existsByEmail(user.getEmail()) > 0) { - throw new BusinessException("邮箱已存在"); - } - - // 检查手机号是否已存在 - if (user.getPhone() != null && userMapper.existsByPhone(user.getPhone()) > 0) { - throw new BusinessException("手机号已存在"); - } - - // 加密密码 - String hashedPassword = passwordEncoder.encode(password); - user.setPassword(hashedPassword); - - // 设置默认值 - if (user.getStatus() == null) { - user.setStatus("active"); - } - - // 创建新用户 - this.save(user); - - // 生成Token - String token = jwtUtil.generateToken(user.getId()); - - // 更新最后登录时间 - userMapper.updateLastLogin(user.getId()); - - // 创建返回结果 - AuthResult result = new AuthResult(); - result.setUser(user); - result.setToken(token); - result.setMessage("注册成功"); - - return result; - } - - @Override - public AuthResult login(String username, String password) { - if (username == null || username.isEmpty() || password == null || password.isEmpty()) { - throw new BusinessException("用户名和密码不能为空"); - } - - // 查找用户(支持用户名、邮箱、手机号登录) - User user = userMapper.selectByUsername(username); - if (user == null) { - user = userMapper.selectByEmail(username); - } - if (user == null) { - user = userMapper.selectByPhone(username); - } - - if (user == null) { - throw new BusinessException("用户不存在"); - } - - // 检查用户状态 - if (!"active".equals(user.getStatus())) { - throw new BusinessException("账户已被禁用"); - } - - // 验证密码 - if (!passwordEncoder.matches(password, user.getPassword())) { - throw new BusinessException("密码错误"); - } - - // 生成Token - String token = jwtUtil.generateToken(user.getId()); - - // 更新最后登录时间 - userMapper.updateLastLogin(user.getId()); - - // 创建返回结果 - AuthResult result = new AuthResult(); - result.setUser(user); - result.setToken(token); - result.setMessage("登录成功"); - - return result; - } - - @Override - public User getCurrentUser(Long userId) { - User user = this.getById(userId); - if (user == null) { - throw new BusinessException("用户不存在"); - } - return user; - } - - @Override - public User updateProfile(Long userId, User user) { - User existingUser = this.getById(userId); - if (existingUser == null) { - throw new BusinessException("用户不存在"); - } - - // 更新字段 - if (user.getRealName() != null) { - existingUser.setRealName(user.getRealName()); - } - if (user.getEmail() != null) { - existingUser.setEmail(user.getEmail()); - } - if (user.getPhone() != null) { - existingUser.setPhone(user.getPhone()); - } - - this.updateById(existingUser); - return existingUser; - } - - @Override - public boolean changePassword(Long userId, String currentPassword, String newPassword) { - if (currentPassword == null || currentPassword.isEmpty() || newPassword == null || newPassword.isEmpty()) { - throw new BusinessException("当前密码和新密码不能为空"); - } - - if (newPassword.length() < 6) { - throw new BusinessException("新密码长度不能少于6位"); - } - - User user = this.getById(userId); - if (user == null) { - throw new BusinessException("用户不存在"); - } - - // 验证当前密码 - if (!passwordEncoder.matches(currentPassword, user.getPassword())) { - throw new BusinessException("当前密码错误"); - } - - // 加密新密码 - String hashedPassword = passwordEncoder.encode(newPassword); - user.setPassword(hashedPassword); - - // 更新密码 - return this.updateById(user); - } - - @Override - public AuthResult wechatLogin(String code, Object userInfo) { - if (code == null || code.isEmpty()) { - throw new BusinessException("微信授权码不能为空"); - } - - // 这里应该调用微信API获取openid和unionid - // 模拟获取微信用户信息 - String openid = "mock_openid_" + System.currentTimeMillis(); - - // 查找是否已存在微信用户 - // 注意:在实际实现中,应该有一个专门的字段来存储微信openid - User user = null; - - if (user == null) { - // 创建新用户(微信注册) - user = new User(); - user.setUsername("wx_" + openid.substring(Math.max(0, openid.length() - 8))); - String randomPassword = String.valueOf(System.currentTimeMillis()).substring(0, 8); - String hashedPassword = passwordEncoder.encode(randomPassword); - user.setPassword(hashedPassword); - user.setRealName("微信用户"); - user.setStatus("active"); - - this.save(user); - } - - // 生成Token - String token = jwtUtil.generateToken(user.getId()); - - // 创建返回结果 - AuthResult result = new AuthResult(); - result.setUser(user); - result.setToken(token); - result.setMessage("微信登录成功"); - - return result; - } - - @Override - public AuthResult adminLogin(String username, String password) { - if (username == null || username.isEmpty() || password == null || password.isEmpty()) { - throw new BusinessException("用户名和密码不能为空"); - } - - // 查找用户(支持用户名、邮箱、手机号登录) - User user = userMapper.selectByUsername(username); - if (user == null) { - user = userMapper.selectByEmail(username); - } - if (user == null) { - user = userMapper.selectByPhone(username); - } - - if (user == null) { - throw new BusinessException("用户不存在"); - } - - // 检查用户状态 - if (!"active".equals(user.getStatus())) { - throw new BusinessException("账户已被禁用"); - } - - // 验证密码 - if (!passwordEncoder.matches(password, user.getPassword())) { - throw new BusinessException("密码错误"); - } - - // 生成Token - String token = jwtUtil.generateToken(user.getId()); - - // 更新最后登录时间 - userMapper.updateLastLogin(user.getId()); - - // 创建返回结果 - AuthResult result = new AuthResult(); - result.setUser(user); - result.setToken(token); - result.setMessage("管理员登录成功"); - - return result; - } -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/java/com/jiebanke/auth/util/JwtUtil.java b/backend-java/auth-service/src/main/java/com/jiebanke/auth/util/JwtUtil.java deleted file mode 100644 index b2c7343..0000000 --- a/backend-java/auth-service/src/main/java/com/jiebanke/auth/util/JwtUtil.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.jiebanke.auth.util; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -@Component -public class JwtUtil { - - @Value("${jwt.secret:mySecretKey}") - private String secret; - - @Value("${jwt.expiration:604800}") - private Long expiration; - - /** - * 生成JWT Token - * @param userId 用户ID - * @return JWT Token - */ - public String generateToken(Long userId) { - Map claims = new HashMap<>(); - return createToken(claims, userId.toString()); - } - - /** - * 从JWT Token中提取用户ID - * @param token JWT Token - * @return 用户ID - */ - public Long extractUserId(String token) { - return Long.valueOf(extractClaim(token, Claims::getSubject)); - } - - /** - * 验证JWT Token是否有效 - * @param token JWT Token - * @param userId 用户ID - * @return 是否有效 - */ - public Boolean validateToken(String token, Long userId) { - final Long extractedUserId = extractUserId(token); - return (extractedUserId.equals(userId) && !isTokenExpired(token)); - } - - /** - * 从JWT Token中提取声明 - * @param token JWT Token - * @param claimsResolver 声明解析器 - * @param 声明类型 - * @return 声明值 - */ - public T extractClaim(String token, Function claimsResolver) { - final Claims claims = extractAllClaims(token); - return claimsResolver.apply(claims); - } - - /** - * 从JWT Token中提取所有声明 - * @param token JWT Token - * @return 所有声明 - */ - private Claims extractAllClaims(String token) { - return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); - } - - /** - * 检查JWT Token是否过期 - * @param token JWT Token - * @return 是否过期 - */ - private Boolean isTokenExpired(String token) { - return extractExpiration(token).before(new Date()); - } - - /** - * 从JWT Token中提取过期时间 - * @param token JWT Token - * @return 过期时间 - */ - public Date extractExpiration(String token) { - return extractClaim(token, Claims::getExpiration); - } - - /** - * 创建JWT Token - * @param claims 声明 - * @param subject 主题 - * @return JWT Token - */ - private String createToken(Map claims, String subject) { - return Jwts.builder() - .setClaims(claims) - .setSubject(subject) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)) - .signWith(SignatureAlgorithm.HS512, secret) - .compact(); - } -} \ No newline at end of file diff --git a/backend-java/auth-service/src/main/resources/application.yml b/backend-java/auth-service/src/main/resources/application.yml deleted file mode 100644 index 8a4c2fc..0000000 --- a/backend-java/auth-service/src/main/resources/application.yml +++ /dev/null @@ -1,36 +0,0 @@ -server: - port: 8081 - -spring: - application: - name: auth-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -jwt: - secret: mySecretKey - expiration: 604800 - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/auth-service/src/test/java/com/jiebanke/auth/service/AuthRabbitMQServiceTest.java b/backend-java/auth-service/src/test/java/com/jiebanke/auth/service/AuthRabbitMQServiceTest.java deleted file mode 100644 index 2bf8097..0000000 --- a/backend-java/auth-service/src/test/java/com/jiebanke/auth/service/AuthRabbitMQServiceTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.jiebanke.auth.service; - -import com.jiebanke.common.config.RabbitMQConfig; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.amqp.rabbit.core.RabbitTemplate; - -import static org.mockito.Mockito.*; - -class AuthRabbitMQServiceTest { - - @Mock - private RabbitTemplate rabbitTemplate; - - @InjectMocks - private AuthRabbitMQService authRabbitMQService; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - void testSendLoginSuccessMessage() { - Long userId = 1L; - String username = "testUser"; - String ip = "127.0.0.1"; - - authRabbitMQService.sendLoginSuccessMessage(userId, username, ip); - - verify(rabbitTemplate).convertAndSend( - RabbitMQConfig.EXCHANGE_NAME, - RabbitMQConfig.USER_ROUTING_KEY, - anyMap() - ); - } - - @Test - void testSendLoginFailureMessage() { - String username = "testUser"; - String ip = "127.0.0.1"; - String reason = "Invalid credentials"; - - authRabbitMQService.sendLoginFailureMessage(username, ip, reason); - - verify(rabbitTemplate).convertAndSend( - RabbitMQConfig.EXCHANGE_NAME, - RabbitMQConfig.USER_ROUTING_KEY, - anyMap() - ); - } -} \ No newline at end of file diff --git a/backend-java/auth-service/src/test/java/com/jiebanke/auth/service/AuthRedisServiceTest.java b/backend-java/auth-service/src/test/java/com/jiebanke/auth/service/AuthRedisServiceTest.java deleted file mode 100644 index 5486396..0000000 --- a/backend-java/auth-service/src/test/java/com/jiebanke/auth/service/AuthRedisServiceTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.jiebanke.auth.service; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ValueOperations; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -class AuthRedisServiceTest { - - @Mock - private RedisTemplate redisTemplate; - - @Mock - private ValueOperations valueOperations; - - @InjectMocks - private AuthRedisService authRedisService; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - when(redisTemplate.opsForValue()).thenReturn(valueOperations); - } - - @Test - void testCacheVerificationCode() { - String phone = "13800138000"; - String code = "123456"; - - authRedisService.cacheVerificationCode(phone, code); - - verify(valueOperations).set(eq("verification:code:" + phone), eq(code), anyLong(), any()); - } - - @Test - void testGetCachedVerificationCode() { - String phone = "13800138000"; - String code = "123456"; - when(valueOperations.get("verification:code:" + phone)).thenReturn(code); - - String result = authRedisService.getCachedVerificationCode(phone); - - assertEquals(code, result); - verify(valueOperations).get("verification:code:" + phone); - } - - @Test - void testRemoveCachedVerificationCode() { - String phone = "13800138000"; - - authRedisService.removeCachedVerificationCode(phone); - - verify(redisTemplate).delete("verification:code:" + phone); - } - - @Test - void testCacheLoginFailures() { - String identifier = "testUser"; - Integer failures = 3; - - authRedisService.cacheLoginFailures(identifier, failures); - - verify(valueOperations).set(eq("login:failures:" + identifier), eq(failures), anyLong(), any()); - } - - @Test - void testGetLoginFailures() { - String identifier = "testUser"; - Integer failures = 3; - when(valueOperations.get("login:failures:" + identifier)).thenReturn(failures); - - Integer result = authRedisService.getLoginFailures(identifier); - - assertEquals(failures, result); - verify(valueOperations).get("login:failures:" + identifier); - } - - @Test - void testIncrementLoginFailures() { - String identifier = "testUser"; - when(valueOperations.get("login:failures:" + identifier)).thenReturn(null); - - authRedisService.incrementLoginFailures(identifier); - - verify(valueOperations).set(eq("login:failures:" + identifier), eq(1), anyLong(), any()); - } - - @Test - void testIncrementLoginFailuresWithExistingValue() { - String identifier = "testUser"; - when(valueOperations.get("login:failures:" + identifier)).thenReturn(2); - - authRedisService.incrementLoginFailures(identifier); - - verify(valueOperations).set(eq("login:failures:" + identifier), eq(3), anyLong(), any()); - } - - @Test - void testClearLoginFailures() { - String identifier = "testUser"; - - authRedisService.clearLoginFailures(identifier); - - verify(redisTemplate).delete("login:failures:" + identifier); - } -} \ No newline at end of file diff --git a/backend-java/auth-service/target/classes/application.yml b/backend-java/auth-service/target/classes/application.yml deleted file mode 100644 index 8a4c2fc..0000000 --- a/backend-java/auth-service/target/classes/application.yml +++ /dev/null @@ -1,36 +0,0 @@ -server: - port: 8081 - -spring: - application: - name: auth-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -jwt: - secret: mySecretKey - expiration: 604800 - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/build-services.sh b/backend-java/build-services.sh deleted file mode 100755 index 5046eca..0000000 --- a/backend-java/build-services.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -# 构建结伴客Java后端服务脚本 - -echo "开始构建结伴客Java后端服务..." - -# 清理之前的构建 -echo "清理项目..." -mvn clean - -# 构建所有模块 -echo "构建所有模块..." -mvn install - -# 检查构建是否成功 -if [ $? -eq 0 ]; then - echo "构建成功!" - - # 显示构建结果 - echo "构建产物位置:" - echo " Eureka Server: eureka-server/target/" - echo " Gateway Service: gateway-service/target/" - echo " Auth Service: auth-service/target/" - echo " User Service: user-service/target/" - echo " Travel Service: travel-service/target/" - echo " Animal Service: animal-service/target/" - echo " Order Service: order-service/target/" - echo " Promotion Service: promotion-service/target/" - - # 复制jar包到各自目录以便Docker构建 - echo "复制jar包..." - cp eureka-server/target/eureka-server.jar eureka-server/ - cp gateway-service/target/gateway-service.jar gateway-service/ - cp auth-service/target/auth-service.jar auth-service/ - cp user-service/target/user-service.jar user-service/ - cp travel-service/target/travel-service.jar travel-service/ - cp animal-service/target/animal-service.jar animal-service/ - cp order-service/target/order-service.jar order-service/ - cp promotion-service/target/promotion-service.jar promotion-service/ - - echo "所有服务构建完成,可以使用docker-compose启动服务" -else - echo "构建失败,请检查错误信息" -fi \ No newline at end of file diff --git a/backend-java/common/pom.xml b/backend-java/common/pom.xml deleted file mode 100644 index 9e13092..0000000 --- a/backend-java/common/pom.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - common - jar - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.projectlombok - lombok - true - - - - - org.springframework.boot - spring-boot-starter-validation - - - \ No newline at end of file diff --git a/backend-java/common/src/main/java/com/jiebanke/common/config/FeignConfig.java b/backend-java/common/src/main/java/com/jiebanke/common/config/FeignConfig.java deleted file mode 100644 index a8023e5..0000000 --- a/backend-java/common/src/main/java/com/jiebanke/common/config/FeignConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.jiebanke.common.config; - -import feign.Request; -import feign.Retryer; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.concurrent.TimeUnit; - -@Configuration -public class FeignConfig { - - @Bean - public Request.Options options() { - return new Request.Options(5, TimeUnit.SECONDS, 30, TimeUnit.SECONDS, true); - } - - @Bean - public Retryer retryer() { - return new Retryer.Default(100, 1000, 3); - } -} \ No newline at end of file diff --git a/backend-java/common/src/main/java/com/jiebanke/common/config/RabbitMQConfig.java b/backend-java/common/src/main/java/com/jiebanke/common/config/RabbitMQConfig.java deleted file mode 100644 index 9873443..0000000 --- a/backend-java/common/src/main/java/com/jiebanke/common/config/RabbitMQConfig.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.jiebanke.common.config; - -import org.springframework.amqp.core.*; -import org.springframework.amqp.rabbit.connection.ConnectionFactory; -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; -import org.springframework.amqp.support.converter.MessageConverter; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class RabbitMQConfig { - - // 定义队列名称 - public static final String USER_QUEUE = "user.queue"; - public static final String TRAVEL_QUEUE = "travel.queue"; - public static final String ANIMAL_QUEUE = "animal.queue"; - public static final String ORDER_QUEUE = "order.queue"; - public static final String PROMOTION_QUEUE = "promotion.queue"; - - // 定义交换机名称 - public static final String EXCHANGE_NAME = "jiebanke.exchange"; - - // 定义路由键 - public static final String USER_ROUTING_KEY = "user.routing.key"; - public static final String TRAVEL_ROUTING_KEY = "travel.routing.key"; - public static final String ANIMAL_ROUTING_KEY = "animal.routing.key"; - public static final String ORDER_ROUTING_KEY = "order.routing.key"; - public static final String PROMOTION_ROUTING_KEY = "promotion.routing.key"; - - // 队列声明 - @Bean - public Queue userQueue() { - return new Queue(USER_QUEUE, true); - } - - @Bean - public Queue travelQueue() { - return new Queue(TRAVEL_QUEUE, true); - } - - @Bean - public Queue animalQueue() { - return new Queue(ANIMAL_QUEUE, true); - } - - @Bean - public Queue orderQueue() { - return new Queue(ORDER_QUEUE, true); - } - - @Bean - public Queue promotionQueue() { - return new Queue(PROMOTION_QUEUE, true); - } - - // 交换机声明 - @Bean - public TopicExchange exchange() { - return new TopicExchange(EXCHANGE_NAME); - } - - // 绑定关系 - @Bean - public Binding userBinding() { - return BindingBuilder.bind(userQueue()).to(exchange()).with(USER_ROUTING_KEY); - } - - @Bean - public Binding travelBinding() { - return BindingBuilder.bind(travelQueue()).to(exchange()).with(TRAVEL_ROUTING_KEY); - } - - @Bean - public Binding animalBinding() { - return BindingBuilder.bind(animalQueue()).to(exchange()).with(ANIMAL_ROUTING_KEY); - } - - @Bean - public Binding orderBinding() { - return BindingBuilder.bind(orderQueue()).to(exchange()).with(ORDER_ROUTING_KEY); - } - - @Bean - public Binding promotionBinding() { - return BindingBuilder.bind(promotionQueue()).to(exchange()).with(PROMOTION_ROUTING_KEY); - } - - // 消息转换器 - @Bean - public MessageConverter messageConverter() { - return new Jackson2JsonMessageConverter(); - } - - // RabbitTemplate配置 - @Bean - public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { - RabbitTemplate template = new RabbitTemplate(connectionFactory); - template.setMessageConverter(messageConverter()); - return template; - } -} \ No newline at end of file diff --git a/backend-java/common/src/main/java/com/jiebanke/common/config/RedisConfig.java b/backend-java/common/src/main/java/com/jiebanke/common/config/RedisConfig.java deleted file mode 100644 index 508350a..0000000 --- a/backend-java/common/src/main/java/com/jiebanke/common/config/RedisConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.jiebanke.common.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -public class RedisConfig { - - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(new StringRedisSerializer()); - return template; - } -} \ No newline at end of file diff --git a/backend-java/common/src/main/java/com/jiebanke/common/entity/BaseEntity.java b/backend-java/common/src/main/java/com/jiebanke/common/entity/BaseEntity.java deleted file mode 100644 index a4ac4f6..0000000 --- a/backend-java/common/src/main/java/com/jiebanke/common/entity/BaseEntity.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.jiebanke.common.entity; - -import lombok.Data; -import java.time.LocalDateTime; - -@Data -public class BaseEntity { - private Long id; - private LocalDateTime createdAt; - private LocalDateTime updatedAt; -} \ No newline at end of file diff --git a/backend-java/common/src/main/java/com/jiebanke/common/exception/BusinessException.java b/backend-java/common/src/main/java/com/jiebanke/common/exception/BusinessException.java deleted file mode 100644 index 4269717..0000000 --- a/backend-java/common/src/main/java/com/jiebanke/common/exception/BusinessException.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.jiebanke.common.exception; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -@Data -@EqualsAndHashCode(callSuper = true) -public class BusinessException extends RuntimeException { - private int code; - private String message; - - public BusinessException(String message) { - super(message); - this.code = 400; - this.message = message; - } - - public BusinessException(int code, String message) { - super(message); - this.code = code; - this.message = message; - } -} \ No newline at end of file diff --git a/backend-java/common/src/main/java/com/jiebanke/common/exception/GlobalExceptionHandler.java b/backend-java/common/src/main/java/com/jiebanke/common/exception/GlobalExceptionHandler.java deleted file mode 100644 index af75f3f..0000000 --- a/backend-java/common/src/main/java/com/jiebanke/common/exception/GlobalExceptionHandler.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.jiebanke.common.exception; - -import com.jiebanke.common.vo.ApiResponse; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestControllerAdvice; - -@RestControllerAdvice -public class GlobalExceptionHandler { - - @ExceptionHandler(BusinessException.class) - public ApiResponse handleBusinessException(BusinessException e) { - return ApiResponse.error(e.getCode(), e.getMessage()); - } - - @ExceptionHandler(Exception.class) - public ApiResponse handleException(Exception e) { - e.printStackTrace(); - return ApiResponse.error(500, "服务器内部错误"); - } -} \ No newline at end of file diff --git a/backend-java/common/src/main/java/com/jiebanke/common/vo/ApiResponse.java b/backend-java/common/src/main/java/com/jiebanke/common/vo/ApiResponse.java deleted file mode 100644 index 871ae2c..0000000 --- a/backend-java/common/src/main/java/com/jiebanke/common/vo/ApiResponse.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.jiebanke.common.vo; - -import lombok.Data; - -@Data -public class ApiResponse { - private boolean success; - private int code; - private String message; - private T data; - private long timestamp; - - public static ApiResponse success(T data) { - ApiResponse response = new ApiResponse<>(); - response.success = true; - response.code = 200; - response.message = "操作成功"; - response.data = data; - response.timestamp = System.currentTimeMillis(); - return response; - } - - public static ApiResponse success(T data, String message) { - ApiResponse response = new ApiResponse<>(); - response.success = true; - response.code = 200; - response.message = message; - response.data = data; - response.timestamp = System.currentTimeMillis(); - return response; - } - - public static ApiResponse error(int code, String message) { - ApiResponse response = new ApiResponse<>(); - response.success = false; - response.code = code; - response.message = message; - response.timestamp = System.currentTimeMillis(); - return response; - } -} \ No newline at end of file diff --git a/backend-java/common/target/classes/com/jiebanke/common/config/FeignConfig.class b/backend-java/common/target/classes/com/jiebanke/common/config/FeignConfig.class deleted file mode 100644 index 69bac0938bda0c16bf1d9451f53fe91b50ed384b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1017 zcma)4OK;Oa5dOAF;0xkF00}C3GE_?2NE|omG;A90hV{D8pT(&X zNO0#zA;wNfBUGuD<(-|`nQy*%{QmR(CxBOY=wU(NQQySjP*G3nBMMoGjb@<_)gas^ zHPBo6-9uTRK9t8Y97#P0cX~tWJAukerImXvP-<;<1+5xa zwN`Y-XxC+xw6g(tmYh8yE3llmC0E*2+$zd854ezR0WSf6*QB;j+bSD-eQueaX4D0q z7ahZ71yh@Mm*=s;^Z0M#9`1AToqxsG-m4_xp6qdV6KsI@lXo6`ifk|W^jHg73YLqH zPf`8Gmj(EIX3xMfe?V>G!15An0xMW$ulm&MGRq9;Sq=>NKhXHtxN?fCzt}pDwlat2 j&(PL!<3hBX=b$yuK`Y^Qp7YL(-Cfon@L%B^0q*?;7770U diff --git a/backend-java/common/target/classes/com/jiebanke/common/config/RabbitMQConfig.class b/backend-java/common/target/classes/com/jiebanke/common/config/RabbitMQConfig.class deleted file mode 100644 index 1c02901f57881ecd6334bd64e32d4968e7967ede..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4809 zcmd5Rwi@U{fm|RYu~-!+$q*K@yK#1d#oyqc z@l(&ybM(7Es;BQ>ve||4WPx*p5A5Q#X_!7S}o)|YfKRsYjHy}EY;9E%Zw;5 zmY!$wE6PqjlT+gG9)XEYXy(|f+8(-%=8iiK7YpUmYJO#BUD=Mq2RQ0@#ErIvPR|{% zBMgS;SBQEY$35@DWY5PCc?QXzry=r$>u-qr30muV9imQkeGkz;B{0>EKxoR9$EvPc zPYLuVQxyUOOGceZ&<~#tLlROLxvZ+Qd|RtBUZT||hGa5p)M&FpxoTr?aKPGAO#-vo z$R&oglCZDEOenaVo<;`ns2ty`+bDypgC5*b}LENUkYSGb!scq47L>~h=XRAavy z{J<_^i@mba)TgEw8PykJ@DN?-mZ`$I!Q=21f&H@1nQ1f+SzSh(TWZr;LB=rQlA8HQ zmJ*IVa?KHyt4#JMScXhx>!`&daU__BM|L>TwW;LEO=HJ>$So5u7(;Fyct~ID3vpN?@LL2|L(_V=dSs2n~BG3UFCn=)qHW@xHu zq9ZQTNkB-olZtbQhJq{MdFmF1=Up7u2$3%+W`PnthlBr5)Z7i^M=f`8Q44J4%O161 z=b-U}wn4~^3o5nliFes!HtwIte%!VQxp_fx^Nn$K*`<%2#!Qno7`BXuj9ZKoxP})* z?${{a6yFi}Jwiy2&lKDO_DSBkyVq##z%=yxYxp?bR05;iX_!k)YhmYrZPBe{7X8q% zO~yuLnbs_WA1$P^?sd|kp(`&5$wY7^JgC(Kb82Y$bl>NcyiBCjmMLN_oB3A zw0Vs!t9DCz)wQwn^)hESd;}gwZ51(m_zBeJP6voRd6HGr=nekXw6MLZqA?<4v!fImWfBYL42R8={(|}K z$uD2S*Z&~ugRa_4Kuz-19-mR|wovWK8P#TmYERFoc2B7G%^B6^g=*hIre_uw1zA`S zsyzdxr`obWEhAKW9zktYptdYjTaTcY6{xKX)$$S43Ieqaq1t8ywW2_+EL1B&xn~wC w0=1VywHL7cA8LL6KK)*xMg?m9@Po6PfAshLPlyljZxqjp9iUJH1`SZ(0;Z<%B>(^b diff --git a/backend-java/common/target/classes/com/jiebanke/common/config/RedisConfig.class b/backend-java/common/target/classes/com/jiebanke/common/config/RedisConfig.class deleted file mode 100644 index 602795cd5548d7b21495a4057461156abd284ee7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1155 zcmbVLO>Yx15PjaHO|v94gtkyVw;-Ve3HE|GkWvXEdRnN|gh(8njT@Zq+L6~Olz+vk z5=e08Mideja0+d!pW46)&ZgK9#52&vFOP}(hpxLr7cej zq7Oa^v>E!zI88q>JQkm{IZf%d;`^Fe;HgJQn_IqVSqN6i0 z@QAXpBogQaZ)`L@87D71x17Xc$%uh@O)K0 zr&BaBnM@??eTJPJZkhBF_Ncp;#AB$ul}SQ9(ArxvhH_meW>qT;O0;A e9Ky;`s|%>^47GsUS=605-d*w^WH}D*!TSSg1xqae diff --git a/backend-java/common/target/classes/com/jiebanke/common/entity/BaseEntity.class b/backend-java/common/target/classes/com/jiebanke/common/entity/BaseEntity.class deleted file mode 100644 index f684fcdc68f59eb50f31f92aba8cd74fff7fe322..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2952 zcma)8U31e`5IxtHEX4>CK9XRPQVIbQ+rj-V*n|Qhfq(;)gwO(QQS949#FkQ9PRozr zz0)61UU;B0E$#5oXaC|%i54(VH)_NuZEjL(9Olt6#kapl!keOWdZ zZMsnJsd$#`hNJe8Qu9|G`aE9V7Bf7^V&K!Ad`H^x_sCd%!q>;pgg|~26>2ekZF{GqP3mFUv2v1SkX@-} zy8>mbVfsT`OcO$4y%IrUnw<;2U0IvA*P|+$t9El$b$~!}d}2<8Ub1i!rx?xk8*}qB z40n!%G-R_?W0xj_Skhy$Q`2KH|EBLP_zlNh5!lx*aBvkuZ7GczTr@Dd<(h;x3zxv7 zj19ZilGnZxIM$2&7;llwJ-nt@ER-=XFkH9SqUA{Wzkt+wF!veci#O%rzovYph&o$8dxAKGjfwb^W# zDKWvTI_Gj6P1o#ZQ#K8J$!Xg~Mz8b?kkW&%hO$;67rc%v7h5HXgqm}d5^BH%E9VK< z9YpZ@Qg3mW;%+C`UHmUl7F_l0Pw0O_A%Wd|Du{Zj4zxl5_F^A*oE#W>jicf1IpWB8 zjiUqGb2N%KdN?Xlmrz+`b3dd1M@rqfsQ^@-VQxxN1S(1n;!WCKrfZAO;qCfV#ZW#E zz24`6?fO)ORX#b3yWJ^48IJH&iG`xHllErnxO^L!Mw z$v?3pqdmv&N3bR{+Ea|T5!s?nNVb^D=n9j1jy;dCGoxoxF;Ko}5R@;P8AE~02xMf; zHb{HSfRbJ9bvF!jvjh)uBIwFNe2cf)atVyV!8_C?kwpdXQqph{vv`k^j(MEL`;=0s zk&F*08E9YxA5t>$5zoxQGR(iR%YgU?Lk5!kGb!#5#lE;m*ZlZ(Gm2B>TJ?&qs8pH! zUo+{Ondpo^ykGq4bh{KMs8hG~=0NGRHWid&bfC1#LYM=&M=&OzqIgf~vqeoAGFoIY zRe3^FzNiN#Rwj7K%;v^Uvj!ULlalemG?{2|CMBCg{Mr3A;s6@1LFlQ=@E&r;H8 z8OAwEdO+tlNWGv!Bb`E!LM|`(?CcXtF$ld4Xk)akstA^f!8*v7wFEQF^O)}Dk>6d$ zKpsaFg}>s0Vk}(pT%O@F@Txg760srFhpvbF&WQX4*Lz>jts_#=s`_IAi(J(;z0LnS Q_?$cSYv~Kz!!k1e0WNJVVE_OC diff --git a/backend-java/common/target/classes/com/jiebanke/common/exception/BusinessException.class b/backend-java/common/target/classes/com/jiebanke/common/exception/BusinessException.class deleted file mode 100644 index 81b5a2ffe04b003b9a5c59b557f263549cc9280d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2357 zcmb7GT~ixn6n@@hlMU$tf$~ub)>f#^7md}bg+LV$+9;t8bm|P=bO}4KknCc1!`Oe} zrQ?j_oxR~gXDprRg`+n*`kU1HoZXOs$)HZMyXTxe?{m(1&UxSD_rG5J2w)x$bVL*i z6}MK{v#l-D*|$WgxlY0QykZ^rHl@XeXFHbXEuUC)XbPA2%tNzKHJzQpdc*PUn$>!* zpjF&$OF@+s^ct6%JJbeO+evg!}bt!fa=t(etEX5ALOY1I5(+f%r;`acV1o+If}_x$u7 z%a;@tqUj9l9dEKxat>|JX6yyWaeY&mWaz=ws$1J~_Y3zd$EusYwN30KA<8E#4W%=k zfk>lw5=KjxgqI`@twjmn4H-?6l-CT5;*v;H2F5Wl$X35@;0DqPqcwBiT5_F=>3?GT zyOccNbbMxZqiccPQi)riHOwlPoN3vEtv##a7c-j@IB#GYS%pN!be6?Ci2`ovctau8 z9)fU*fsD8+_w0l;@f2dNziZVM3~Am}Ynplk^C^A9H!J&P^Pt)5#IEVFKAD{YW)0lI zC1QQNUMeqh>gtx)sQOH>4UpV$8}*8{V$1l9bPWAX$(!jfx~}i}b@QNX`Md76m&77I z(6L0e+m+eQq06ll_9Ucx#jN;l{fYE}34D2a+MC`X;C<8Cu3FyIs_X7I4vL)(IAuAr z@ZpmKtBd=mr~FTPbjs9(STd{C4coVh{c$WLaG%w5Fp!o_J+Jatn?0CU8Fr=QaFCa( zrsr9nj*k?schJzSFdb!uE9bkiPazAq#+iz8j3fMT>jx4yKA$peJQjGrKy5wn00y(U z=PWgRS%jTXT^?k5Lw!$DZ-g}AD2Lt^WKnfRW8R1%aJA`3AMUn^{OyZ9;@i*xs zd8D#=!58bKL?2>S!^9s6(65H;TIi{u4kcJYoCqUu*Ajn>wm7xRd`e9P%HkKx z{(!zC3K6Cjy2xEpH$sOdIL{zV{0mU(yZ;3A3a)eknx##+iU$O=nU$s5G_ymVIC#ys1t^D$34bhT^2cNj-9>dPME8n4M0xDK3Gd0&e{o=IJ@{EfC45jS($ zZxPduaz8_Tg;?|`_Y+h(<HtmGQe7N(`On^^JH*4r|mVXSL~HabZmR1p`lEOpj^D zO?OQi96i-wJ!tUlFlvjSlcj`ahvxDisbce+M-zC1ieE^!@I;9MM6*ffj%9o z$M_Q?Itu*qCsUIXx=V>Ogq7yTq_%&KTbNDQTbb~1r^J|pWTWJe?E?8VZL;U`sp4Gr zIcDZ3QpH{A$>aHe5mCuUB9(gzefk(PkLM@4^N{tF|6daT+$7GQGQie0Yk@(bYw8g z(3VW)7~*%`g3!^1E(7i8VCc?BM?9>Q^1@r@d0Q~_Wn7EfIqpfdu5ZSJ73niv&m6?J zG{f*p=;ob@PjtQ?dC%}T`47w{n{=wBMb$Ou%5q8gW!Lcqadu^8(cwYGqoCyfVVTJ^ zGM;l~Aw5gHBTE%0kR_3mzN8G!IgT4}RXR%G&5Y|6O~33(r})(4C9&>$Yv#Jhn|bLJ zOdj1eqZHK(Ou+3`ZdWLnsh06K6w;hA9m5#WaD+kW=`Z4HGBt1%qYPS61WG!gjusT$ zaRVoCl0m1FMJg#T(&0cdwJRgpK!ussaT;edj4_P0BHvp#17~rLLKU9pdJH#`3(bK0 ztUn`%x@)?NlF5)x?gEVV_p7PJgIl-M%3w=pbX>%whD!|n4Shwv8Zg6`t3(uJ18%J? zd)yM8m|__G{`U3ut9RQQo7*p6>^$Gxd9(3jYm2Isbt|4F?n(8+M_Yd(lZuOBcHa`E zw??9H0?)PS2bwEXr6tl-Y!V55XP}-6i4N*DTA4I58r#P|q4NVxV$i8q$3Q0zQE${P z(3qeV!(nt2NDs|p=tUomhiSK;+Q1Vq3xgr>Z90u9>xqvTqIT>vPQ4Fp8u&(tKUBL{ z$5(vk2}8Mc0m+Cd)q-g}WSXxtC5UCBm;LO!yoX8;;d>D$02NM+E)mfsh;E$7Vz?5z McQqtZ377_c1I7!l(EtDd diff --git a/backend-java/common/target/classes/com/jiebanke/common/vo/ApiResponse.class b/backend-java/common/target/classes/com/jiebanke/common/vo/ApiResponse.class deleted file mode 100644 index b4db8232dcefc3b87829150f5c4d2c8ac2f8907a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4861 zcmbVQZF3t}6@IRzm1K3DC?-y9=gmo+Shkdkmbcb#kT^+WV<*KnYT^c(wY;@AmUdlf zWe8B-S|Ajd@eF(*3^V;kzJwW=!D*)q416gJzXSR!DCIeOS1*p##Pv*+z4xB8=REg3 z=Vg`FyJEh$6`-ipoTGzBG|TC3c3&o*9L@XL<7I!4VE%eQvQ zv`NZ37o1hs@~dUO99dkH6W^gZ-zsg;_>97H=_Z@ud&9F&z6DKP9A6x5eR(oXKfAFo zPQ6LNKgF9Sq0nRE5DqKE#vRx3Cy6*cobRNd&xC=Ptd5w7Bay%{1@nVn{^H+%`RxaH zxBm0i+afz*q7zA3oiy5WLIHuchNgEyTi<#jhd-X z61$l;>@`sm=E!a=l8F4r^SL*hHHHnlT=vQe&!?yNW{BVxKL*?$E!LoQI+cZ5*^zn{ z-jVsLD>X9hZaNi*44-#h&$oPswJTLt^h(R#dhP|=wab=ouSf>_Ymz$gRojxDM?_3P(cc((Vf{pZWP`4(HNuGwKo2=M=9e6aoG@O?PQu7~8Ps@QQ z)dBQ0r%Ej`!nZVn9U8S(K#f>X(Oj6c*MuROo)IrG`?ac7K%GuXUOyY~|Tb_d9`D-?F z%9Pj-GA_D9b_K_cePTY170v@J)roC2QTD^4x;uzvTGD?GlsgldiG!Qk&vwwKmfxafO#2 zUUI>!mJ9Y}NBUx_X~sP*b4nrIzG$0#)bl)b!SnozU$!>pY=6yLsU-0|{2-3+v!OPI zp5tzMoU1x=`c{{%g71~@$aR0H@ayIXh1%NS70X>I+Lggs&s(o z&27|QZqjc(-k-}tCn9||MpHSHWnfLMxQ(2ahDe|mm(u5jj z#!tI!JyS)iQn4#>+*LT!5}Wnl z$Wp5-Sns2p1C#4+j$s1_xYv?ye2S-AwAR6A`p-}|-oe4yOmrK)nFILeHu^K&N4If2 zGqR0=%)2|+&r^OTw(sn<+oS@ya++`>|q;1RC=PrQ(WO0tz zp57tbSC{1|6O^B>qkJYnd5=Ej)4sF+=#&K zXGk^J7M%S7m8aYfPmnWD$-XQps zq2`$4ZFT;C>9K(s*sBZ9$+qZ)4;}OL@447Z%r9W7jp!ZK>e_u6DeG44Z1L6vCHV`Ya`I$q;Pp4| z1}E1?4LK4H5~<96B>IepSPev^CJ@EyA~HkK(e|`V5(FJ|>}+tmp4Ke>dNS$4CA>W)vRR`;Ub&X|x+T(X{fv zNm^-bnz!%ZPW!6Yp{nIh!*nfUqWBgucd#b(?D`H~=U#g28~nYAA9E+4EI+|d@iX-O EA9+%P0{{R3 diff --git a/backend-java/docker-compose.yml b/backend-java/docker-compose.yml deleted file mode 100644 index 6fa800e..0000000 --- a/backend-java/docker-compose.yml +++ /dev/null @@ -1,147 +0,0 @@ -version: '3.8' - -services: - # MySQL数据库 - mysql: - image: mysql:8.0 - container_name: jiebanke-mysql - environment: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: jiebanke - ports: - - "3306:3306" - volumes: - - mysql_data:/var/lib/mysql - - ./scripts/init-database.sql:/docker-entrypoint-initdb.d/init-database.sql - networks: - - jiebanke-network - - # Redis缓存 - redis: - image: redis:6.0 - container_name: jiebanke-redis - ports: - - "6379:6379" - networks: - - jiebanke-network - - # RabbitMQ消息队列 - rabbitmq: - image: rabbitmq:3.8-management - container_name: jiebanke-rabbitmq - ports: - - "5672:5672" - - "15672:15672" - networks: - - jiebanke-network - - # Eureka服务注册中心 - eureka-server: - build: - context: ./eureka-server - container_name: jiebanke-eureka - ports: - - "8761:8761" - networks: - - jiebanke-network - depends_on: - - mysql - - redis - - rabbitmq - - # API网关 - gateway-service: - build: - context: ./gateway-service - container_name: jiebanke-gateway - ports: - - "8080:8080" - networks: - - jiebanke-network - depends_on: - - eureka-server - - # 认证服务 - auth-service: - build: - context: ./auth-service - container_name: jiebanke-auth - ports: - - "8081:8081" - networks: - - jiebanke-network - depends_on: - - eureka-server - - mysql - - # 用户服务 - user-service: - build: - context: ./user-service - container_name: jiebanke-user - ports: - - "8082:8082" - networks: - - jiebanke-network - depends_on: - - eureka-server - - mysql - - # 旅行服务 - travel-service: - build: - context: ./travel-service - container_name: jiebanke-travel - ports: - - "8083:8083" - networks: - - jiebanke-network - depends_on: - - eureka-server - - mysql - - # 动物服务 - animal-service: - build: - context: ./animal-service - container_name: jiebanke-animal - ports: - - "8084:8084" - networks: - - jiebanke-network - depends_on: - - eureka-server - - mysql - - # 订单服务 - order-service: - build: - context: ./order-service - container_name: jiebanke-order - ports: - - "8085:8085" - networks: - - jiebanke-network - depends_on: - - eureka-server - - mysql - - # 推广服务 - promotion-service: - build: - context: ./promotion-service - container_name: jiebanke-promotion - ports: - - "8086:8086" - networks: - - jiebanke-network - depends_on: - - eureka-server - - mysql - -volumes: - mysql_data: - -networks: - jiebanke-network: - driver: bridge \ No newline at end of file diff --git a/backend-java/eureka-server/pom.xml b/backend-java/eureka-server/pom.xml deleted file mode 100644 index b97c511..0000000 --- a/backend-java/eureka-server/pom.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - eureka-server - jar - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-server - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/backend-java/eureka-server/src/main/java/com/jiebanke/eureka/EurekaServerApplication.java b/backend-java/eureka-server/src/main/java/com/jiebanke/eureka/EurekaServerApplication.java deleted file mode 100644 index 136165e..0000000 --- a/backend-java/eureka-server/src/main/java/com/jiebanke/eureka/EurekaServerApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jiebanke.eureka; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; - -@SpringBootApplication -@EnableEurekaServer -public class EurekaServerApplication { - public static void main(String[] args) { - SpringApplication.run(EurekaServerApplication.class, args); - } -} \ No newline at end of file diff --git a/backend-java/eureka-server/src/main/resources/application.yml b/backend-java/eureka-server/src/main/resources/application.yml deleted file mode 100644 index b4c0e4b..0000000 --- a/backend-java/eureka-server/src/main/resources/application.yml +++ /dev/null @@ -1,17 +0,0 @@ -server: - port: 8761 - -spring: - application: - name: eureka-server - -eureka: - instance: - hostname: localhost - client: - register-with-eureka: false - fetch-registry: false - service-url: - defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ - server: - enable-self-preservation: false \ No newline at end of file diff --git a/backend-java/eureka-server/target/classes/application.yml b/backend-java/eureka-server/target/classes/application.yml deleted file mode 100644 index b4c0e4b..0000000 --- a/backend-java/eureka-server/target/classes/application.yml +++ /dev/null @@ -1,17 +0,0 @@ -server: - port: 8761 - -spring: - application: - name: eureka-server - -eureka: - instance: - hostname: localhost - client: - register-with-eureka: false - fetch-registry: false - service-url: - defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ - server: - enable-self-preservation: false \ No newline at end of file diff --git a/backend-java/eureka-server/target/classes/com/jiebanke/eureka/EurekaServerApplication.class b/backend-java/eureka-server/target/classes/com/jiebanke/eureka/EurekaServerApplication.class deleted file mode 100644 index 471a7add2d8735b98a0c32127e4eb602f88df12b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 808 zcmb7Cv2qhJ5Pfo-oO2iw90&wLLFbqObu@;|BqmfhFoPLWQ0Xr6A^T49=yV~!MFm5_ z2k=putV9@JaTGMW(ysRHd#n9@_45~i*LV`4!|*IKC0{6+3cZwE)>bYBKMQUu?S-@_ zt5u;g;gr!4x(vGuaUpmibk5(W3z<2FtyfAbcg(OcJeo0dC+1wn*uZulo7iI5NtBlF z>N1t~qeu(MFi1=$ikYy=-*19l_eE6<&y)Y4G^Tc?P?}+X_&Hfqn>wp>K0cboxQo3A z1BQ{YIj>eeKDVNjUyWVz)ELL7A=nVw$35I9IkqO?blAY16r!reZJm-f_{?Z0FCCv4 zJy&^cz1l_}3j4GdA#6_C_gat{;;E@^Cf_PQy2F2b&I>P|;ow89ohs!_RmwNh+PLs} zgnr!0F^oXe&Jfu^Qr-;YlxEW)ODx~C0%V1$&$*UvUZ~5zD^!K$;b+=QZc-lODQL8` zf{|8x^eQ1{O0I8df!4iChOC{Hg1va|9L?Ec8J}<4n=(N%K!%S25j^LyPwwe fF=as25ml`*df3MUig)lZ*aJKw@83Qqe+XOyv+vzG diff --git a/backend-java/gateway-service/pom.xml b/backend-java/gateway-service/pom.xml deleted file mode 100644 index 82c3ba4..0000000 --- a/backend-java/gateway-service/pom.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - gateway-service - jar - - - - - org.springframework.cloud - spring-cloud-starter-gateway - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - io.jsonwebtoken - jjwt-api - - - io.jsonwebtoken - jjwt-impl - runtime - - - io.jsonwebtoken - jjwt-jackson - runtime - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/backend-java/gateway-service/src/main/java/com/jiebanke/gateway/GatewayApplication.java b/backend-java/gateway-service/src/main/java/com/jiebanke/gateway/GatewayApplication.java deleted file mode 100644 index f73b552..0000000 --- a/backend-java/gateway-service/src/main/java/com/jiebanke/gateway/GatewayApplication.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jiebanke.gateway; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; -import org.springframework.context.annotation.Bean; - -@SpringBootApplication -@EnableDiscoveryClient -public class GatewayApplication { - public static void main(String[] args) { - SpringApplication.run(GatewayApplication.class, args); - } - - @Bean - public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { - return builder.routes() - .route("auth-service", r -> r.path("/api/auth/**") - .uri("lb://auth-service")) - .route("user-service", r -> r.path("/api/users/**") - .uri("lb://user-service")) - .route("travel-service", r -> r.path("/api/travel/**") - .uri("lb://travel-service")) - .route("animal-service", r -> r.path("/api/animals/**") - .uri("lb://animal-service")) - .route("order-service", r -> r.path("/api/orders/**") - .uri("lb://order-service")) - .route("promotion-service", r -> r.path("/api/promotion/**") - .uri("lb://promotion-service")) - .build(); - } -} \ No newline at end of file diff --git a/backend-java/gateway-service/src/main/resources/application.yml b/backend-java/gateway-service/src/main/resources/application.yml deleted file mode 100644 index 20b2330..0000000 --- a/backend-java/gateway-service/src/main/resources/application.yml +++ /dev/null @@ -1,38 +0,0 @@ -server: - port: 8080 - -spring: - application: - name: gateway-service - cloud: - gateway: - routes: - - id: auth-service - uri: lb://auth-service - predicates: - - Path=/api/auth/** - - id: user-service - uri: lb://user-service - predicates: - - Path=/api/users/** - - id: travel-service - uri: lb://travel-service - predicates: - - Path=/api/travel/** - - id: animal-service - uri: lb://animal-service - predicates: - - Path=/api/animals/** - - id: order-service - uri: lb://order-service - predicates: - - Path=/api/orders/** - - id: promotion-service - uri: lb://promotion-service - predicates: - - Path=/api/promotion/** - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ \ No newline at end of file diff --git a/backend-java/gateway-service/target/classes/application.yml b/backend-java/gateway-service/target/classes/application.yml deleted file mode 100644 index 20b2330..0000000 --- a/backend-java/gateway-service/target/classes/application.yml +++ /dev/null @@ -1,38 +0,0 @@ -server: - port: 8080 - -spring: - application: - name: gateway-service - cloud: - gateway: - routes: - - id: auth-service - uri: lb://auth-service - predicates: - - Path=/api/auth/** - - id: user-service - uri: lb://user-service - predicates: - - Path=/api/users/** - - id: travel-service - uri: lb://travel-service - predicates: - - Path=/api/travel/** - - id: animal-service - uri: lb://animal-service - predicates: - - Path=/api/animals/** - - id: order-service - uri: lb://order-service - predicates: - - Path=/api/orders/** - - id: promotion-service - uri: lb://promotion-service - predicates: - - Path=/api/promotion/** - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ \ No newline at end of file diff --git a/backend-java/gateway-service/target/classes/com/jiebanke/gateway/GatewayApplication.class b/backend-java/gateway-service/target/classes/com/jiebanke/gateway/GatewayApplication.class deleted file mode 100644 index b9f4f5fd9364347ff976044758246485a9dd5699..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3944 zcmb_eX>-&@5PgGfv|a=@YcRJtV!$?sxIhKd(XfbNyXh8< zaZBX6Ga-yo?u#3I$~Y6gPnJryWpdwg9Sw~Pt>b)>8#Z@FjZ67)VfqYHF7HCeE zwkmSVVQBBVo{P*H@;%EL&2|r`u^eq0G7LSgH)@niQa7ObEW02)BM#6P%Cg-HMu}^a#cKuw$G3`N z*eYAnE5~tt#Sn61S2AcN7<_iA(I>c*O=AN#YUp6-PmE!G9_iSG&BRCLI@xlmYvC@= z6R6H=z*2aCLFa)#wyP|>Ny`)&N~5hhwqZL%6Q@*}V%SK#DmDhbWg8=bW6I<)PFDux zb2oNq=wUd2AAGJFr(-8}krB#whC6ZQRx)B#&L`LZVpvLcJ2k}&H?;wr-xn`Jf1YB*g} z&_kZ2aF))_;3dnDR5yBh(s&p-4d)q-)yvo#V|84>MJjkD?vF7HCRXjbL)_=OHkA?; zj1(>tEA0FcLz!M>MH+*+qG5<3Td(~wbRCa^uD6E3vt((B-3-+mr+(XIC00klz^Jev zuN$EzzA_)#F|AG9NN;}% zbg8$5luMduqd)ypPllrr?q%YQNbMpiF(1ngOLb zE3R^YAwA>6vgJ{3_b?xex+l8$~1kmif6 z7^uiz*KtkBUW;V!=y*!W-i~A+>M)h;gGlz7jxiKsK` z!}oLtM%L9ttM&{u{K(KT|59pn!UJQ_R81EiHj|qT)RO?sG@|aCo*I1_^k(#K>iHe1 z-)OK1X?n_OK*tjGR14^9DSb6#8CojJhiJ8&OJ!KkA85TA>8EK1v{IwB5k?B_SVeM% z)mTF-*3ww+w2t1=n7d@6)En3_jrEx=Gw1}S(UsXfgFWGB?+o^bqXRQI6pkL8!9(Hb z$PA9E(KL?zN;sh}+sJ014UN>mFCz<9({Bsyy%XyRq5~(eiH^Tb+1VcMU-6YJ!AbOi zwWcLO$Wm$LNeZ9zx~-@2Pn^2ekU29njdPhx(|9D>Gz`EB3fan70NQXBj{yWn+?osS zaRv880$e-6txAL=TFwRcw1VRaaH|P!O(GmIdM>zvf*VPITT5{365%Kr=7O^n+(ZK0 zdV<@K2uFD|7o4NuN(pcs1h?^CIAVpTm{L}3l*i`NcR>G1`u7q)ZxbtDz{_|=jb6nY vcvFqu!n=4+jo!yc_*jiT!RPowjqc)We1mTZBSV - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - order-service - jar - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - com.baomidou - mybatis-plus-boot-starter - - - - - mysql - mysql-connector-java - - - - - com.jiebanke - common - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/backend-java/order-service/src/main/java/com/jiebanke/order/OrderApplication.java b/backend-java/order-service/src/main/java/com/jiebanke/order/OrderApplication.java deleted file mode 100644 index 70f64fc..0000000 --- a/backend-java/order-service/src/main/java/com/jiebanke/order/OrderApplication.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.jiebanke.order; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDiscoveryClient -@EnableFeignClients -@MapperScan("com.jiebanke.order.mapper") -@ComponentScan(basePackages = "com.jiebanke") -public class OrderApplication { - public static void main(String[] args) { - SpringApplication.run(OrderApplication.class, args); - } -} \ No newline at end of file diff --git a/backend-java/order-service/src/main/java/com/jiebanke/order/controller/OrderController.java b/backend-java/order-service/src/main/java/com/jiebanke/order/controller/OrderController.java deleted file mode 100644 index 5442b50..0000000 --- a/backend-java/order-service/src/main/java/com/jiebanke/order/controller/OrderController.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.jiebanke.order.controller; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.jiebanke.common.vo.ApiResponse; -import com.jiebanke.order.entity.Order; -import com.jiebanke.order.service.OrderService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.Map; - -@RestController -@RequestMapping("/api/orders") -public class OrderController { - - @Autowired - private OrderService orderService; - - /** - * 创建订单 - */ - @PostMapping - public ApiResponse> createOrder( - @RequestHeader("userId") Long userId, - @RequestBody Order order) { - - Long orderId = orderService.createOrder(order, userId); - Order createdOrder = orderService.getOrderById(orderId); - - Map result = new HashMap<>(); - result.put("order", createdOrder); - result.put("message", "订单创建成功"); - - return ApiResponse.success(result); - } - - /** - * 获取订单详情 - */ - @GetMapping("/{orderId}") - public ApiResponse getOrder(@PathVariable Long orderId) { - Order order = orderService.getOrderById(orderId); - return ApiResponse.success(order); - } - - /** - * 获取用户订单列表 - */ - @GetMapping - public ApiResponse> getUserOrders( - @RequestHeader("userId") Long userId, - @RequestParam(defaultValue = "1") Integer page, - @RequestParam(defaultValue = "10") Integer pageSize, - @RequestParam(required = false) String status) { - - IPage orders = orderService.getUserOrders(userId, page, pageSize, status); - - Map result = new HashMap<>(); - result.put("orders", orders.getRecords()); - result.put("pagination", Map.of( - "page", orders.getCurrent(), - "pageSize", orders.getSize(), - "total", orders.getTotal(), - "totalPages", orders.getPages() - )); - - return ApiResponse.success(result); - } - - /** - * 更新订单状态 - */ - @PutMapping("/{orderId}/status") - public ApiResponse> updateOrderStatus( - @PathVariable Long orderId, - @RequestBody Map requestBody, - @RequestHeader("userId") Long userId) { - - String status = requestBody.get("status"); - Order updatedOrder = orderService.updateOrderStatus(orderId, status, userId); - - Map result = new HashMap<>(); - result.put("order", updatedOrder); - result.put("message", "订单状态更新成功"); - - return ApiResponse.success(result); - } - - /** - * 删除订单 - */ - @DeleteMapping("/{orderId}") - public ApiResponse> deleteOrder( - @PathVariable Long orderId, - @RequestHeader("userId") Long userId) { - - boolean deleted = orderService.deleteOrder(orderId, userId); - - Map result = new HashMap<>(); - result.put("message", "订单删除成功"); - result.put("orderId", orderId); - - return ApiResponse.success(result); - } - - /** - * 获取订单统计信息 - */ - @GetMapping("/statistics") - public ApiResponse> getOrderStatistics(@RequestHeader("merchantId") Long merchantId) { - Map statistics = orderService.getOrderStats(merchantId); - return ApiResponse.success(statistics); - } - - /** - * 管理员获取所有订单 - */ - @GetMapping("/admin") - public ApiResponse> getAllOrders( - @RequestParam(defaultValue = "1") Integer page, - @RequestParam(defaultValue = "10") Integer pageSize, - @RequestParam(required = false) String status, - @RequestParam(required = false) Long merchantId, - @RequestParam(required = false) Long userId) { - - IPage orders = orderService.getAllOrders(page, pageSize, status, merchantId, userId); - - Map result = new HashMap<>(); - result.put("orders", orders.getRecords()); - result.put("pagination", Map.of( - "page", orders.getCurrent(), - "pageSize", orders.getSize(), - "total", orders.getTotal(), - "totalPages", orders.getPages() - )); - - return ApiResponse.success(result); - } -} \ No newline at end of file diff --git a/backend-java/order-service/src/main/java/com/jiebanke/order/entity/Order.java b/backend-java/order-service/src/main/java/com/jiebanke/order/entity/Order.java deleted file mode 100644 index d7e3494..0000000 --- a/backend-java/order-service/src/main/java/com/jiebanke/order/entity/Order.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.jiebanke.order.entity; - -import com.jiebanke.common.entity.BaseEntity; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.math.BigDecimal; - -@Data -@EqualsAndHashCode(callSuper = true) -public class Order extends BaseEntity { - private Long userId; - private String orderNo; - private BigDecimal amount; - private String status; - private String type; - private String description; -} \ No newline at end of file diff --git a/backend-java/order-service/src/main/java/com/jiebanke/order/mapper/OrderMapper.java b/backend-java/order-service/src/main/java/com/jiebanke/order/mapper/OrderMapper.java deleted file mode 100644 index e4c78fd..0000000 --- a/backend-java/order-service/src/main/java/com/jiebanke/order/mapper/OrderMapper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.jiebanke.order.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.jiebanke.order.entity.Order; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; - -import java.util.List; - -@Mapper -public interface OrderMapper extends BaseMapper { - - /** - * 根据用户ID获取订单列表 - * @param userId 用户ID - * @return 订单列表 - */ - @Select("SELECT * FROM orders WHERE user_id = #{userId} ORDER BY created_at DESC") - List selectByUserId(@Param("userId") Long userId); - - /** - * 根据状态获取订单列表 - * @param status 状态 - * @return 订单列表 - */ - @Select("SELECT * FROM orders WHERE status = #{status} ORDER BY created_at DESC") - List selectByStatus(@Param("status") String status); - - /** - * 根据订单号获取订单 - * @param orderNo 订单号 - * @return 订单 - */ - @Select("SELECT * FROM orders WHERE order_no = #{orderNo}") - Order selectByOrderNo(@Param("orderNo") String orderNo); -} \ No newline at end of file diff --git a/backend-java/order-service/src/main/java/com/jiebanke/order/service/OrderService.java b/backend-java/order-service/src/main/java/com/jiebanke/order/service/OrderService.java deleted file mode 100644 index 8d5215e..0000000 --- a/backend-java/order-service/src/main/java/com/jiebanke/order/service/OrderService.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.jiebanke.order.service; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.jiebanke.order.entity.Order; - -import java.util.Map; - -public interface OrderService extends IService { - - /** - * 创建订单 - * @param order 订单信息 - * @param userId 用户ID - * @return 创建的订单ID - */ - Long createOrder(Order order, Long userId); - - /** - * 根据ID获取订单 - * @param orderId 订单ID - * @return 订单信息 - */ - Order getOrderById(Long orderId); - - /** - * 获取用户订单列表 - * @param userId 用户ID - * @param page 页码 - * @param pageSize 每页数量 - * @param status 状态 - * @return 订单分页列表 - */ - IPage getUserOrders(Long userId, Integer page, Integer pageSize, String status); - - /** - * 更新订单状态 - * @param orderId 订单ID - * @param status 新状态 - * @param userId 操作人ID - * @return 更新后的订单 - */ - Order updateOrderStatus(Long orderId, String status, Long userId); - - /** - * 删除订单(软删除) - * @param orderId 订单ID - * @param userId 用户ID - * @return 是否删除成功 - */ - boolean deleteOrder(Long orderId, Long userId); - - /** - * 获取订单统计信息 - * @param merchantId 商家ID - * @return 统计信息 - */ - Map getOrderStats(Long merchantId); - - /** - * 获取所有订单(管理员) - * @param page 页码 - * @param pageSize 每页数量 - * @param status 状态 - * @param merchantId 商家ID - * @param userId 用户ID - * @return 订单分页列表 - */ - IPage getAllOrders(Integer page, Integer pageSize, String status, Long merchantId, Long userId); -} \ No newline at end of file diff --git a/backend-java/order-service/src/main/java/com/jiebanke/order/service/impl/OrderServiceImpl.java b/backend-java/order-service/src/main/java/com/jiebanke/order/service/impl/OrderServiceImpl.java deleted file mode 100644 index 306fd14..0000000 --- a/backend-java/order-service/src/main/java/com/jiebanke/order/service/impl/OrderServiceImpl.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.jiebanke.order.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.jiebanke.common.exception.BusinessException; -import com.jiebanke.order.entity.Order; -import com.jiebanke.order.mapper.OrderMapper; -import com.jiebanke.order.service.OrderService; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -@Service -public class OrderServiceImpl extends ServiceImpl implements OrderService { - - @Override - public Long createOrder(Order order, Long userId) { - // 生成订单号 - String orderNo = "ORD" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); - order.setOrderNo(orderNo); - order.setUserId(userId); - - // 设置默认状态 - if (order.getStatus() == null) { - order.setStatus("pending"); - } - - this.save(order); - return order.getId(); - } - - @Override - public Order getOrderById(Long orderId) { - Order order = this.getById(orderId); - if (order == null) { - throw new BusinessException("订单不存在"); - } - return order; - } - - @Override - public IPage getUserOrders(Long userId, Integer page, Integer pageSize, String status) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("user_id", userId); - - if (status != null && !status.isEmpty()) { - queryWrapper.eq("status", status); - } - - queryWrapper.orderByDesc("created_at"); - - Page pageObj = new Page<>(page != null ? page : 1, pageSize != null ? pageSize : 10); - return this.page(pageObj, queryWrapper); - } - - @Override - public Order updateOrderStatus(Long orderId, String status, Long userId) { - Order existingOrder = this.getById(orderId); - if (existingOrder == null) { - throw new BusinessException("订单不存在"); - } - - // 验证状态是否有效 - String[] validStatuses = {"pending", "processing", "completed", "cancelled", "failed"}; - boolean isValidStatus = false; - for (String validStatus : validStatuses) { - if (validStatus.equals(status)) { - isValidStatus = true; - break; - } - } - - if (!isValidStatus) { - throw new BusinessException("无效的订单状态"); - } - - existingOrder.setStatus(status); - this.updateById(existingOrder); - return existingOrder; - } - - @Override - public boolean deleteOrder(Long orderId, Long userId) { - return this.removeById(orderId); - } - - @Override - public Map getOrderStats(Long merchantId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("merchant_id", merchantId); - - int totalOrders = Math.toIntExact(this.count(queryWrapper)); - - QueryWrapper pendingWrapper = new QueryWrapper<>(); - pendingWrapper.eq("merchant_id", merchantId).eq("status", "pending"); - int pendingOrders = Math.toIntExact(this.count(pendingWrapper)); - - QueryWrapper processingWrapper = new QueryWrapper<>(); - processingWrapper.eq("merchant_id", merchantId).eq("status", "processing"); - int processingOrders = Math.toIntExact(this.count(processingWrapper)); - - QueryWrapper completedWrapper = new QueryWrapper<>(); - completedWrapper.eq("merchant_id", merchantId).eq("status", "completed"); - int completedOrders = Math.toIntExact(this.count(completedWrapper)); - - QueryWrapper cancelledWrapper = new QueryWrapper<>(); - cancelledWrapper.eq("merchant_id", merchantId).eq("status", "cancelled"); - int cancelledOrders = Math.toIntExact(this.count(cancelledWrapper)); - - QueryWrapper failedWrapper = new QueryWrapper<>(); - failedWrapper.eq("merchant_id", merchantId).eq("status", "failed"); - int failedOrders = Math.toIntExact(this.count(failedWrapper)); - - // 计算总收入 - QueryWrapper revenueWrapper = new QueryWrapper<>(); - revenueWrapper.eq("merchant_id", merchantId).select("SUM(amount) as totalRevenue"); - Map revenueMap = this.getMap(revenueWrapper); - BigDecimal totalRevenue = revenueMap != null && revenueMap.get("totalRevenue") != null ? - new BigDecimal(revenueMap.get("totalRevenue").toString()) : BigDecimal.ZERO; - - Map stats = new HashMap<>(); - stats.put("totalOrders", totalOrders); - stats.put("pendingOrders", pendingOrders); - stats.put("processingOrders", processingOrders); - stats.put("completedOrders", completedOrders); - stats.put("cancelledOrders", cancelledOrders); - stats.put("failedOrders", failedOrders); - stats.put("totalRevenue", totalRevenue); - - return stats; - } - - @Override - public IPage getAllOrders(Integer page, Integer pageSize, String status, Long merchantId, Long userId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - - if (status != null && !status.isEmpty()) { - queryWrapper.eq("status", status); - } - - if (merchantId != null) { - queryWrapper.eq("merchant_id", merchantId); - } - - if (userId != null) { - queryWrapper.eq("user_id", userId); - } - - queryWrapper.orderByDesc("created_at"); - - Page pageObj = new Page<>(page != null ? page : 1, pageSize != null ? pageSize : 10); - return this.page(pageObj, queryWrapper); - } -} \ No newline at end of file diff --git a/backend-java/order-service/src/main/resources/application.yml b/backend-java/order-service/src/main/resources/application.yml deleted file mode 100644 index 883e008..0000000 --- a/backend-java/order-service/src/main/resources/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8085 - -spring: - application: - name: order-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/order-service/target/classes/application.yml b/backend-java/order-service/target/classes/application.yml deleted file mode 100644 index 883e008..0000000 --- a/backend-java/order-service/target/classes/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8085 - -spring: - application: - name: order-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/order-service/target/classes/com/jiebanke/order/OrderApplication.class b/backend-java/order-service/target/classes/com/jiebanke/order/OrderApplication.class deleted file mode 100644 index 3c6777162264bff310e06a0e45323af549db88f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1079 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 D7qwI| diff --git a/backend-java/order-service/target/classes/com/jiebanke/order/mapper/OrderMapper.class b/backend-java/order-service/target/classes/com/jiebanke/order/mapper/OrderMapper.class deleted file mode 100644 index 2fcf551487f7b4c711bb7e9cf74b53461b591122..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1226 zcmb7EU2oGc6usV9%f{HsH{;U+hJXjm3r}H4bW6viY()tlLOfJ%Vv0)=SGF^$Li=Mp z@B{c!h#O~Pom#c!!LqOIbA9f~x%vI)=Pv-*g8Ow?Ag~#$jP<4H^8CACN+&|Ij1LAl zwaZ}Nt?O`(K%>tOIZJuoW9@EV#I_DK0<28X}RO&zGb=RK`93M*3g8KLm|Cd_1=i=5!P5>g^xy6jI5TEh2Ndy+I(`irYK|_DJM|1 zoF-7Mx*s zRAzr(`kKJk5r0>$<2ir+N88M&@GR3-tUPR60*g47@K3OatzC!n7%yYA04s0-=QTWC z#c}Zq5QEV=?yZ)vM!9L=5~41{m4B$K6HwR2P}dQ418(9g<8N$?-M)p{Z#zzRj=9}+ KxEfNp2k;kTMPh3J diff --git a/backend-java/order-service/target/classes/com/jiebanke/order/service/OrderService.class b/backend-java/order-service/target/classes/com/jiebanke/order/service/OrderService.class deleted file mode 100644 index 0572608b529f0e43cc526d0ce599cf37fe1109ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1464 zcmd5+OHRWu5FPUie<=Uo2C)D(c)_xO1W2GtMIc3N*ty9la!HfQaS*)$ci;%zfCUHO zP>6{gN<;%?2aCw^O#J5g&GWpzJ--0JA#6A>z+l^pTf8Z;A);I4vGP&z1l67NkY8py z*KQmbVldkjcY=o^3ixHCiJo>~gu#9W(GYP<`fGM9f{~WGV|i5TpT+BO6jXP=1{h2Rs14vrr{)u}ov**__N~HTia@SO z0t1vVxbHzJpw=Rd0jeUol8~#FG>pGh%8M297HZ)OEqLup1XyJ-=E@)vI#tNv@sDU6 z^p)(0m{!s@F}K}xHBlzvu76^jOHz2Q8{1TCXCg=3HhWIx zc1pDj`GsiHozDCHb5LO4dmsBks+l^OFOS3U!%+`K;1au(gnHr4)d~a(@|C{Da)&+r z6Dq%R*|;00%EL1m(u1hje%kT0mkkF7&4M7g{>HwgihMtve#3?aAA>>qhH08QG#nim xg=|QU!MIr`V3M*^lpTO+iqF8TiC19Gtn;wY%`Z}Z36{J26*{wOPOjw$>+jM>-EjZ_ diff --git a/backend-java/order-service/target/classes/com/jiebanke/order/service/impl/OrderServiceImpl.class b/backend-java/order-service/target/classes/com/jiebanke/order/service/impl/OrderServiceImpl.class deleted file mode 100644 index c2be512c7cfe00dbcbc8763a3fc4bb497f946117..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7837 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 diff --git a/backend-java/pom.xml b/backend-java/pom.xml deleted file mode 100644 index 8f56e35..0000000 --- a/backend-java/pom.xml +++ /dev/null @@ -1,163 +0,0 @@ - - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - pom - 结伴客Java后端 - 结伴客Java微服务架构后端系统 - - - eureka-server - gateway-service - auth-service - user-service - travel-service - animal-service - order-service - promotion-service - common - - - - 17 - 17 - UTF-8 - 3.1.0 - 2022.0.3 - 8.0.33 - 3.5.3.1 - 5.9.2 - 5.2.0 - - - - - - - org.springframework.boot - spring-boot-dependencies - ${spring.boot.version} - pom - import - - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring.cloud.version} - pom - import - - - - - mysql - mysql-connector-java - ${mysql.version} - - - - - com.baomidou - mybatis-plus-boot-starter - ${mybatis.plus.version} - - - - - io.jsonwebtoken - jjwt-api - 0.11.5 - - - io.jsonwebtoken - jjwt-impl - 0.11.5 - runtime - - - io.jsonwebtoken - jjwt-jackson - 0.11.5 - runtime - - - - - org.springframework.boot - spring-boot-starter-data-redis - ${spring.boot.version} - - - - - org.springframework.boot - spring-boot-starter-amqp - ${spring.boot.version} - - - - - org.springframework.cloud - spring-cloud-starter-openfeign - ${spring.cloud.version} - - - - - org.junit.jupiter - junit-jupiter - ${junit.version} - test - - - - - org.mockito - mockito-core - ${mockito.version} - test - - - - - org.springframework.boot - spring-boot-starter-test - ${spring.boot.version} - test - - - - - com.jiebanke - common - ${project.version} - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - ${spring.boot.version} - - - - org.projectlombok - lombok - - - - - - - \ No newline at end of file diff --git a/backend-java/promotion-service/pom.xml b/backend-java/promotion-service/pom.xml deleted file mode 100644 index e7c423b..0000000 --- a/backend-java/promotion-service/pom.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - promotion-service - jar - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - com.baomidou - mybatis-plus-boot-starter - - - - - mysql - mysql-connector-java - - - - - com.jiebanke - common - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/PromotionApplication.java b/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/PromotionApplication.java deleted file mode 100644 index 887e2ee..0000000 --- a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/PromotionApplication.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.jiebanke.promotion; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDiscoveryClient -@EnableFeignClients -@MapperScan({"com.jiebanke.promotion.mapper"}) -@ComponentScan(basePackages = "com.jiebanke") -public class PromotionApplication { - public static void main(String[] args) { - SpringApplication.run(PromotionApplication.class, args); - } -} \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/controller/PromotionController.java b/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/controller/PromotionController.java deleted file mode 100644 index 15326b7..0000000 --- a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/controller/PromotionController.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.jiebanke.promotion.controller; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.jiebanke.common.vo.ApiResponse; -import com.jiebanke.promotion.entity.PromotionActivity; -import com.jiebanke.promotion.entity.RewardRecord; -import com.jiebanke.promotion.service.PromotionService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.Map; - -@RestController -@RequestMapping("/api/promotion") -public class PromotionController { - - @Autowired - private PromotionService promotionService; - - /** - * 获取推广活动列表 - */ - @GetMapping("/activities") - public ApiResponse> getPromotionActivities( - @RequestParam(defaultValue = "1") Integer page, - @RequestParam(defaultValue = "10") Integer pageSize, - @RequestParam(required = false) String name, - @RequestParam(required = false) String status) { - - IPage activities = promotionService.getPromotionActivities(page, pageSize, name, status); - - Map result = new HashMap<>(); - result.put("activities", activities.getRecords()); - result.put("pagination", Map.of( - "current", activities.getCurrent(), - "pageSize", activities.getSize(), - "total", activities.getTotal(), - "totalPages", activities.getPages() - )); - - return ApiResponse.success(result); - } - - /** - * 获取推广活动详情 - */ - @GetMapping("/activities/{id}") - public ApiResponse getPromotionActivity(@PathVariable Long id) { - PromotionActivity activity = promotionService.getPromotionActivityById(id); - return ApiResponse.success(activity); - } - - /** - * 创建推广活动 - */ - @PostMapping("/activities") - public ApiResponse> createPromotionActivity(@RequestBody PromotionActivity activity) { - Long activityId = promotionService.createPromotionActivity(activity); - PromotionActivity createdActivity = promotionService.getPromotionActivityById(activityId); - - Map result = new HashMap<>(); - result.put("activity", createdActivity); - result.put("message", "推广活动创建成功"); - - return ApiResponse.success(result); - } - - /** - * 更新推广活动 - */ - @PutMapping("/activities/{id}") - public ApiResponse> updatePromotionActivity( - @PathVariable Long id, - @RequestBody PromotionActivity activity) { - - PromotionActivity updatedActivity = promotionService.updatePromotionActivity(id, activity); - - Map result = new HashMap<>(); - result.put("activity", updatedActivity); - result.put("message", "推广活动更新成功"); - - return ApiResponse.success(result); - } - - /** - * 删除推广活动 - */ - @DeleteMapping("/activities/{id}") - public ApiResponse> deletePromotionActivity(@PathVariable Long id) { - boolean deleted = promotionService.deletePromotionActivity(id); - - Map result = new HashMap<>(); - result.put("message", "推广活动删除成功"); - result.put("id", id); - - return ApiResponse.success(result); - } - - /** - * 暂停推广活动 - */ - @PostMapping("/activities/{id}/pause") - public ApiResponse> pausePromotionActivity(@PathVariable Long id) { - boolean paused = promotionService.pausePromotionActivity(id); - - Map result = new HashMap<>(); - result.put("message", "推广活动已暂停"); - result.put("id", id); - - return ApiResponse.success(result); - } - - /** - * 恢复推广活动 - */ - @PostMapping("/activities/{id}/resume") - public ApiResponse> resumePromotionActivity(@PathVariable Long id) { - boolean resumed = promotionService.resumePromotionActivity(id); - - Map result = new HashMap<>(); - result.put("message", "推广活动已恢复"); - result.put("id", id); - - return ApiResponse.success(result); - } - - /** - * 获取奖励记录列表 - */ - @GetMapping("/rewards") - public ApiResponse> getRewardRecords( - @RequestParam(defaultValue = "1") Integer page, - @RequestParam(defaultValue = "10") Integer pageSize, - @RequestParam(required = false) String user, - @RequestParam(required = false) String rewardType, - @RequestParam(required = false) String status) { - - IPage rewards = promotionService.getRewardRecords(page, pageSize, user, rewardType, status); - - Map result = new HashMap<>(); - result.put("rewards", rewards.getRecords()); - result.put("pagination", Map.of( - "current", rewards.getCurrent(), - "pageSize", rewards.getSize(), - "total", rewards.getTotal(), - "totalPages", rewards.getPages() - )); - - return ApiResponse.success(result); - } - - /** - * 发放奖励 - */ - @PostMapping("/rewards/{id}/issue") - public ApiResponse> issueReward(@PathVariable Long id) { - boolean issued = promotionService.issueReward(id); - - Map result = new HashMap<>(); - result.put("message", "奖励已发放"); - result.put("id", id); - - return ApiResponse.success(result); - } - - /** - * 获取推广统计数据 - */ - @GetMapping("/statistics") - public ApiResponse> getPromotionStatistics() { - Map statistics = promotionService.getPromotionStatistics(); - return ApiResponse.success(statistics); - } -} \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/entity/PromotionActivity.java b/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/entity/PromotionActivity.java deleted file mode 100644 index b58759e..0000000 --- a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/entity/PromotionActivity.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.jiebanke.promotion.entity; - -import com.jiebanke.common.entity.BaseEntity; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -@Data -@EqualsAndHashCode(callSuper = true) -public class PromotionActivity extends BaseEntity { - private String name; - private String description; - private String rewardType; - private BigDecimal rewardAmount; - private String status; - private LocalDateTime startTime; - private LocalDateTime endTime; - private Integer maxParticipants; - private Integer currentParticipants; -} \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/entity/RewardRecord.java b/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/entity/RewardRecord.java deleted file mode 100644 index 0aabd52..0000000 --- a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/entity/RewardRecord.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.jiebanke.promotion.entity; - -import com.jiebanke.common.entity.BaseEntity; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.math.BigDecimal; -import java.time.LocalDateTime; - -@Data -@EqualsAndHashCode(callSuper = true) -public class RewardRecord extends BaseEntity { - private Long userId; - private String userName; - private String userPhone; - private Long activityId; - private String activityName; - private String rewardType; - private BigDecimal rewardAmount; - private String status; - private LocalDateTime issuedAt; -} \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/mapper/PromotionActivityMapper.java b/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/mapper/PromotionActivityMapper.java deleted file mode 100644 index 6728ce1..0000000 --- a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/mapper/PromotionActivityMapper.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.jiebanke.promotion.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.jiebanke.promotion.entity.PromotionActivity; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; -import org.apache.ibatis.annotations.Update; - -import java.util.List; - -@Mapper -public interface PromotionActivityMapper extends BaseMapper { - - /** - * 根据状态获取推广活动列表 - * @param status 状态 - * @return 推广活动列表 - */ - @Select("SELECT * FROM promotion_activities WHERE status = #{status} ORDER BY created_at DESC") - List selectByStatus(@Param("status") String status); - - /** - * 根据名称模糊查询推广活动 - * @param name 名称 - * @return 推广活动列表 - */ - @Select("SELECT * FROM promotion_activities WHERE name LIKE CONCAT('%', #{name}, '%') ORDER BY created_at DESC") - List selectByName(@Param("name") String name); - - /** - * 暂停推广活动 - * @param id 活动ID - * @return 更新记录数 - */ - @Update("UPDATE promotion_activities SET status = 'paused', updated_at = NOW() WHERE id = #{id}") - int pauseActivity(@Param("id") Long id); - - /** - * 恢复推广活动 - * @param id 活动ID - * @return 更新记录数 - */ - @Update("UPDATE promotion_activities SET status = 'active', updated_at = NOW() WHERE id = #{id}") - int resumeActivity(@Param("id") Long id); -} \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/mapper/RewardRecordMapper.java b/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/mapper/RewardRecordMapper.java deleted file mode 100644 index f9e3568..0000000 --- a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/mapper/RewardRecordMapper.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.jiebanke.promotion.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.jiebanke.promotion.entity.RewardRecord; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; -import org.apache.ibatis.annotations.Update; - -import java.util.List; - -@Mapper -public interface RewardRecordMapper extends BaseMapper { - - /** - * 根据用户ID获取奖励记录列表 - * @param userId 用户ID - * @return 奖励记录列表 - */ - @Select("SELECT * FROM reward_records WHERE user_id = #{userId} ORDER BY created_at DESC") - List selectByUserId(@Param("userId") Long userId); - - /** - * 根据状态获取奖励记录列表 - * @param status 状态 - * @return 奖励记录列表 - */ - @Select("SELECT * FROM reward_records WHERE status = #{status} ORDER BY created_at DESC") - List selectByStatus(@Param("status") String status); - - /** - * 发放奖励 - * @param id 奖励记录ID - * @return 更新记录数 - */ - @Update("UPDATE reward_records SET status = 'issued', issued_at = NOW() WHERE id = #{id}") - int issueReward(@Param("id") Long id); -} \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/service/PromotionService.java b/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/service/PromotionService.java deleted file mode 100644 index 75892e8..0000000 --- a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/service/PromotionService.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.jiebanke.promotion.service; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.jiebanke.promotion.entity.PromotionActivity; -import com.jiebanke.promotion.entity.RewardRecord; - -import java.util.Map; - -public interface PromotionService extends IService { - - /** - * 获取推广活动列表 - * @param page 页码 - * @param pageSize 每页数量 - * @param name 活动名称 - * @param status 状态 - * @return 推广活动分页列表 - */ - IPage getPromotionActivities(Integer page, Integer pageSize, String name, String status); - - /** - * 获取推广活动详情 - * @param id 活动ID - * @return 推广活动 - */ - PromotionActivity getPromotionActivityById(Long id); - - /** - * 创建推广活动 - * @param activity 活动信息 - * @return 创建的活动ID - */ - Long createPromotionActivity(PromotionActivity activity); - - /** - * 更新推广活动 - * @param id 活动ID - * @param activity 更新的活动信息 - * @return 更新后的活动 - */ - PromotionActivity updatePromotionActivity(Long id, PromotionActivity activity); - - /** - * 删除推广活动 - * @param id 活动ID - * @return 是否删除成功 - */ - boolean deletePromotionActivity(Long id); - - /** - * 暂停推广活动 - * @param id 活动ID - * @return 是否暂停成功 - */ - boolean pausePromotionActivity(Long id); - - /** - * 恢复推广活动 - * @param id 活动ID - * @return 是否恢复成功 - */ - boolean resumePromotionActivity(Long id); - - /** - * 获取奖励记录列表 - * @param page 页码 - * @param pageSize 每页数量 - * @param user 用户 - * @param rewardType 奖励类型 - * @param status 状态 - * @return 奖励记录分页列表 - */ - IPage getRewardRecords(Integer page, Integer pageSize, String user, String rewardType, String status); - - /** - * 发放奖励 - * @param id 奖励记录ID - * @return 是否发放成功 - */ - boolean issueReward(Long id); - - /** - * 获取推广统计数据 - * @return 统计数据 - */ - Map getPromotionStatistics(); -} \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/service/impl/PromotionServiceImpl.java b/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/service/impl/PromotionServiceImpl.java deleted file mode 100644 index 3d4ed88..0000000 --- a/backend-java/promotion-service/src/main/java/com/jiebanke/promotion/service/impl/PromotionServiceImpl.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.jiebanke.promotion.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.jiebanke.common.exception.BusinessException; -import com.jiebanke.promotion.entity.PromotionActivity; -import com.jiebanke.promotion.entity.RewardRecord; -import com.jiebanke.promotion.mapper.PromotionActivityMapper; -import com.jiebanke.promotion.mapper.RewardRecordMapper; -import com.jiebanke.promotion.service.PromotionService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.math.BigDecimal; -import java.util.HashMap; -import java.util.Map; - -@Service -public class PromotionServiceImpl extends ServiceImpl implements PromotionService { - - @Autowired - private PromotionActivityMapper promotionActivityMapper; - - @Autowired - private RewardRecordMapper rewardRecordMapper; - - @Override - public IPage getPromotionActivities(Integer page, Integer pageSize, String name, String status) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - - if (name != null && !name.isEmpty()) { - queryWrapper.like("name", name); - } - - if (status != null && !status.isEmpty()) { - queryWrapper.eq("status", status); - } - - queryWrapper.orderByDesc("created_at"); - - Page pageObj = new Page<>(page != null ? page : 1, pageSize != null ? pageSize : 10); - return this.page(pageObj, queryWrapper); - } - - @Override - public PromotionActivity getPromotionActivityById(Long id) { - PromotionActivity activity = this.getById(id); - if (activity == null) { - throw new BusinessException("推广活动不存在"); - } - return activity; - } - - @Override - public Long createPromotionActivity(PromotionActivity activity) { - this.save(activity); - return activity.getId(); - } - - @Override - public PromotionActivity updatePromotionActivity(Long id, PromotionActivity activity) { - PromotionActivity existingActivity = this.getById(id); - if (existingActivity == null) { - throw new BusinessException("推广活动不存在"); - } - - // 更新字段 - if (activity.getName() != null) { - existingActivity.setName(activity.getName()); - } - if (activity.getDescription() != null) { - existingActivity.setDescription(activity.getDescription()); - } - if (activity.getRewardType() != null) { - existingActivity.setRewardType(activity.getRewardType()); - } - if (activity.getRewardAmount() != null) { - existingActivity.setRewardAmount(activity.getRewardAmount()); - } - if (activity.getStatus() != null) { - existingActivity.setStatus(activity.getStatus()); - } - if (activity.getStartTime() != null) { - existingActivity.setStartTime(activity.getStartTime()); - } - if (activity.getEndTime() != null) { - existingActivity.setEndTime(activity.getEndTime()); - } - if (activity.getMaxParticipants() != null) { - existingActivity.setMaxParticipants(activity.getMaxParticipants()); - } - if (activity.getCurrentParticipants() != null) { - existingActivity.setCurrentParticipants(activity.getCurrentParticipants()); - } - - this.updateById(existingActivity); - return existingActivity; - } - - @Override - public boolean deletePromotionActivity(Long id) { - return this.removeById(id); - } - - @Override - public boolean pausePromotionActivity(Long id) { - int result = promotionActivityMapper.pauseActivity(id); - return result > 0; - } - - @Override - public boolean resumePromotionActivity(Long id) { - int result = promotionActivityMapper.resumeActivity(id); - return result > 0; - } - - @Override - public IPage getRewardRecords(Integer page, Integer pageSize, String user, String rewardType, String status) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - - if (user != null && !user.isEmpty()) { - queryWrapper.like("user_name", user).or().like("user_phone", user); - } - - if (rewardType != null && !rewardType.isEmpty()) { - queryWrapper.eq("reward_type", rewardType); - } - - if (status != null && !status.isEmpty()) { - queryWrapper.eq("status", status); - } - - queryWrapper.orderByDesc("created_at"); - - Page pageObj = new Page<>(page != null ? page : 1, pageSize != null ? pageSize : 10); - return rewardRecordMapper.selectPage(pageObj, queryWrapper); - } - - @Override - public boolean issueReward(Long id) { - int result = rewardRecordMapper.issueReward(id); - return result > 0; - } - - @Override - public Map getPromotionStatistics() { - // 获取活动总数 - int totalActivities = Math.toIntExact(this.count()); - - // 获取进行中的活动数 - QueryWrapper activeWrapper = new QueryWrapper<>(); - activeWrapper.eq("status", "active"); - int activeActivities = Math.toIntExact(this.count(activeWrapper)); - - // 获取奖励记录总数 - int totalRewards = Math.toIntExact(rewardRecordMapper.selectCount(null)); - - // 获取已发放的奖励数 - QueryWrapper issuedWrapper = new QueryWrapper<>(); - issuedWrapper.eq("status", "issued"); - int issuedRewards = Math.toIntExact(rewardRecordMapper.selectCount(issuedWrapper)); - - // 计算总奖励金额 - QueryWrapper amountWrapper = new QueryWrapper<>(); - amountWrapper.eq("status", "issued").select("SUM(reward_amount) as totalAmount"); - Map amountMap = rewardRecordMapper.selectMap(amountWrapper); - BigDecimal totalAmount = amountMap != null && amountMap.get("totalAmount") != null ? - new BigDecimal(amountMap.get("totalAmount").toString()) : BigDecimal.ZERO; - - Map statistics = new HashMap<>(); - statistics.put("totalActivities", totalActivities); - statistics.put("activeActivities", activeActivities); - statistics.put("totalRewards", totalRewards); - statistics.put("issuedRewards", issuedRewards); - statistics.put("totalAmount", totalAmount); - - return statistics; - } -} \ No newline at end of file diff --git a/backend-java/promotion-service/src/main/resources/application.yml b/backend-java/promotion-service/src/main/resources/application.yml deleted file mode 100644 index 6d19d0a..0000000 --- a/backend-java/promotion-service/src/main/resources/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8086 - -spring: - application: - name: promotion-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/promotion-service/target/classes/application.yml b/backend-java/promotion-service/target/classes/application.yml deleted file mode 100644 index 6d19d0a..0000000 --- a/backend-java/promotion-service/target/classes/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8086 - -spring: - application: - name: promotion-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/promotion-service/target/classes/com/jiebanke/promotion/PromotionApplication.class b/backend-java/promotion-service/target/classes/com/jiebanke/promotion/PromotionApplication.class deleted file mode 100644 index e8e1fad0cea320c063d990e7ebd1c119cfed6097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1103 zcmb7DT~8B16unbg+OE}N1r!k-(1(g~=f(ISN&*OpNmW9T#PBq`otA;!na%8MwSUCF zVxoz@`=g9^r!AmvOnlh++B@f-d(NF7KfinffEVzf3MB%MLLIYHDFUv}1WSyLwUt`2 z{po5eNg^5Y{ICjT0&}N)$XUeIfV~Y)MQ91kK9@?`O#(CRherg;JGv*TP$$s5h}|_t zn;Kjp@adg0BGu7Q^e84zWaPjp<_;ner_ZQYKRgjs#)&qTYBTWD#7H&h8y<@f+MM}e zq_du{6QTM-4ipW!Qrgl$&?&N4-&Gvp_VWKbkrc|N1!2@`%BdYC!t*~yeVo&D$mWq7z^Wq3BA7skPSiDk0nM$O;m8zEl_8HZ)M*8+@~6+hKYs>(?1BkA zEoP>b6(6y>bK%$ycC=R5Zj%I!fTv=ghi7~sP}RoeJg^G*X7DirlyFsnSsbgldxEC~ zXYVW2-nYEZ(D?3RnmFb$fKhWeHpWqK9a^}n!ws09Agup}uuy<7=MYMGZw7ASSb|%y hgmaF68|P*G)}Rb`a9+XhE}q{z29g4Gyw}|N{x6I0L1+K~ diff --git a/backend-java/promotion-service/target/classes/com/jiebanke/promotion/controller/PromotionController.class b/backend-java/promotion-service/target/classes/com/jiebanke/promotion/controller/PromotionController.class deleted file mode 100644 index 480882e64ca80c87ff5c226e1929eca98df3202d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7717 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 diff --git a/backend-java/promotion-service/target/classes/com/jiebanke/promotion/entity/PromotionActivity.class b/backend-java/promotion-service/target/classes/com/jiebanke/promotion/entity/PromotionActivity.class deleted file mode 100644 index bcbb65812e03c7dc95b368bce4428e4c7aa1100f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4830 zcmeHL+j1L45baTfb+KXxIhJFbgf$SbxM&G?;t-H+B@rb;DmJcyx6x`Mjk6bJcVzIF zQ3X}-#sfdWH}C@#XLq$)*;+dbwN!ZUgEiB$-DkRIdQNxw_rHGng@`_*PJwcabi=Xq z11Y-Pej@at>sXGGj;#w@Np++@j24=Pl80C+P@d6^V@43H*kX%&q7@i3%G=x$jH;aj ze#mu`+kJgkxzg@$GMeuR&v50?-;Gh(72k8Ww|6vzekBx|mNT*yqgrTgaW&AlWPe8( z(&8o{<~+sK$YWH(#8rFJ-)uG1RuJ@#V{mhaE8%~FK|$EPP;1fRKRkquG~|%m3K&aM zPPT0&`oe|9k}+~!oW*h7LSLu{L1>pZ>Qi=;;MN|&bL`o+52Yu&rfAx>17{H{wyJha z$Lcyy^n1b`sTHctYoBBRDqa$tcU}SZLyT?HYKFRpxx6fVa%j3no8b}b(&CW3be>UrbpBBJ* zJ27P!=?0_qvq=e@#ONaI9!-(^;zW-4{Yu24vkYH?^6r@AE8#ri`L)O@k?G4&Zbf8Y zh49r$zF&^)gR&GeehtdoiKOpEq`!dK)KMTtEF6n*B1bWVci2mJ`pgjpPoJT=k z9h)V@=v$Vd9Y+aaCd%4$zC=O#rZs3MhFMfjSjHG#*r@Lp>2t<@JNur4;O zRH25}R+{uQY4@Zn3}qgnKs^>HvXpj*r7DyexqFS zeUR4BaaH8SDbFlPwe@twO|NP9?sIS87vqHI`9CX~XewXZzBCLQ{O(Kk2Cb`lT6V*rCS;LwwWo~?Myl38vYZLoFOrj z-$~$JmdNB^Q1cYDIN!Ds(B>1+^0bozE$N*mp)qRF-BWyvBTb8zqkCYA9NiCUU>UPE I#O!<(|3DK2f*4&Pu{9_d=Y&RGU2lyJ@^YJ+|zRBhXXxn42#X7%1$}U20m? z*)|Kp*`6biP%9@8!aL=o;at@7017pc;hB20?wL~S`M1=Oq zZ6@F9Tr$(ymUwkGW9#S;ZS&49_ju7_ImZ#`1FMK$G6hT6Me)I0VGeVVwv3$dMNwwG zaE?HKvpCDHE8GN}CntWrbzJ5NYnPP`tZrd#7HFr*4YNDQKHJNQDjDA ztP}<{Bv$9x{J1j5i{PJa4^$I+`2I}62#lv;0xqCH&2xv#X9Uhnw}_1v$LtnrMu9tQ zt!5XQyGcSjf~R9hz*Pd1hieo{ z6iTw@(o%j3VXj5Z`&)3}PFVyePN3<^BEWT7KUWXvps*{U-q6~vvdA~&eXKqxT;RQ? zzz?;S+}C$i@IGx31ew;To)yBjtXi zoP-{Hi$O0W{5GlEl>XkQaay;h;Iwboukip3A|64;3=AR9FrpqrXRtkszkBG3V4M01 zBkwY!pJD7fq8MDnr?SHyFz}hy?~`x|5rNBaSvtXW?n+a diff --git a/backend-java/promotion-service/target/classes/com/jiebanke/promotion/mapper/PromotionActivityMapper.class b/backend-java/promotion-service/target/classes/com/jiebanke/promotion/mapper/PromotionActivityMapper.class deleted file mode 100644 index 97a1fa106aa5dd7d804dfec344fd4d9a72da549b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1407 zcmbVM+invv5FM8`p`|T_aw`O9OU!=u0txuuuA?iLnz$}v-4^MME fn)2R2@5h&TKbiJM1)D~}(-S4nOqLvGcnzcsi^>02(0(`31>bJyR6>n3D*=LPk;@4b$Ap=FG^U@?{Fh^>?axz zlsI!)=2~Q~2&`%0Bf8vgX`!kffhRk)bJw*f>=t)3Lt>=QYEqjbfh9+FLv9i!2sCB_ z-q!w+q6m#N{fQKd@6i30o#06zK1eM)zSs-H$Y3T>s0qBNMXJkq%-zp|$uvR6&o3}1 z%?F(ZG6*6oUA z)AC2^D#4BL+T75JqKN-O<-f3eAaE%*&4TE4;8`U)mx3qUeo$p zRL5%45xea)ptt>sW{ZK2C3;jp-q{_hKNMbirv!2mXJFZh66J~m>0|$FPEX+L!GsX_ zIyNcU5Ej!;pJM>$7G_raXLDV|w}8L`evA0hEZ}=lfUCG)!d(uQVFmwdc)E(;wNF4a z?yjS4bpTr*7&Y8L)J@nJp>AD(x;=%ugQ!ioi&4&EY>i^vo4S1;y+24fJsfg-l;ZM; Hc?|FeT>XZH diff --git a/backend-java/promotion-service/target/classes/com/jiebanke/promotion/service/PromotionService.class b/backend-java/promotion-service/target/classes/com/jiebanke/promotion/service/PromotionService.class deleted file mode 100644 index d05276c66c0beea899e3afbcc2f35a35affd95cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1683 zcmd5-&2G~`5T0#;^oO66(x&|O+FaN}4?UzH0TNQAAgcPtZDWtD4gS-59B`kZufhxT zzyt75h{_b{SK@MkbWA=iN>)?KBLS`8mFYw zMCNFw+DCcv8}a5q2W|=IPSjM%NF|~CIG&(S9k?UlaF%MU(pU#+A>(qaNatBpO%l`lD8Eeriz0NGedI zgBpAk8>v>UpE327=Xo8xpV2d|m?UW20L+j1BPcvnBlC}pkY z%3P;}fSzwq5iWMEwE0`^Q!C?st)-R`=PxpDMpJ%T;(u+0Zgk)PBWxtJy+o-0iSKl# zioA(`&tP7}O>er~v{U?|OmK>PB?BIS^Lp;T9Dth0Hyw$K|A@|2gHcz~&cvq9^8)Aa zg6DWN^C{9kOTKmBu46$uk{?vY<8-u$9WRSnL*|BPi*9&nVSIeABX*IUYFwQ4y_~rl z+uZWrcC%_X(yJ7ys@JT7JzKykKezdZu))6Gfi+&O^J>MeH{mYK{Qe%?xA6gVZQO!~ iHg3E4$i*Glt@ihL-=4!C!;=bs%DJD}3eR1o7ry{G$unC3 diff --git a/backend-java/promotion-service/target/classes/com/jiebanke/promotion/service/impl/PromotionServiceImpl.class b/backend-java/promotion-service/target/classes/com/jiebanke/promotion/service/impl/PromotionServiceImpl.class deleted file mode 100644 index ce78909d1b98a5a2d75158eb952ea2bb09bfaf8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7222 zcmd5=`F|AU9eyUqZnBwRNF=y;MXELl!SyVf1e8k+21F7Q!2>6|Lo%?tv&_y0g0|AC z^*-8CYOUJKDs8pZ)-EEg*b7^G+1u70+KN5?20o?F_nq0zB-srFe`qz#&U<~&=li_x zJForcrI!IL#=pa;&~S0wPQ^A`=8%!zV#YF#ow8laPRFvQGit@nn3c*TV`~fDeO_-5 zJHx2b&?T#f3_E2d>|880He|R~Hj~U{W9D|(OlPM^njj#gA$An?lQnCYTeNX$+_gq6 zcWkwh$(W9YMZIN&rPPFRFD5SR(hyyjOS@Le9I&$1P|{qQPTMX$vC~-wsMmIeW7&*j zrH3~;M#|h~J6mEyrjgFZHW_i(cE(~xaY1Zp&b7B$j+vm?M#tP{IEi&;+;$QLE6+cQ zmFuRgp`=i^mA2d^8Y)}c1~gPHw-aUrm6)xg9GT`)fVz9_xRD$% z9821MXO%l*(WTCECLA^CG^KgibcBWanGx}&vsvoUJKl16$s){}P4VbkfFzN^ob zs0JtbJ#EUulE7jt%~;BGjfCMEv7WWYut}?G`>f%#;pQB={_OwEknVDUH3=_wY$^h~ zmUM-2@^p2i+>P7mgr)Ep+nO^8xNGD&=qOxAFb}gMI1MdfoUWl^JPBSfb)13u8p2j~ zWhDGY6>!I^|nnsAooXX|)BTG^4bwlIJf2LpKZ&}K9426N>1v;}hOch#VsSk1C_ za#@kvp<|)QtuVLNAf_P_cTB@I6B`XzhR@S+J}%Hu$MP_pWn(MMY+S?HCA62&6~;wG z@-gra>1fzuv1SbZsH%<$Xd+mIOTxHV!|d^h`LNZ|34*G|O1lF_GRKgx?s_7)5R0YY zSclcEt5&rQM4;g^9ZRu{v7>xWe7JRH&^^lRK<52)cg?sqngWR`)Fqu0d;6>%w7D@b z!7o4!x5NPeQ};U>)_^k9yc@Ue6lQ;<(8Mt zt}OJ_V7-Pp?>@Na(7prjzOet$y?fqy@qt6nK62=>JrNAxdMVr+I3pO9!fwMYwZdY^ z8UhZeh_Ot##j8_>hVxXmXA(Z1Ry@X=ykU}snVvGom2zR35MO1Uq$i=n#3u4j))-|i zPw=n6)Egq`$A}IKtiNjJQSi~&8qAmP?%Z64`>I*OUN;yxHTyX1pQ*=UcUp&yjEBE9 z+^{s9IKgs1i89sEk(DHev!*Lkr7x#rRF==8+p@tpmI9CrZPzg-(`Rw|q@i1M+$yW; zxyn0{^^<92(T8;0CX4F1XyV9+b$kT3^DtIivovM%V5#Axg25@n9f>WohF6$zD`h0R zMBtq|K8m}ztSGRsEb51R@+#SQ`f-nrd&R_Bsv|3?Ew>-{>v%xStEIH@-iLHNjE|Aj zy}6Ft&(p4klM8mq;Wws;bp^98gUYl|=-7o%a+xQru|r+5m6VRx|QjK z$PB>bsuas+ zD#?L(aW)oC|3B988h*kp(B>t2BDWUL^*Xa*!rFBzfbIGdg!QQL1V|ZqmZR8n%=_bshb-G{bOd z*j!%Qdp_d@W5C=nrdBqaGrew! zaY|?P!h>j9n8&G)LXTEAzK^eG4MwXDVotP5_13euP2Lv_^6i{F&K=y33)e3=h{%FG zKJYZEs_yJyqeC^S8zOh^MR#YYJsOHu=W*$CR8|EsbUu9sPN&yr(7^dP6=$IxXY(H4 zhHfmt&FD~0T@3D z@}?QDIzsbHjaPZ=t0b{&a5bNj=&f{2T#L3dz-wPY|LTrcQNJGp>l?4ziwy@lB&L-r zrj7I*IFBBlPo!MHbYG-m*y0H&#xRN-aTCSYq5&Hjp$g?cF?bkr!#rbYFfin+mk3LY z>qLEgkdI+eSfLa~)KDh_*rgOncsaGGs7{F&f3_g$3Dj<+F=FOZ1%K8ooaj#;se`Cn zNCc(w*vcQ*Z@PJGV{?b!+>yrz+1%+jcjj>in|J%oyYsk@%?JJFgL!ufuk%$4*?2yKn;@VhVOMK2LDQlZdPMwR@2%#_uUV zQH++Ks9HRZXPL4}m9p80cqyAz_>V#U8ouu5u9NAIgoGs2&ppF8FKr%4j092^Dyj_m zDmA=Nlw)w6K(ML(1$=A4KJ2Z);!~bLb=5PKBGdz)hlLcgpALYosVKO~7hK1}{|;WJ zNGUp+au~A(AqUE;d!@X(EY-QkrSALq0Zs78@P~>F-=ZC@3bark?v0lZGg9mSWOyfJtTS4~&~P_D6EHBy~5!htVNSs;D$Pg-Q!-I#h!p zVbd}*NT@PH5$g0)6sMM%LRu9midNq&39{FT=|7bR*+T@`!^Z`(zu>P$kiDhY{6bcX t?8=e-czb>0-}mCs0k(o=xkqX8_U?$Ewo1IKX8pql>_3?nRXg|>@LvXC<1_#O diff --git a/backend-java/scripts/init-database.sql b/backend-java/scripts/init-database.sql deleted file mode 100644 index a08edcb..0000000 --- a/backend-java/scripts/init-database.sql +++ /dev/null @@ -1,137 +0,0 @@ --- 创建数据库 -CREATE DATABASE IF NOT EXISTS jiebanke CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -USE jiebanke; - --- 创建管理员表 -CREATE TABLE IF NOT EXISTS admins ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(50) NOT NULL UNIQUE, - password VARCHAR(255) NOT NULL, - email VARCHAR(100), - role VARCHAR(20) DEFAULT 'admin', - status VARCHAR(20) DEFAULT 'active', - last_login TIMESTAMP NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -); - --- 创建用户表 -CREATE TABLE IF NOT EXISTS users ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - username VARCHAR(50) NOT NULL UNIQUE, - password VARCHAR(255) NOT NULL, - email VARCHAR(100) UNIQUE, - phone VARCHAR(20), - real_name VARCHAR(100), - id_card VARCHAR(20), - status VARCHAR(20) DEFAULT 'active', - balance DECIMAL(15,2) DEFAULT 0.00, - credit_score INT DEFAULT 100, - last_login TIMESTAMP NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -); - --- 创建订单表 -CREATE TABLE IF NOT EXISTS orders ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - user_id BIGINT NOT NULL, - order_no VARCHAR(50) NOT NULL UNIQUE, - amount DECIMAL(15,2) NOT NULL, - status VARCHAR(20) DEFAULT 'pending', - type VARCHAR(20) NOT NULL, - description TEXT, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -); - --- 创建旅行计划表 -CREATE TABLE IF NOT EXISTS travel_plans ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - user_id BIGINT NOT NULL, - destination VARCHAR(100) NOT NULL, - start_date DATE NOT NULL, - end_date DATE NOT NULL, - budget DECIMAL(10,2), - interests TEXT, - description TEXT, - visibility VARCHAR(20) DEFAULT 'public', - status VARCHAR(20) DEFAULT 'active', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -); - --- 创建动物表 -CREATE TABLE IF NOT EXISTS animals ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - merchant_id BIGINT NOT NULL, - name VARCHAR(50) NOT NULL, - species VARCHAR(50) NOT NULL, - breed VARCHAR(50), - birth_date DATE, - personality TEXT, - farm_location VARCHAR(255), - price DECIMAL(10,2) NOT NULL, - claim_count INT DEFAULT 0, - status VARCHAR(20) DEFAULT 'available', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -); - --- 创建推广活动表 -CREATE TABLE IF NOT EXISTS promotion_activities ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - name VARCHAR(100) NOT NULL, - description TEXT, - reward_type VARCHAR(20), - reward_amount DECIMAL(10,2), - status VARCHAR(20) DEFAULT 'active', - start_time TIMESTAMP, - end_time TIMESTAMP, - max_participants INT, - current_participants INT DEFAULT 0, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -); - --- 创建奖励记录表 -CREATE TABLE IF NOT EXISTS reward_records ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - user_id BIGINT, - user_name VARCHAR(50), - user_phone VARCHAR(20), - activity_id BIGINT, - activity_name VARCHAR(100), - reward_type VARCHAR(20), - reward_amount DECIMAL(10,2), - status VARCHAR(20) DEFAULT 'pending', - issued_at TIMESTAMP, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - --- 插入默认管理员账号 -INSERT INTO admins (username, password, email, role) VALUES -('admin', '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'admin@jiebanke.com', 'super_admin'), -('manager', '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'manager@jiebanke.com', 'admin'); - --- 插入测试用户账号 -INSERT INTO users (username, password, email, phone, real_name, id_card, balance, credit_score) VALUES -('user1', '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'user1@jiebanke.com', '13800138001', '张三', '110101199001011234', 1000.00, 95), -('user2', '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'user2@jiebanke.com', '13800138002', '李四', '110101199002022345', 500.00, 85); - --- 创建索引 -CREATE INDEX idx_admins_username ON admins(username); -CREATE INDEX idx_admins_email ON admins(email); -CREATE INDEX idx_users_username ON users(username); -CREATE INDEX idx_users_email ON users(email); -CREATE INDEX idx_users_phone ON users(phone); -CREATE INDEX idx_orders_user_id ON orders(user_id); -CREATE INDEX idx_orders_order_no ON orders(order_no); -CREATE INDEX idx_orders_status ON orders(status); -CREATE INDEX idx_travel_plans_user_id ON travel_plans(user_id); -CREATE INDEX idx_travel_plans_destination ON travel_plans(destination); -CREATE INDEX idx_animals_species ON animals(species); -CREATE INDEX idx_animals_status ON animals(status); -CREATE INDEX idx_promotion_activities_status ON promotion_activities(status); -CREATE INDEX idx_reward_records_user_id ON reward_records(user_id); -CREATE INDEX idx_reward_records_activity_id ON reward_records(activity_id); \ No newline at end of file diff --git a/backend-java/start-services.sh b/backend-java/start-services.sh deleted file mode 100755 index 5a8040b..0000000 --- a/backend-java/start-services.sh +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash - -# 启动结伴客Java后端服务脚本 - -# 启动顺序:Eureka Server -> 其他服务 -> Gateway - -echo "开始启动结伴客Java后端服务..." - -# 启动Eureka Server -echo "正在启动Eureka Server..." -cd eureka-server -mvn spring-boot:run > eureka.log 2>&1 & -EUREKA_PID=$! -cd .. - -sleep 10 - -# 启动Auth Service -echo "正在启动Auth Service..." -cd auth-service -mvn spring-boot:run > auth.log 2>&1 & -AUTH_PID=$! -cd .. - -sleep 5 - -# 启动User Service -echo "正在启动User Service..." -cd user-service -mvn spring-boot:run > user.log 2>&1 & -USER_PID=$! -cd .. - -sleep 5 - -# 启动Travel Service -echo "正在启动Travel Service..." -cd travel-service -mvn spring-boot:run > travel.log 2>&1 & -TRAVEL_PID=$! -cd .. - -sleep 5 - -# 启动Animal Service -echo "正在启动Animal Service..." -cd animal-service -mvn spring-boot:run > animal.log 2>&1 & -ANIMAL_PID=$! -cd .. - -sleep 5 - -# 启动Order Service -echo "正在启动Order Service..." -cd order-service -mvn spring-boot:run > order.log 2>&1 & -ORDER_PID=$! -cd .. - -sleep 5 - -# 启动Promotion Service -echo "正在启动Promotion Service..." -cd promotion-service -mvn spring-boot:run > promotion.log 2>&1 & -PROMOTION_PID=$! -cd .. - -sleep 5 - -# 启动Gateway Service -echo "正在启动Gateway Service..." -cd gateway-service -mvn spring-boot:run > gateway.log 2>&1 & -GATEWAY_PID=$! -cd .. - -echo "所有服务已启动!" -echo "Eureka Server PID: $EUREKA_PID" -echo "Auth Service PID: $AUTH_PID" -echo "User Service PID: $USER_PID" -echo "Travel Service PID: $TRAVEL_PID" -echo "Animal Service PID: $ANIMAL_PID" -echo "Order Service PID: $ORDER_PID" -echo "Promotion Service PID: $PROMOTION_PID" -echo "Gateway Service PID: $GATEWAY_PID" - -echo "服务访问地址:" -echo "Eureka Dashboard: http://localhost:8761" -echo "API Gateway: http://localhost:8080" -echo "API文档: http://localhost:8080/doc.html" \ No newline at end of file diff --git a/backend-java/stop-services.sh b/backend-java/stop-services.sh deleted file mode 100755 index 03c9337..0000000 --- a/backend-java/stop-services.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# 停止结伴客Java后端服务脚本 - -echo "开始停止结伴客Java后端服务..." - -# 查找并停止所有相关的Java进程 -PIDS=$(ps aux | grep "com.jiebanke" | grep -v grep | awk '{print $2}') - -if [ -z "$PIDS" ]; then - echo "没有找到正在运行的结伴客服务" -else - echo "正在停止以下进程: $PIDS" - kill $PIDS - echo "服务已停止" -fi - -# 清理日志文件 -echo "清理日志文件..." -rm -f eureka-server/eureka.log -rm -f auth-service/auth.log -rm -f user-service/user.log -rm -f travel-service/travel.log -rm -f animal-service/animal.log -rm -f order-service/order.log -rm -f promotion-service/promotion.log -rm -f gateway-service/gateway.log - -echo "清理完成" \ No newline at end of file diff --git a/backend-java/travel-service/pom.xml b/backend-java/travel-service/pom.xml deleted file mode 100644 index 197395b..0000000 --- a/backend-java/travel-service/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - travel-service - jar - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - org.springframework.cloud - spring-cloud-starter-openfeign - - - - - com.baomidou - mybatis-plus-boot-starter - - - - - mysql - mysql-connector-java - - - - - com.jiebanke - common - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/backend-java/travel-service/src/main/java/com/jiebanke/travel/TravelApplication.java b/backend-java/travel-service/src/main/java/com/jiebanke/travel/TravelApplication.java deleted file mode 100644 index 891088b..0000000 --- a/backend-java/travel-service/src/main/java/com/jiebanke/travel/TravelApplication.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.jiebanke.travel; - -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@EnableDiscoveryClient -@EnableFeignClients -@MapperScan("com.jiebanke.travel.mapper") -@ComponentScan(basePackages = "com.jiebanke") -public class TravelApplication { - public static void main(String[] args) { - SpringApplication.run(TravelApplication.class, args); - } -} \ No newline at end of file diff --git a/backend-java/travel-service/src/main/java/com/jiebanke/travel/controller/TravelPlanController.java b/backend-java/travel-service/src/main/java/com/jiebanke/travel/controller/TravelPlanController.java deleted file mode 100644 index 6f13b3a..0000000 --- a/backend-java/travel-service/src/main/java/com/jiebanke/travel/controller/TravelPlanController.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.jiebanke.travel.controller; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.jiebanke.common.vo.ApiResponse; -import com.jiebanke.travel.entity.TravelPlan; -import com.jiebanke.travel.service.TravelPlanService; -import com.jiebanke.travel.service.TravelStats; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import java.util.HashMap; -import java.util.Map; - -@RestController -@RequestMapping("/api/travel") -public class TravelPlanController { - - @Autowired - private TravelPlanService travelPlanService; - - /** - * 获取旅行计划列表 - */ - @GetMapping("/plans") - public ApiResponse> getTravelPlans( - @RequestHeader("userId") Long userId, - @RequestParam(defaultValue = "1") Integer page, - @RequestParam(defaultValue = "10") Integer pageSize, - @RequestParam(required = false) String status) { - - IPage plans = travelPlanService.getTravelPlans(userId, page, pageSize, status); - - Map result = new HashMap<>(); - result.put("plans", plans.getRecords()); - result.put("pagination", Map.of( - "page", plans.getCurrent(), - "pageSize", plans.getSize(), - "total", plans.getTotal(), - "totalPages", plans.getPages() - )); - - return ApiResponse.success(result); - } - - /** - * 获取单个旅行计划详情 - */ - @GetMapping("/plans/{planId}") - public ApiResponse getTravelPlan(@PathVariable Long planId) { - TravelPlan plan = travelPlanService.getTravelPlanById(planId); - return ApiResponse.success(plan); - } - - /** - * 创建旅行计划 - */ - @PostMapping("/plans") - public ApiResponse> createTravelPlan( - @RequestHeader("userId") Long userId, - @RequestBody TravelPlan travelPlan) { - - Long planId = travelPlanService.createTravelPlan(userId, travelPlan); - TravelPlan plan = travelPlanService.getTravelPlanById(planId); - - Map result = new HashMap<>(); - result.put("plan", plan); - result.put("message", "旅行计划创建成功"); - - return ApiResponse.success(result); - } - - /** - * 更新旅行计划 - */ - @PutMapping("/plans/{planId}") - public ApiResponse> updateTravelPlan( - @PathVariable Long planId, - @RequestHeader("userId") Long userId, - @RequestBody TravelPlan travelPlan) { - - TravelPlan updatedPlan = travelPlanService.updateTravelPlan(planId, userId, travelPlan); - - Map result = new HashMap<>(); - result.put("plan", updatedPlan); - result.put("message", "旅行计划更新成功"); - - return ApiResponse.success(result); - } - - /** - * 删除旅行计划 - */ - @DeleteMapping("/plans/{planId}") - public ApiResponse> deleteTravelPlan( - @PathVariable Long planId, - @RequestHeader("userId") Long userId) { - - boolean deleted = travelPlanService.deleteTravelPlan(planId, userId); - - Map result = new HashMap<>(); - result.put("message", "旅行计划删除成功"); - result.put("planId", planId); - - return ApiResponse.success(result); - } - - /** - * 获取用户旅行统计 - */ - @GetMapping("/stats") - public ApiResponse getTravelStats(@RequestHeader("userId") Long userId) { - TravelStats stats = travelPlanService.getUserTravelStats(userId); - return ApiResponse.success(stats); - } -} \ No newline at end of file diff --git a/backend-java/travel-service/src/main/java/com/jiebanke/travel/entity/TravelPlan.java b/backend-java/travel-service/src/main/java/com/jiebanke/travel/entity/TravelPlan.java deleted file mode 100644 index 58f1c38..0000000 --- a/backend-java/travel-service/src/main/java/com/jiebanke/travel/entity/TravelPlan.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.jiebanke.travel.entity; - -import com.jiebanke.common.entity.BaseEntity; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.math.BigDecimal; -import java.time.LocalDate; - -@Data -@EqualsAndHashCode(callSuper = true) -public class TravelPlan extends BaseEntity { - private Long userId; - private String destination; - private LocalDate startDate; - private LocalDate endDate; - private BigDecimal budget; - private String interests; - private String description; - private String visibility; - private String status; -} \ No newline at end of file diff --git a/backend-java/travel-service/src/main/java/com/jiebanke/travel/mapper/TravelPlanMapper.java b/backend-java/travel-service/src/main/java/com/jiebanke/travel/mapper/TravelPlanMapper.java deleted file mode 100644 index a05f476..0000000 --- a/backend-java/travel-service/src/main/java/com/jiebanke/travel/mapper/TravelPlanMapper.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.jiebanke.travel.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.jiebanke.travel.entity.TravelPlan; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.apache.ibatis.annotations.Select; - -import java.util.List; - -@Mapper -public interface TravelPlanMapper extends BaseMapper { - - /** - * 根据用户ID获取旅行计划列表 - * @param userId 用户ID - * @return 旅行计划列表 - */ - @Select("SELECT * FROM travel_plans WHERE user_id = #{userId} ORDER BY created_at DESC") - List selectByUserId(@Param("userId") Long userId); - - /** - * 根据状态获取旅行计划列表 - * @param status 状态 - * @return 旅行计划列表 - */ - @Select("SELECT * FROM travel_plans WHERE status = #{status} ORDER BY created_at DESC") - List selectByStatus(@Param("status") String status); -} \ No newline at end of file diff --git a/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/TravelPlanService.java b/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/TravelPlanService.java deleted file mode 100644 index 3a7f2f2..0000000 --- a/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/TravelPlanService.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.jiebanke.travel.service; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.IService; -import com.jiebanke.travel.entity.TravelPlan; - -import java.util.List; - -public interface TravelPlanService extends IService { - - /** - * 获取旅行计划列表 - * @param userId 用户ID - * @param page 页码 - * @param pageSize 每页数量 - * @param status 状态 - * @return 旅行计划分页列表 - */ - IPage getTravelPlans(Long userId, Integer page, Integer pageSize, String status); - - /** - * 获取单个旅行计划详情 - * @param planId 计划ID - * @return 旅行计划 - */ - TravelPlan getTravelPlanById(Long planId); - - /** - * 创建旅行计划 - * @param userId 用户ID - * @param travelPlan 旅行计划信息 - * @return 创建的旅行计划ID - */ - Long createTravelPlan(Long userId, TravelPlan travelPlan); - - /** - * 更新旅行计划 - * @param planId 计划ID - * @param userId 用户ID - * @param travelPlan 更新的旅行计划信息 - * @return 更新后的旅行计划 - */ - TravelPlan updateTravelPlan(Long planId, Long userId, TravelPlan travelPlan); - - /** - * 删除旅行计划 - * @param planId 计划ID - * @param userId 用户ID - * @return 是否删除成功 - */ - boolean deleteTravelPlan(Long planId, Long userId); - - /** - * 获取用户旅行统计 - * @param userId 用户ID - * @return 统计信息 - */ - TravelStats getUserTravelStats(Long userId); -} \ No newline at end of file diff --git a/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/TravelStats.java b/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/TravelStats.java deleted file mode 100644 index e96d73b..0000000 --- a/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/TravelStats.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.jiebanke.travel.service; - -import lombok.Data; - -import java.math.BigDecimal; - -@Data -public class TravelStats { - private Integer totalPlans; - private Integer completedPlans; - private Integer planningPlans; - private Integer cancelledPlans; - private BigDecimal totalBudget; -} \ No newline at end of file diff --git a/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/impl/TravelPlanServiceImpl.java b/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/impl/TravelPlanServiceImpl.java deleted file mode 100644 index d9f49cb..0000000 --- a/backend-java/travel-service/src/main/java/com/jiebanke/travel/service/impl/TravelPlanServiceImpl.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.jiebanke.travel.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.jiebanke.common.exception.BusinessException; -import com.jiebanke.travel.entity.TravelPlan; -import com.jiebanke.travel.mapper.TravelPlanMapper; -import com.jiebanke.travel.service.TravelPlanService; -import com.jiebanke.travel.service.TravelStats; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class TravelPlanServiceImpl extends ServiceImpl implements TravelPlanService { - - @Override - public IPage getTravelPlans(Long userId, Integer page, Integer pageSize, String status) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - - if (userId != null) { - queryWrapper.eq("user_id", userId); - } - - if (status != null && !status.isEmpty()) { - queryWrapper.eq("status", status); - } - - queryWrapper.orderByDesc("created_at"); - - Page pageObj = new Page<>(page != null ? page : 1, pageSize != null ? pageSize : 10); - return this.page(pageObj, queryWrapper); - } - - @Override - public TravelPlan getTravelPlanById(Long planId) { - TravelPlan travelPlan = this.getById(planId); - if (travelPlan == null) { - throw new BusinessException("旅行计划不存在"); - } - return travelPlan; - } - - @Override - public Long createTravelPlan(Long userId, TravelPlan travelPlan) { - travelPlan.setUserId(userId); - this.save(travelPlan); - return travelPlan.getId(); - } - - @Override - public TravelPlan updateTravelPlan(Long planId, Long userId, TravelPlan travelPlan) { - TravelPlan existingPlan = this.getById(planId); - if (existingPlan == null) { - throw new BusinessException("旅行计划不存在"); - } - - if (!existingPlan.getUserId().equals(userId)) { - throw new BusinessException("没有权限修改此旅行计划"); - } - - // 更新字段 - if (travelPlan.getDestination() != null) { - existingPlan.setDestination(travelPlan.getDestination()); - } - if (travelPlan.getStartDate() != null) { - existingPlan.setStartDate(travelPlan.getStartDate()); - } - if (travelPlan.getEndDate() != null) { - existingPlan.setEndDate(travelPlan.getEndDate()); - } - if (travelPlan.getBudget() != null) { - existingPlan.setBudget(travelPlan.getBudget()); - } - if (travelPlan.getInterests() != null) { - existingPlan.setInterests(travelPlan.getInterests()); - } - if (travelPlan.getDescription() != null) { - existingPlan.setDescription(travelPlan.getDescription()); - } - if (travelPlan.getVisibility() != null) { - existingPlan.setVisibility(travelPlan.getVisibility()); - } - if (travelPlan.getStatus() != null) { - existingPlan.setStatus(travelPlan.getStatus()); - } - - this.updateById(existingPlan); - return existingPlan; - } - - @Override - public boolean deleteTravelPlan(Long planId, Long userId) { - TravelPlan existingPlan = this.getById(planId); - if (existingPlan == null) { - throw new BusinessException("旅行计划不存在"); - } - - if (!existingPlan.getUserId().equals(userId)) { - throw new BusinessException("没有权限删除此旅行计划"); - } - - return this.removeById(planId); - } - - @Override - public TravelStats getUserTravelStats(Long userId) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("user_id", userId); - - List plans = this.list(queryWrapper); - - TravelStats stats = new TravelStats(); - stats.setTotalPlans(plans.size()); - - int completedPlans = 0; - int planningPlans = 0; - int cancelledPlans = 0; - java.math.BigDecimal totalBudget = java.math.BigDecimal.ZERO; - - for (TravelPlan plan : plans) { - switch (plan.getStatus()) { - case "completed": - completedPlans++; - break; - case "planning": - planningPlans++; - break; - case "cancelled": - cancelledPlans++; - break; - } - - if (plan.getBudget() != null) { - totalBudget = totalBudget.add(plan.getBudget()); - } - } - - stats.setCompletedPlans(completedPlans); - stats.setPlanningPlans(planningPlans); - stats.setCancelledPlans(cancelledPlans); - stats.setTotalBudget(totalBudget); - - return stats; - } -} \ No newline at end of file diff --git a/backend-java/travel-service/src/main/resources/application.yml b/backend-java/travel-service/src/main/resources/application.yml deleted file mode 100644 index 7421ff9..0000000 --- a/backend-java/travel-service/src/main/resources/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8083 - -spring: - application: - name: travel-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/travel-service/target/classes/application.yml b/backend-java/travel-service/target/classes/application.yml deleted file mode 100644 index 7421ff9..0000000 --- a/backend-java/travel-service/target/classes/application.yml +++ /dev/null @@ -1,32 +0,0 @@ -server: - port: 8083 - -spring: - application: - name: travel-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ - -mybatis-plus: - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - global-config: - db-config: - id-type: auto \ No newline at end of file diff --git a/backend-java/user-service/pom.xml b/backend-java/user-service/pom.xml deleted file mode 100644 index 9b148ce..0000000 --- a/backend-java/user-service/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - com.jiebanke - backend-java - 1.0.0 - - - user-service - jar - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.cloud - spring-cloud-starter-netflix-eureka-client - - - - - org.springframework.cloud - spring-cloud-starter-openfeign - - - - - com.baomidou - mybatis-plus-boot-starter - - - - - mysql - mysql-connector-java - - - - - org.springframework.boot - spring-boot-starter-data-redis - - - - - org.springframework.boot - spring-boot-starter-amqp - - - - - com.jiebanke - common - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - \ No newline at end of file diff --git a/backend-java/user-service/src/main/java/com/jiebanke/user/UserApplication.java b/backend-java/user-service/src/main/java/com/jiebanke/user/UserApplication.java deleted file mode 100644 index 22e22c8..0000000 --- a/backend-java/user-service/src/main/java/com/jiebanke/user/UserApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.jiebanke.user; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.cloud.openfeign.EnableFeignClients; - -@SpringBootApplication -@EnableDiscoveryClient -@EnableFeignClients(basePackages = "com.jiebanke.user.client") -public class UserApplication { - public static void main(String[] args) { - SpringApplication.run(UserApplication.class, args); - } -} \ No newline at end of file diff --git a/backend-java/user-service/src/main/java/com/jiebanke/user/client/AuthServiceClient.java b/backend-java/user-service/src/main/java/com/jiebanke/user/client/AuthServiceClient.java deleted file mode 100644 index 5ed1d77..0000000 --- a/backend-java/user-service/src/main/java/com/jiebanke/user/client/AuthServiceClient.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.jiebanke.user.client; - -import com.jiebanke.common.vo.ApiResponse; -import com.jiebanke.user.config.FeignConfig; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestHeader; - -@FeignClient(name = "auth-service", configuration = FeignConfig.class) -public interface AuthServiceClient { - - @GetMapping("/api/auth/validate") - ApiResponse validateToken(@RequestHeader("Authorization") String token); -} \ No newline at end of file diff --git a/backend-java/user-service/src/main/java/com/jiebanke/user/config/FeignConfig.java b/backend-java/user-service/src/main/java/com/jiebanke/user/config/FeignConfig.java deleted file mode 100644 index 690119c..0000000 --- a/backend-java/user-service/src/main/java/com/jiebanke/user/config/FeignConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.jiebanke.user.config; - -import feign.RequestInterceptor; -import feign.RequestTemplate; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import jakarta.servlet.http.HttpServletRequest; - -@Configuration -public class FeignConfig { - - @Bean - public RequestInterceptor requestInterceptor() { - return new RequestInterceptor() { - @Override - public void apply(RequestTemplate template) { - ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - if (attributes != null) { - HttpServletRequest request = attributes.getRequest(); - String authorization = request.getHeader("Authorization"); - if (authorization != null) { - template.header("Authorization", authorization); - } - } - } - }; - } -} \ No newline at end of file diff --git a/backend-java/user-service/src/main/java/com/jiebanke/user/service/UserRabbitMQService.java b/backend-java/user-service/src/main/java/com/jiebanke/user/service/UserRabbitMQService.java deleted file mode 100644 index 2645fe9..0000000 --- a/backend-java/user-service/src/main/java/com/jiebanke/user/service/UserRabbitMQService.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.jiebanke.user.service; - -import com.jiebanke.common.config.RabbitMQConfig; -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.Map; - -@Service -public class UserRabbitMQService { - - @Autowired - private RabbitTemplate rabbitTemplate; - - // 发送用户注册消息 - public void sendUserRegistrationMessage(Long userId, String username) { - Map message = new HashMap<>(); - message.put("userId", userId); - message.put("username", username); - message.put("eventType", "USER_REGISTERED"); - - rabbitTemplate.convertAndSend( - RabbitMQConfig.EXCHANGE_NAME, - RabbitMQConfig.USER_ROUTING_KEY, - message - ); - } - - // 发送用户更新消息 - public void sendUserUpdateMessage(Long userId, String username) { - Map message = new HashMap<>(); - message.put("userId", userId); - message.put("username", username); - message.put("eventType", "USER_UPDATED"); - - rabbitTemplate.convertAndSend( - RabbitMQConfig.EXCHANGE_NAME, - RabbitMQConfig.USER_ROUTING_KEY, - message - ); - } -} \ No newline at end of file diff --git a/backend-java/user-service/src/main/java/com/jiebanke/user/service/UserRedisService.java b/backend-java/user-service/src/main/java/com/jiebanke/user/service/UserRedisService.java deleted file mode 100644 index 93546db..0000000 --- a/backend-java/user-service/src/main/java/com/jiebanke/user/service/UserRedisService.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.jiebanke.user.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.util.concurrent.TimeUnit; - -@Service -public class UserRedisService { - - @Autowired - private RedisTemplate redisTemplate; - - // 缓存用户信息 - public void cacheUserInfo(Long userId, Object userInfo) { - redisTemplate.opsForValue().set("user:" + userId, userInfo, 30, TimeUnit.MINUTES); - } - - // 获取缓存的用户信息 - public Object getCachedUserInfo(Long userId) { - return redisTemplate.opsForValue().get("user:" + userId); - } - - // 删除缓存的用户信息 - public void removeCachedUserInfo(Long userId) { - redisTemplate.delete("user:" + userId); - } - - // 缓存用户登录状态 - public void cacheUserLoginStatus(String token, Long userId) { - redisTemplate.opsForValue().set("login:token:" + token, userId, 7, TimeUnit.DAYS); - } - - // 获取用户登录状态 - public Long getUserLoginStatus(String token) { - return (Long) redisTemplate.opsForValue().get("login:token:" + token); - } - - // 删除用户登录状态 - public void removeUserLoginStatus(String token) { - redisTemplate.delete("login:token:" + token); - } -} \ No newline at end of file diff --git a/backend-java/user-service/src/main/resources/application.yml b/backend-java/user-service/src/main/resources/application.yml deleted file mode 100644 index efcdc3f..0000000 --- a/backend-java/user-service/src/main/resources/application.yml +++ /dev/null @@ -1,25 +0,0 @@ -server: - port: 8082 - -spring: - application: - name: user-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ \ No newline at end of file diff --git a/backend-java/user-service/src/test/java/com/jiebanke/user/service/UserRabbitMQServiceTest.java b/backend-java/user-service/src/test/java/com/jiebanke/user/service/UserRabbitMQServiceTest.java deleted file mode 100644 index 5105a95..0000000 --- a/backend-java/user-service/src/test/java/com/jiebanke/user/service/UserRabbitMQServiceTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.jiebanke.user.service; - -import com.jiebanke.common.config.RabbitMQConfig; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.amqp.rabbit.core.RabbitTemplate; - -import static org.mockito.Mockito.*; - -class UserRabbitMQServiceTest { - - @Mock - private RabbitTemplate rabbitTemplate; - - @InjectMocks - private UserRabbitMQService userRabbitMQService; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - } - - @Test - void testSendUserRegistrationMessage() { - Long userId = 1L; - String username = "testUser"; - - userRabbitMQService.sendUserRegistrationMessage(userId, username); - - verify(rabbitTemplate).convertAndSend( - RabbitMQConfig.EXCHANGE_NAME, - RabbitMQConfig.USER_ROUTING_KEY, - anyMap() - ); - } - - @Test - void testSendUserUpdateMessage() { - Long userId = 1L; - String username = "testUser"; - - userRabbitMQService.sendUserUpdateMessage(userId, username); - - verify(rabbitTemplate).convertAndSend( - RabbitMQConfig.EXCHANGE_NAME, - RabbitMQConfig.USER_ROUTING_KEY, - anyMap() - ); - } -} \ No newline at end of file diff --git a/backend-java/user-service/src/test/java/com/jiebanke/user/service/UserRedisServiceTest.java b/backend-java/user-service/src/test/java/com/jiebanke/user/service/UserRedisServiceTest.java deleted file mode 100644 index 0029b98..0000000 --- a/backend-java/user-service/src/test/java/com/jiebanke/user/service/UserRedisServiceTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.jiebanke.user.service; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ValueOperations; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -class UserRedisServiceTest { - - @Mock - private RedisTemplate redisTemplate; - - @Mock - private ValueOperations valueOperations; - - @InjectMocks - private UserRedisService userRedisService; - - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - when(redisTemplate.opsForValue()).thenReturn(valueOperations); - } - - @Test - void testCacheUserInfo() { - Long userId = 1L; - String userInfo = "testUser"; - - userRedisService.cacheUserInfo(userId, userInfo); - - verify(valueOperations).set(eq("user:" + userId), eq(userInfo), anyLong(), any()); - } - - @Test - void testGetCachedUserInfo() { - Long userId = 1L; - String userInfo = "testUser"; - when(valueOperations.get("user:" + userId)).thenReturn(userInfo); - - Object result = userRedisService.getCachedUserInfo(userId); - - assertEquals(userInfo, result); - verify(valueOperations).get("user:" + userId); - } - - @Test - void testRemoveCachedUserInfo() { - Long userId = 1L; - - userRedisService.removeCachedUserInfo(userId); - - verify(redisTemplate).delete("user:" + userId); - } - - @Test - void testCacheUserLoginStatus() { - String token = "testToken"; - Long userId = 1L; - - userRedisService.cacheUserLoginStatus(token, userId); - - verify(valueOperations).set(eq("login:token:" + token), eq(userId), anyLong(), any()); - } - - @Test - void testGetUserLoginStatus() { - String token = "testToken"; - Long userId = 1L; - when(valueOperations.get("login:token:" + token)).thenReturn(userId); - - Long result = userRedisService.getUserLoginStatus(token); - - assertEquals(userId, result); - verify(valueOperations).get("login:token:" + token); - } - - @Test - void testRemoveUserLoginStatus() { - String token = "testToken"; - - userRedisService.removeUserLoginStatus(token); - - verify(redisTemplate).delete("login:token:" + token); - } -} \ No newline at end of file diff --git a/backend-java/user-service/target/classes/application.yml b/backend-java/user-service/target/classes/application.yml deleted file mode 100644 index efcdc3f..0000000 --- a/backend-java/user-service/target/classes/application.yml +++ /dev/null @@ -1,25 +0,0 @@ -server: - port: 8082 - -spring: - application: - name: user-service - datasource: - url: jdbc:mysql://localhost:3306/jiebanke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai - username: root - password: root - driver-class-name: com.mysql.cj.jdbc.Driver - redis: - host: localhost - port: 6379 - database: 0 - rabbitmq: - host: localhost - port: 5672 - username: guest - password: guest - -eureka: - client: - service-url: - defaultZone: http://localhost:8761/eureka/ \ No newline at end of file From 4db35e91d49cb541b7d1e441ff74b2bfdae598f2 Mon Sep 17 00:00:00 2001 From: ylweng Date: Fri, 12 Sep 2025 00:57:52 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E7=94=B1=E4=BA=8E=E6=9C=AC=E6=AC=A1?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=8F=98=E6=9B=B4=E5=86=85=E5=AE=B9=E4=B8=BA?= =?UTF-8?q?=E7=A9=BA=EF=BC=8C=E6=97=A0=E6=B3=95=E7=94=9F=E6=88=90=E6=9C=89?= =?UTF-8?q?=E6=95=88=E7=9A=84=E6=8F=90=E4=BA=A4=E4=BF=A1=E6=81=AF=E3=80=82?= =?UTF-8?q?=E8=AF=B7=E6=8F=90=E4=BE=9B=E5=85=B7=E4=BD=93=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=8F=98=E6=9B=B4=E5=86=85=E5=AE=B9=E4=BB=A5=E4=BE=BF?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=90=88=E9=80=82=E7=9A=84=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E3=80=82=E7=99=BB=E5=BD=95=E3=80=81=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E7=99=BB=E5=BD=95=E7=AD=89=E8=AE=A4=E8=AF=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD-=20=E6=B7=BB=E5=8A=A0=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=8A=9F=E8=83=BD=20-=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E8=B5=84=E6=96=99=E6=9B=B4=E6=96=B0=E5=92=8C?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E4=BF=AE=E6=94=B9-=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E8=BF=9E=E6=8E=A5=E5=92=8C=20Alembi?= =?UTF-8?q?c=20=E8=BF=81=E7=A7=BB=20-=20=E6=B7=BB=E5=8A=A0=E5=81=A5?= =?UTF-8?q?=E5=BA=B7=E6=A3=80=E6=9F=A5=E5=92=8C=E7=B3=BB=E7=BB=9F=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1=E6=8E=A5=E5=8F=A3=20-=20=E5=AE=9E=E7=8E=B0=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86=E5=92=8C?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E6=A0=BC=E5=BC=8F=20-=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=20FastAPI=20=E5=BA=94=E7=94=A8=E5=92=8C=E4=B8=AD=E9=97=B4?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi-backend/alembic.ini | 41 +++ fastapi-backend/alembic/env.py | 79 +++++ .../versions/0001_initial_migration.py | 62 ++++ fastapi-backend/app/api/api.py | 121 +++++++ fastapi-backend/app/api/deps.py | 115 ++++++ fastapi-backend/app/api/endpoints/auth.py | 332 ++++++++++++++++++ fastapi-backend/app/api/endpoints/users.py | 174 +++++++++ fastapi-backend/app/core/config.py | 59 ++++ fastapi-backend/app/core/security.py | 46 +++ fastapi-backend/app/crud/user.py | 287 +++++++++++++++ fastapi-backend/app/db/session.py | 29 ++ fastapi-backend/app/models/user.py | 44 +++ fastapi-backend/app/schemas/user.py | 167 +++++++++ fastapi-backend/app/utils/errors.py | 59 ++++ fastapi-backend/app/utils/response.py | 43 +++ fastapi-backend/main.py | 15 + fastapi-backend/migrations/env.py | 74 ++++ fastapi-backend/requirements.txt | 16 + 18 files changed, 1763 insertions(+) create mode 100644 fastapi-backend/alembic.ini create mode 100644 fastapi-backend/alembic/env.py create mode 100644 fastapi-backend/alembic/versions/0001_initial_migration.py create mode 100644 fastapi-backend/app/api/api.py create mode 100644 fastapi-backend/app/api/deps.py create mode 100644 fastapi-backend/app/api/endpoints/auth.py create mode 100644 fastapi-backend/app/api/endpoints/users.py create mode 100644 fastapi-backend/app/core/config.py create mode 100644 fastapi-backend/app/core/security.py create mode 100644 fastapi-backend/app/crud/user.py create mode 100644 fastapi-backend/app/db/session.py create mode 100644 fastapi-backend/app/models/user.py create mode 100644 fastapi-backend/app/schemas/user.py create mode 100644 fastapi-backend/app/utils/errors.py create mode 100644 fastapi-backend/app/utils/response.py create mode 100644 fastapi-backend/main.py create mode 100644 fastapi-backend/migrations/env.py create mode 100644 fastapi-backend/requirements.txt diff --git a/fastapi-backend/alembic.ini b/fastapi-backend/alembic.ini new file mode 100644 index 0000000..52cd8d1 --- /dev/null +++ b/fastapi-backend/alembic.ini @@ -0,0 +1,41 @@ +[alembic] +# 模板路径 +script_location = fastapi-backend/alembic + +# 数据库连接URL +sqlalchemy.url = mysql+pymysql://jiebanke:aiot741$12346@nj-cdb-3pwh2kz1.sql.tencentcdb.com:20784/jbkdata + +# 日志配置 +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S \ No newline at end of file diff --git a/fastapi-backend/alembic/env.py b/fastapi-backend/alembic/env.py new file mode 100644 index 0000000..99b9f96 --- /dev/null +++ b/fastapi-backend/alembic/env.py @@ -0,0 +1,79 @@ +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context + +# 导入模型 +from app.models.user import Base + +# 导入配置 +from app.core.config import settings + +# 确保Python能够找到app模块 +import os +import sys +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) + +# 这是Alembic Config对象,它提供对.ini文件中值的访问 +config = context.config + +# 解释配置文件并设置日志记录器 +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# 添加你的模型元数据对象 +target_metadata = Base.metadata + +# 其他值来自config,可以通过以下方式定义: +# my_important_option = config.get_main_option("my_important_option") +# ... 等等。 + + +def run_migrations_offline() -> None: + """在'offline'模式下运行迁移。 + + 这配置了上下文,只需要一个URL,并且不要求引擎可用。 + 跳过引擎创建,甚至不需要DBAPI可用。 + + 调用context.execute()来执行迁移。 + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """在'online'模式下运行迁移。 + + 在这种情况下,我们创建了一个Engine并将其与迁移上下文关联。 + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() \ No newline at end of file diff --git a/fastapi-backend/alembic/versions/0001_initial_migration.py b/fastapi-backend/alembic/versions/0001_initial_migration.py new file mode 100644 index 0000000..f568c27 --- /dev/null +++ b/fastapi-backend/alembic/versions/0001_initial_migration.py @@ -0,0 +1,62 @@ +"""initial migration + +Revision ID: 0001 +Revises: +Create Date: 2025-09-11 16:00:00.000000 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '0001' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # 创建用户表 + op.create_table( + 'users', + sa.Column('id', sa.Integer, primary_key=True, index=True), + sa.Column('username', sa.String(50), unique=True, index=True, nullable=False), + sa.Column('password_hash', sa.String(255), nullable=False), + sa.Column('user_type', sa.Enum('farmer', 'merchant', 'admin', 'super_admin'), server_default='farmer'), + sa.Column('real_name', sa.String(50)), + sa.Column('nickname', sa.String(50)), + sa.Column('avatar_url', sa.String(255)), + sa.Column('email', sa.String(100), unique=True, index=True), + sa.Column('phone', sa.String(20), unique=True, index=True), + sa.Column('gender', sa.Enum('male', 'female', 'other'), server_default='other'), + sa.Column('birthday', sa.DateTime), + sa.Column('status', sa.Enum('active', 'inactive'), server_default='active'), + sa.Column('wechat_openid', sa.String(100), unique=True, index=True), + sa.Column('wechat_unionid', sa.String(100), unique=True, index=True), + sa.Column('level', sa.Integer, server_default='1'), + sa.Column('created_at', sa.DateTime, server_default=sa.func.now()), + sa.Column('updated_at', sa.DateTime, server_default=sa.func.now(), onupdate=sa.func.now()), + sa.Column('last_login', sa.DateTime) + ) + + # 创建管理员表 + op.create_table( + 'admins', + sa.Column('id', sa.Integer, primary_key=True, index=True), + sa.Column('username', sa.String(50), unique=True, index=True, nullable=False), + sa.Column('password', sa.String(255), nullable=False), + sa.Column('email', sa.String(100), unique=True, index=True), + sa.Column('nickname', sa.String(50)), + sa.Column('avatar', sa.String(255)), + sa.Column('role', sa.Enum('admin', 'super_admin'), server_default='admin'), + sa.Column('status', sa.Enum('active', 'inactive'), server_default='active'), + sa.Column('last_login', sa.DateTime), + sa.Column('created_at', sa.DateTime, server_default=sa.func.now()), + sa.Column('updated_at', sa.DateTime, server_default=sa.func.now(), onupdate=sa.func.now()) + ) + + +def downgrade(): + op.drop_table('admins') + op.drop_table('users') \ No newline at end of file diff --git a/fastapi-backend/app/api/api.py b/fastapi-backend/app/api/api.py new file mode 100644 index 0000000..d34f3a1 --- /dev/null +++ b/fastapi-backend/app/api/api.py @@ -0,0 +1,121 @@ +from fastapi import APIRouter, FastAPI +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse +from fastapi.exceptions import RequestValidationError +from starlette.exceptions import HTTPException as StarletteHTTPException + +from app.api.endpoints import auth, users +from app.core.config import settings +from app.utils.response import error_response + +# 创建FastAPI应用 +app = FastAPI( + title=settings.PROJECT_NAME, + openapi_url=f"{settings.API_V1_STR}/openapi.json", + docs_url="/api-docs", + redoc_url="/redoc", +) + +# 配置CORS +if settings.BACKEND_CORS_ORIGINS: + app.add_middleware( + CORSMiddleware, + allow_origins=[str(origin) for origin in settings.BACKEND_CORS_ORIGINS], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) +else: + # 默认CORS配置 + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + +# 创建API路由 +api_router = APIRouter() + +# 添加各个端点路由 +api_router.include_router(auth.router, prefix="/auth", tags=["认证"]) +api_router.include_router(users.router, prefix="/users", tags=["用户"]) + +# 将API路由添加到应用 +app.include_router(api_router, prefix=settings.API_V1_STR) + + +# 自定义异常处理 +@app.exception_handler(StarletteHTTPException) +async def http_exception_handler(request, exc): + return JSONResponse( + status_code=exc.status_code, + content=error_response( + message=str(exc.detail), + code=exc.status_code + ) + ) + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler(request, exc): + errors = [] + for error in exc.errors(): + error_msg = f"{error['loc'][-1]}: {error['msg']}" + errors.append(error_msg) + + return JSONResponse( + status_code=400, + content=error_response( + message="请求参数验证失败", + code=400, + data={"errors": errors} + ) + ) + + +# 健康检查路由 +@app.get("/health") +async def health_check(): + import platform + import psutil + from datetime import datetime + + return { + "status": "OK", + "timestamp": datetime.now().isoformat(), + "uptime": psutil.boot_time(), + "environment": settings.DEBUG and "development" or "production", + "no_db_mode": settings.NO_DB_MODE, + "system_info": { + "python_version": platform.python_version(), + "platform": platform.platform(), + "cpu_count": psutil.cpu_count(), + "memory": { + "total": psutil.virtual_memory().total, + "available": psutil.virtual_memory().available, + } + } + } + + +# 系统统计路由 +@app.get("/system-stats") +async def system_stats(): + import platform + import psutil + from datetime import datetime + + return { + "status": "OK", + "timestamp": datetime.now().isoformat(), + "environment": settings.DEBUG and "development" or "production", + "python_version": platform.python_version(), + "memory_usage": dict(psutil.virtual_memory()._asdict()), + "uptime": psutil.boot_time(), + "cpu_count": psutil.cpu_count(), + "platform": platform.platform(), + "architecture": platform.architecture(), + "no_db_mode": settings.NO_DB_MODE + } \ No newline at end of file diff --git a/fastapi-backend/app/api/deps.py b/fastapi-backend/app/api/deps.py new file mode 100644 index 0000000..56fe47e --- /dev/null +++ b/fastapi-backend/app/api/deps.py @@ -0,0 +1,115 @@ +from typing import Generator, Optional +from fastapi import Depends, HTTPException, status +from fastapi.security import OAuth2PasswordBearer +from jose import jwt, JWTError +from pydantic import ValidationError +from sqlalchemy.orm import Session + +from app.core.config import settings +from app.core.security import verify_password +from app.crud.user import user, admin +from app.db.session import SessionLocal +from app.models.user import User, Admin +from app.schemas.user import TokenPayload + +# OAuth2密码承载令牌 +oauth2_scheme = OAuth2PasswordBearer( + tokenUrl=f"{settings.API_V1_STR}/auth/login" +) + +# 获取数据库会话 +def get_db() -> Generator: + try: + db = SessionLocal() + yield db + finally: + db.close() + +# 获取当前用户 +def get_current_user( + db: Session = Depends(get_db), token: str = Depends(oauth2_scheme) +) -> User: + try: + payload = jwt.decode( + token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] + ) + token_data = TokenPayload(**payload) + + # 检查令牌是否过期 + if token_data.exp is None: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="令牌无效", + headers={"WWW-Authenticate": "Bearer"}, + ) + except (JWTError, ValidationError): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="无法验证凭据", + headers={"WWW-Authenticate": "Bearer"}, + ) + + # 获取用户 + current_user = user.get(db, user_id=token_data.sub) + if not current_user: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="用户不存在") + + # 检查用户是否活跃 + if not user.is_active(current_user): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账户已被禁用") + + return current_user + +# 获取当前活跃用户 +def get_current_active_user( + current_user: User = Depends(get_current_user), +) -> User: + if not user.is_active(current_user): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账户已被禁用") + return current_user + +# 获取当前管理员 +def get_current_admin( + db: Session = Depends(get_db), token: str = Depends(oauth2_scheme) +) -> Admin: + try: + payload = jwt.decode( + token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] + ) + token_data = TokenPayload(**payload) + except (JWTError, ValidationError): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="无法验证凭据", + headers={"WWW-Authenticate": "Bearer"}, + ) + + # 获取管理员 + current_admin = admin.get(db, admin_id=token_data.sub) + if not current_admin: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="管理员不存在") + + # 检查管理员是否活跃 + if not admin.is_active(current_admin): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账户已被禁用") + + return current_admin + +# 获取当前活跃管理员 +def get_current_active_admin( + current_admin: Admin = Depends(get_current_admin), +) -> Admin: + if not admin.is_active(current_admin): + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="账户已被禁用") + return current_admin + +# 获取超级管理员 +def get_current_super_admin( + current_admin: Admin = Depends(get_current_admin), +) -> Admin: + if current_admin.role != "super_admin": + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="需要超级管理员权限" + ) + return current_admin \ No newline at end of file diff --git a/fastapi-backend/app/api/endpoints/auth.py b/fastapi-backend/app/api/endpoints/auth.py new file mode 100644 index 0000000..e20fa85 --- /dev/null +++ b/fastapi-backend/app/api/endpoints/auth.py @@ -0,0 +1,332 @@ +from datetime import timedelta +from typing import Any + +from fastapi import APIRouter, Body, Depends, HTTPException, status +from fastapi.security import OAuth2PasswordRequestForm +from sqlalchemy.orm import Session + +from app.api.deps import get_db, get_current_user +from app.core.config import settings +from app.core.security import create_access_token, create_refresh_token +from app.crud.user import user, admin +from app.schemas.user import ( + UserCreate, UserResponse, UserLogin, UserWithToken, + Token, PasswordChange, AdminWithToken +) +from app.utils.response import success_response, error_response +from app.utils.errors import BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError + +router = APIRouter() + + +@router.post("/register", response_model=UserWithToken, status_code=status.HTTP_201_CREATED) +def register( + *, + db: Session = Depends(get_db), + user_in: UserCreate, +) -> Any: + """ + 用户注册 + """ + # 检查用户名是否已存在 + if user.get_by_username(db, username=user_in.username): + raise BadRequestError("用户名已存在") + + # 检查邮箱是否已存在 + if user_in.email and user.get_by_email(db, email=user_in.email): + raise BadRequestError("邮箱已存在") + + # 检查手机号是否已存在 + if user_in.phone and user.get_by_phone(db, phone=user_in.phone): + raise BadRequestError("手机号已存在") + + # 创建新用户 + db_user = user.create(db, obj_in=user_in) + + # 更新最后登录时间 + user.update_last_login(db, db_obj=db_user) + + # 生成令牌 + access_token = create_access_token(db_user.id) + refresh_token = create_refresh_token(db_user.id) + + return success_response( + data={ + "user": db_user, + "token": access_token, + "refresh_token": refresh_token + }, + message="注册成功", + code=201 + ) + + +@router.post("/login", response_model=UserWithToken) +def login( + *, + db: Session = Depends(get_db), + form_data: OAuth2PasswordRequestForm = Depends() +) -> Any: + """ + 用户登录 + """ + # 验证用户 + db_user = user.authenticate(db, username=form_data.username, password=form_data.password) + if not db_user: + raise UnauthorizedError("用户名或密码错误") + + # 检查用户状态 + if not user.is_active(db_user): + raise ForbiddenError("账户已被禁用") + + # 更新最后登录时间 + user.update_last_login(db, db_obj=db_user) + + # 生成令牌 + access_token = create_access_token(db_user.id) + refresh_token = create_refresh_token(db_user.id) + + return success_response( + data={ + "user": db_user, + "token": access_token, + "refresh_token": refresh_token + }, + message="登录成功" + ) + + +@router.post("/login/json", response_model=UserWithToken) +def login_json( + *, + db: Session = Depends(get_db), + login_in: UserLogin +) -> Any: + """ + 用户登录(JSON格式) + """ + # 验证用户 + db_user = user.authenticate(db, username=login_in.username, password=login_in.password) + if not db_user: + raise UnauthorizedError("用户名或密码错误") + + # 检查用户状态 + if not user.is_active(db_user): + raise ForbiddenError("账户已被禁用") + + # 更新最后登录时间 + user.update_last_login(db, db_obj=db_user) + + # 生成令牌 + access_token = create_access_token(db_user.id) + refresh_token = create_refresh_token(db_user.id) + + return success_response( + data={ + "user": db_user, + "token": access_token, + "refresh_token": refresh_token + }, + message="登录成功" + ) + + +@router.post("/refresh-token", response_model=Token) +def refresh_token( + *, + db: Session = Depends(get_db), + refresh_token: str = Body(..., embed=True) +) -> Any: + """ + 刷新访问令牌 + """ + try: + from jose import jwt + from pydantic import ValidationError + from app.schemas.user import TokenPayload + + payload = jwt.decode( + refresh_token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] + ) + token_data = TokenPayload(**payload) + + # 检查令牌类型 + if token_data.type != "refresh": + raise UnauthorizedError("无效的刷新令牌") + + # 检查用户是否存在 + db_user = user.get(db, user_id=token_data.sub) + if not db_user: + raise NotFoundError("用户不存在") + + # 检查用户状态 + if not user.is_active(db_user): + raise ForbiddenError("账户已被禁用") + + # 生成新令牌 + access_token = create_access_token(db_user.id) + new_refresh_token = create_refresh_token(db_user.id) + + return success_response( + data={ + "access_token": access_token, + "refresh_token": new_refresh_token, + "token_type": "bearer" + } + ) + except (jwt.JWTError, ValidationError): + raise UnauthorizedError("无效的刷新令牌") + + +@router.get("/me", response_model=UserResponse) +def get_current_user_info( + current_user: UserResponse = Depends(get_current_user) +) -> Any: + """ + 获取当前用户信息 + """ + return success_response(data=current_user) + + +@router.put("/profile", response_model=UserResponse) +def update_profile( + *, + db: Session = Depends(get_db), + current_user: UserResponse = Depends(get_current_user), + profile_in: dict = Body(...) +) -> Any: + """ + 更新用户个人信息 + """ + # 更新用户信息 + db_user = user.update(db, db_obj=current_user, obj_in=profile_in) + + return success_response( + data=db_user, + message="个人信息更新成功" + ) + + +@router.put("/password", response_model=dict) +def change_password( + *, + db: Session = Depends(get_db), + current_user: UserResponse = Depends(get_current_user), + password_in: PasswordChange +) -> Any: + """ + 修改密码 + """ + from app.core.security import verify_password + + # 验证当前密码 + if not verify_password(password_in.current_password, current_user.password_hash): + raise UnauthorizedError("当前密码错误") + + # 更新密码 + user.update_password(db, db_obj=current_user, new_password=password_in.new_password) + + return success_response(message="密码修改成功") + + +@router.post("/admin/login", response_model=AdminWithToken) +def admin_login( + *, + db: Session = Depends(get_db), + login_in: UserLogin +) -> Any: + """ + 管理员登录 + """ + # 验证管理员 + db_admin = admin.authenticate(db, username=login_in.username, password=login_in.password) + if not db_admin: + raise UnauthorizedError("用户名或密码错误") + + # 检查管理员状态 + if not admin.is_active(db_admin): + raise ForbiddenError("账户已被禁用") + + # 更新最后登录时间 + admin.update_last_login(db, db_obj=db_admin) + + # 生成令牌 + access_token = create_access_token(db_admin.id) + refresh_token = create_refresh_token(db_admin.id) + + return success_response( + data={ + "admin": db_admin, + "token": access_token, + "refresh_token": refresh_token + }, + message="管理员登录成功" + ) + + +@router.post("/wechat", response_model=UserWithToken) +def wechat_login( + *, + db: Session = Depends(get_db), + code: str = Body(...), + user_info: dict = Body(None) +) -> Any: + """ + 微信登录/注册 + """ + # 模拟获取微信用户信息 + wechat_user_info = { + "openid": f"mock_openid_{code}", + "unionid": f"mock_unionid_{code}", + "nickname": user_info.get("nickName") if user_info else "微信用户", + "avatar": user_info.get("avatarUrl") if user_info else "", + "gender": "male" if user_info and user_info.get("gender") == 1 else + "female" if user_info and user_info.get("gender") == 2 else "other" + } + + # 查找是否已存在微信用户 + db_user = user.get_by_wechat_openid(db, openid=wechat_user_info["openid"]) + + if db_user: + # 更新最后登录时间 + user.update_last_login(db, db_obj=db_user) + else: + # 创建新用户(微信注册) + import secrets + import string + from app.schemas.user import UserCreate + + # 生成随机密码 + alphabet = string.ascii_letters + string.digits + random_password = ''.join(secrets.choice(alphabet) for _ in range(12)) + + # 创建用户 + user_in = UserCreate( + username=f"wx_{wechat_user_info['openid'][-8:]}", + password=random_password, + nickname=wechat_user_info["nickname"], + user_type="farmer" + ) + + db_user = user.create(db, obj_in=user_in) + + # 更新微信信息 + user.update(db, db_obj=db_user, obj_in={ + "wechat_openid": wechat_user_info["openid"], + "wechat_unionid": wechat_user_info["unionid"], + "avatar_url": wechat_user_info["avatar"], + "gender": wechat_user_info["gender"] + }) + + # 生成令牌 + access_token = create_access_token(db_user.id) + refresh_token = create_refresh_token(db_user.id) + + return success_response( + data={ + "user": db_user, + "token": access_token, + "refresh_token": refresh_token + }, + message="微信登录成功" + ) \ No newline at end of file diff --git a/fastapi-backend/app/api/endpoints/users.py b/fastapi-backend/app/api/endpoints/users.py new file mode 100644 index 0000000..220b5c5 --- /dev/null +++ b/fastapi-backend/app/api/endpoints/users.py @@ -0,0 +1,174 @@ +from typing import Any, List + +from fastapi import APIRouter, Body, Depends, Query, Path, status +from sqlalchemy.orm import Session + +from app.api.deps import get_db, get_current_user, get_current_admin, get_current_super_admin +from app.crud.user import user +from app.models.user import User +from app.schemas.user import ( + UserResponse, UserUpdate, UserListResponse, + PaginationResponse, UserStatistics, BatchUserStatusUpdate +) +from app.utils.response import success_response +from app.utils.errors import NotFoundError, BadRequestError + +router = APIRouter() + + +@router.get("/profile", response_model=UserResponse) +def get_user_profile( + current_user: User = Depends(get_current_user), +) -> Any: + """ + 获取当前用户个人信息 + """ + return success_response(data=current_user) + + +@router.put("/profile", response_model=UserResponse) +def update_user_profile( + *, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), + user_in: UserUpdate, +) -> Any: + """ + 更新当前用户个人信息 + """ + # 更新用户信息 + db_user = user.update(db, db_obj=current_user, obj_in=user_in) + + return success_response( + data=db_user, + message="个人信息更新成功" + ) + + +@router.get("", response_model=UserListResponse) +def get_users( + db: Session = Depends(get_db), + current_admin: User = Depends(get_current_admin), + page: int = Query(1, ge=1, description="页码"), + page_size: int = Query(20, ge=1, le=100, description="每页数量"), + user_type: str = Query(None, description="用户类型"), + status: str = Query(None, description="用户状态"), + keyword: str = Query(None, description="搜索关键词"), +) -> Any: + """ + 获取用户列表(管理员) + """ + # 计算分页参数 + skip = (page - 1) * page_size + + # 获取用户列表 + users_list = user.get_multi( + db, skip=skip, limit=page_size, + user_type=user_type, status=status, keyword=keyword + ) + + # 获取用户总数 + total = user.count( + db, user_type=user_type, status=status, keyword=keyword + ) + + # 计算总页数 + total_pages = (total + page_size - 1) // page_size + + # 构建分页信息 + pagination = PaginationResponse( + page=page, + page_size=page_size, + total=total, + total_pages=total_pages + ) + + return success_response( + data={ + "users": users_list, + "pagination": pagination + } + ) + + +@router.get("/{user_id}", response_model=UserResponse) +def get_user_by_id( + user_id: int = Path(..., ge=1), + db: Session = Depends(get_db), + current_admin: User = Depends(get_current_admin), +) -> Any: + """ + 获取用户详情(管理员) + """ + # 获取用户 + db_user = user.get(db, user_id=user_id) + if not db_user: + raise NotFoundError("用户不存在") + + return success_response(data=db_user) + + +@router.get("/statistics", response_model=UserStatistics) +def get_user_statistics( + db: Session = Depends(get_db), + current_admin: User = Depends(get_current_admin), +) -> Any: + """ + 获取用户统计信息(管理员) + """ + # 获取统计信息 + statistics = user.get_statistics(db) + + return success_response(data=statistics) + + +@router.post("/batch-status", response_model=dict) +def batch_update_user_status( + *, + db: Session = Depends(get_db), + current_admin: User = Depends(get_current_admin), + batch_in: BatchUserStatusUpdate, +) -> Any: + """ + 批量操作用户状态(管理员) + """ + # 检查用户ID列表是否为空 + if not batch_in.user_ids: + raise BadRequestError("用户ID列表不能为空") + + # 批量更新用户状态 + affected_rows = user.batch_update_status( + db, user_ids=batch_in.user_ids, status=batch_in.status + ) + + return success_response( + data={ + "message": f"成功更新{affected_rows}个用户的状态", + "affected_rows": affected_rows + } + ) + + +@router.delete("/{user_id}", response_model=dict) +def delete_user( + user_id: int = Path(..., ge=1), + db: Session = Depends(get_db), + current_admin: User = Depends(get_current_super_admin), +) -> Any: + """ + 删除用户(超级管理员) + """ + # 获取用户 + db_user = user.get(db, user_id=user_id) + if not db_user: + raise NotFoundError("用户不存在") + + # 删除用户 + user.remove(db, user_id=user_id) + + return success_response( + data={ + "message": "用户删除成功", + "user_id": user_id + } + ) \ No newline at end of file diff --git a/fastapi-backend/app/core/config.py b/fastapi-backend/app/core/config.py new file mode 100644 index 0000000..985a7ef --- /dev/null +++ b/fastapi-backend/app/core/config.py @@ -0,0 +1,59 @@ +import os +from typing import Any, Dict, List, Optional, Union +from pydantic import AnyHttpUrl, field_validator +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + # 基本配置 + PROJECT_NAME: str = "结伴客API" + API_V1_STR: str = "/api/v1" + DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true" + + # 服务器配置 + HOST: str = os.getenv("HOST", "0.0.0.0") + PORT: int = int(os.getenv("PORT", "3110")) + + # 安全配置 + SECRET_KEY: str = os.getenv("SECRET_KEY", "dev-jwt-secret-key-2024") + ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "10080")) # 7天 + REFRESH_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("REFRESH_TOKEN_EXPIRE_MINUTES", "43200")) # 30天 + ALGORITHM: str = "HS256" + + # 数据库配置 + DB_HOST: str = os.getenv("DB_HOST", "nj-cdb-3pwh2kz1.sql.tencentcdb.com") + DB_PORT: int = int(os.getenv("DB_PORT", "20784")) + DB_USER: str = os.getenv("DB_USER", "jiebanke") + DB_PASSWORD: str = os.getenv("DB_PASSWORD", "aiot741$12346") + DB_NAME: str = os.getenv("DB_NAME", "jbkdata") + + # 构建数据库URL + @property + def SQLALCHEMY_DATABASE_URI(self) -> str: + return f"mysql+pymysql://{self.DB_USER}:{self.DB_PASSWORD}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}" + + # CORS配置 + BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = [] + + @field_validator("BACKEND_CORS_ORIGINS", mode="before") + def assemble_cors_origins(cls, v: Union[str, List[str]]) -> Union[List[str], str]: + if isinstance(v, str) and not v.startswith("["): + return [i.strip() for i in v.split(",")] + elif isinstance(v, (list, str)): + return v + raise ValueError(v) + + # 上传文件配置 + UPLOAD_DIR: str = "uploads" + MAX_FILE_SIZE: int = 10 * 1024 * 1024 # 10MB + ALLOWED_EXTENSIONS: List[str] = ["jpg", "jpeg", "png", "gif", "webp"] + + # 无数据库模式 + NO_DB_MODE: bool = os.getenv("NO_DB_MODE", "False").lower() == "true" + + class Config: + case_sensitive = True + env_file = ".env" + + +settings = Settings() \ No newline at end of file diff --git a/fastapi-backend/app/core/security.py b/fastapi-backend/app/core/security.py new file mode 100644 index 0000000..b5533dd --- /dev/null +++ b/fastapi-backend/app/core/security.py @@ -0,0 +1,46 @@ +from datetime import datetime, timedelta +from typing import Any, Optional, Union + +from jose import jwt +from passlib.context import CryptContext + +from app.core.config import settings + +# 密码上下文 +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + +# 验证密码 +def verify_password(plain_password: str, hashed_password: str) -> bool: + return pwd_context.verify(plain_password, hashed_password) + +# 获取密码哈希 +def get_password_hash(password: str) -> str: + return pwd_context.hash(password) + +# 创建访问令牌 +def create_access_token( + subject: Union[str, Any], expires_delta: Optional[timedelta] = None +) -> str: + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta( + minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES + ) + to_encode = {"exp": expire, "sub": str(subject)} + encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) + return encoded_jwt + +# 创建刷新令牌 +def create_refresh_token( + subject: Union[str, Any], expires_delta: Optional[timedelta] = None +) -> str: + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta( + minutes=settings.REFRESH_TOKEN_EXPIRE_MINUTES + ) + to_encode = {"exp": expire, "sub": str(subject), "type": "refresh"} + encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) + return encoded_jwt \ No newline at end of file diff --git a/fastapi-backend/app/crud/user.py b/fastapi-backend/app/crud/user.py new file mode 100644 index 0000000..57bdce2 --- /dev/null +++ b/fastapi-backend/app/crud/user.py @@ -0,0 +1,287 @@ +from datetime import datetime +from typing import Any, Dict, Optional, Union, List +from sqlalchemy.orm import Session +from sqlalchemy import func, or_ + +from app.core.security import get_password_hash, verify_password +from app.models.user import User, Admin +from app.schemas.user import UserCreate, UserUpdate, AdminCreate, AdminUpdate + + +# 用户CRUD操作 +class CRUDUser: + # 根据ID获取用户 + def get(self, db: Session, user_id: int) -> Optional[User]: + return db.query(User).filter(User.id == user_id).first() + + # 根据用户名获取用户 + def get_by_username(self, db: Session, username: str) -> Optional[User]: + return db.query(User).filter(User.username == username).first() + + # 根据邮箱获取用户 + def get_by_email(self, db: Session, email: str) -> Optional[User]: + return db.query(User).filter(User.email == email).first() + + # 根据手机号获取用户 + def get_by_phone(self, db: Session, phone: str) -> Optional[User]: + return db.query(User).filter(User.phone == phone).first() + + # 根据微信OpenID获取用户 + def get_by_wechat_openid(self, db: Session, openid: str) -> Optional[User]: + return db.query(User).filter(User.wechat_openid == openid).first() + + # 创建用户 + def create(self, db: Session, obj_in: UserCreate) -> User: + db_obj = User( + username=obj_in.username, + password_hash=get_password_hash(obj_in.password), + user_type=obj_in.user_type, + real_name=obj_in.real_name or obj_in.username, + nickname=obj_in.nickname or obj_in.username, + email=obj_in.email, + phone=obj_in.phone, + created_at=datetime.now(), + updated_at=datetime.now() + ) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + # 更新用户 + def update( + self, db: Session, *, db_obj: User, obj_in: Union[UserUpdate, Dict[str, Any]] + ) -> User: + if isinstance(obj_in, dict): + update_data = obj_in + else: + update_data = obj_in.dict(exclude_unset=True) + + # 更新时间 + update_data["updated_at"] = datetime.now() + + for field in update_data: + if field in update_data: + setattr(db_obj, field, update_data[field]) + + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + # 更新用户密码 + def update_password(self, db: Session, db_obj: User, new_password: str) -> User: + db_obj.password_hash = get_password_hash(new_password) + db_obj.updated_at = datetime.now() + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + # 更新用户最后登录时间 + def update_last_login(self, db: Session, db_obj: User) -> User: + db_obj.last_login = datetime.now() + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + # 验证用户密码 + def authenticate(self, db: Session, username: str, password: str) -> Optional[User]: + user = self.get_by_username(db, username) + if not user: + user = self.get_by_email(db, username) + if not user: + user = self.get_by_phone(db, username) + if not user: + return None + if not verify_password(password, user.password_hash): + return None + return user + + # 检查用户是否活跃 + def is_active(self, user: User) -> bool: + return user.status == "active" + + # 获取用户列表(带分页) + def get_multi( + self, db: Session, *, skip: int = 0, limit: int = 100, + user_type: Optional[str] = None, status: Optional[str] = None, + keyword: Optional[str] = None + ) -> List[User]: + query = db.query(User) + + # 应用过滤条件 + if user_type: + query = query.filter(User.user_type == user_type) + if status: + query = query.filter(User.status == status) + if keyword: + query = query.filter( + or_( + User.username.like(f"%{keyword}%"), + User.real_name.like(f"%{keyword}%"), + User.nickname.like(f"%{keyword}%"), + User.email.like(f"%{keyword}%"), + User.phone.like(f"%{keyword}%") + ) + ) + + return query.offset(skip).limit(limit).all() + + # 获取用户总数 + def count( + self, db: Session, *, user_type: Optional[str] = None, + status: Optional[str] = None, keyword: Optional[str] = None + ) -> int: + query = db.query(func.count(User.id)) + + # 应用过滤条件 + if user_type: + query = query.filter(User.user_type == user_type) + if status: + query = query.filter(User.status == status) + if keyword: + query = query.filter( + or_( + User.username.like(f"%{keyword}%"), + User.real_name.like(f"%{keyword}%"), + User.nickname.like(f"%{keyword}%"), + User.email.like(f"%{keyword}%"), + User.phone.like(f"%{keyword}%") + ) + ) + + return query.scalar() + + # 批量更新用户状态 + def batch_update_status( + self, db: Session, user_ids: List[int], status: str + ) -> int: + result = db.query(User).filter(User.id.in_(user_ids)).update( + {"status": status, "updated_at": datetime.now()}, + synchronize_session=False + ) + db.commit() + return result + + # 删除用户 + def remove(self, db: Session, *, user_id: int) -> Optional[User]: + user = db.query(User).filter(User.id == user_id).first() + if user: + db.delete(user) + db.commit() + return user + + # 获取用户统计信息 + def get_statistics(self, db: Session) -> Dict[str, Any]: + total_users = db.query(func.count(User.id)).scalar() + farmers = db.query(func.count(User.id)).filter(User.user_type == "farmer").scalar() + merchants = db.query(func.count(User.id)).filter(User.user_type == "merchant").scalar() + admins = db.query(func.count(User.id)).filter( + or_(User.user_type == "admin", User.user_type == "super_admin") + ).scalar() + active_users = db.query(func.count(User.id)).filter(User.status == "active").scalar() + inactive_users = db.query(func.count(User.id)).filter(User.status == "inactive").scalar() + + return { + "total_users": total_users, + "farmers": farmers, + "merchants": merchants, + "admins": admins, + "active_users": active_users, + "inactive_users": inactive_users, + "date": datetime.now() + } + + +# 管理员CRUD操作 +class CRUDAdmin: + # 根据ID获取管理员 + def get(self, db: Session, admin_id: int) -> Optional[Admin]: + return db.query(Admin).filter(Admin.id == admin_id).first() + + # 根据用户名获取管理员 + def get_by_username(self, db: Session, username: str) -> Optional[Admin]: + return db.query(Admin).filter(Admin.username == username).first() + + # 创建管理员 + def create(self, db: Session, obj_in: AdminCreate) -> Admin: + db_obj = Admin( + username=obj_in.username, + password=get_password_hash(obj_in.password), + email=obj_in.email, + nickname=obj_in.nickname or obj_in.username, + avatar=obj_in.avatar, + role=obj_in.role, + created_at=datetime.now(), + updated_at=datetime.now() + ) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + # 更新管理员 + def update( + self, db: Session, *, db_obj: Admin, obj_in: Union[AdminUpdate, Dict[str, Any]] + ) -> Admin: + if isinstance(obj_in, dict): + update_data = obj_in + else: + update_data = obj_in.dict(exclude_unset=True) + + # 更新时间 + update_data["updated_at"] = datetime.now() + + for field in update_data: + if field in update_data: + setattr(db_obj, field, update_data[field]) + + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + # 更新管理员密码 + def update_password(self, db: Session, db_obj: Admin, new_password: str) -> Admin: + db_obj.password = get_password_hash(new_password) + db_obj.updated_at = datetime.now() + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + # 更新管理员最后登录时间 + def update_last_login(self, db: Session, db_obj: Admin) -> Admin: + db_obj.last_login = datetime.now() + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + # 验证管理员密码 + def authenticate(self, db: Session, username: str, password: str) -> Optional[Admin]: + admin = self.get_by_username(db, username) + if not admin: + return None + if not verify_password(password, admin.password): + return None + return admin + + # 检查管理员是否活跃 + def is_active(self, admin: Admin) -> bool: + return admin.status == "active" + + # 删除管理员 + def remove(self, db: Session, *, admin_id: int) -> Optional[Admin]: + admin = db.query(Admin).filter(Admin.id == admin_id).first() + if admin: + db.delete(admin) + db.commit() + return admin + + +# 实例化CRUD对象 +user = CRUDUser() +admin = CRUDAdmin() \ No newline at end of file diff --git a/fastapi-backend/app/db/session.py b/fastapi-backend/app/db/session.py new file mode 100644 index 0000000..c11086b --- /dev/null +++ b/fastapi-backend/app/db/session.py @@ -0,0 +1,29 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +from app.core.config import settings + +# 创建数据库引擎 +engine = create_engine( + settings.SQLALCHEMY_DATABASE_URI, + pool_pre_ping=True, + pool_recycle=3600, + pool_size=20, + max_overflow=0, + echo=settings.DEBUG +) + +# 创建会话工厂 +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +# 创建基础模型类 +Base = declarative_base() + +# 获取数据库会话 +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/fastapi-backend/app/models/user.py b/fastapi-backend/app/models/user.py new file mode 100644 index 0000000..607add5 --- /dev/null +++ b/fastapi-backend/app/models/user.py @@ -0,0 +1,44 @@ +from datetime import datetime +from sqlalchemy import Boolean, Column, String, Integer, DateTime, Enum +from sqlalchemy.sql import func + +from app.db.session import Base + + +class User(Base): + __tablename__ = "users" + + id = Column(Integer, primary_key=True, index=True) + username = Column(String(50), unique=True, index=True, nullable=False) + password_hash = Column(String(255), nullable=False) + user_type = Column(Enum('farmer', 'merchant', 'admin', 'super_admin'), default='farmer') + real_name = Column(String(50)) + nickname = Column(String(50)) + avatar_url = Column(String(255)) + email = Column(String(100), unique=True, index=True) + phone = Column(String(20), unique=True, index=True) + gender = Column(Enum('male', 'female', 'other'), default='other') + birthday = Column(DateTime) + status = Column(Enum('active', 'inactive'), default='active') + wechat_openid = Column(String(100), unique=True, index=True) + wechat_unionid = Column(String(100), unique=True, index=True) + level = Column(Integer, default=1) + created_at = Column(DateTime, default=func.now()) + updated_at = Column(DateTime, default=func.now(), onupdate=func.now()) + last_login = Column(DateTime) + + +class Admin(Base): + __tablename__ = "admins" + + id = Column(Integer, primary_key=True, index=True) + username = Column(String(50), unique=True, index=True, nullable=False) + password = Column(String(255), nullable=False) + email = Column(String(100), unique=True, index=True) + nickname = Column(String(50)) + avatar = Column(String(255)) + role = Column(Enum('admin', 'super_admin'), default='admin') + status = Column(Enum('active', 'inactive'), default='active') + last_login = Column(DateTime) + created_at = Column(DateTime, default=func.now()) + updated_at = Column(DateTime, default=func.now(), onupdate=func.now()) \ No newline at end of file diff --git a/fastapi-backend/app/schemas/user.py b/fastapi-backend/app/schemas/user.py new file mode 100644 index 0000000..9fabbd9 --- /dev/null +++ b/fastapi-backend/app/schemas/user.py @@ -0,0 +1,167 @@ +from datetime import datetime +from typing import Optional, List +from pydantic import BaseModel, EmailStr, Field, validator + + +# 用户基础模式 +class UserBase(BaseModel): + username: Optional[str] = None + email: Optional[EmailStr] = None + phone: Optional[str] = None + user_type: Optional[str] = None + real_name: Optional[str] = None + nickname: Optional[str] = None + avatar_url: Optional[str] = None + gender: Optional[str] = None + birthday: Optional[datetime] = None + + +# 创建用户请求模式 +class UserCreate(BaseModel): + username: str = Field(..., min_length=3, max_length=50) + password: str = Field(..., min_length=6) + email: Optional[EmailStr] = None + phone: Optional[str] = None + real_name: Optional[str] = None + nickname: Optional[str] = None + user_type: str = "farmer" + + +# 更新用户请求模式 +class UserUpdate(BaseModel): + nickname: Optional[str] = None + avatar_url: Optional[str] = None + gender: Optional[str] = None + birthday: Optional[datetime] = None + email: Optional[EmailStr] = None + phone: Optional[str] = None + + +# 用户登录请求模式 +class UserLogin(BaseModel): + username: str + password: str + + +# 密码更改请求模式 +class PasswordChange(BaseModel): + current_password: str + new_password: str = Field(..., min_length=6) + + +# 用户响应模式 +class UserResponse(UserBase): + id: int + status: str + created_at: datetime + updated_at: datetime + last_login: Optional[datetime] = None + + class Config: + orm_mode = True + + +# 带令牌的用户响应模式 +class UserWithToken(BaseModel): + user: UserResponse + token: str + refresh_token: Optional[str] = None + + +# 令牌响应模式 +class Token(BaseModel): + access_token: str + refresh_token: str + token_type: str = "bearer" + + +# 令牌数据模式 +class TokenPayload(BaseModel): + sub: Optional[int] = None + exp: Optional[int] = None + type: Optional[str] = None + + +# 管理员基础模式 +class AdminBase(BaseModel): + username: str + email: Optional[EmailStr] = None + nickname: Optional[str] = None + avatar: Optional[str] = None + role: str = "admin" + + +# 创建管理员请求模式 +class AdminCreate(AdminBase): + password: str = Field(..., min_length=6) + + +# 更新管理员请求模式 +class AdminUpdate(BaseModel): + nickname: Optional[str] = None + avatar: Optional[str] = None + email: Optional[EmailStr] = None + role: Optional[str] = None + status: Optional[str] = None + + +# 管理员响应模式 +class AdminResponse(AdminBase): + id: int + status: str + created_at: datetime + updated_at: datetime + last_login: Optional[datetime] = None + + class Config: + orm_mode = True + + +# 带令牌的管理员响应模式 +class AdminWithToken(BaseModel): + admin: AdminResponse + token: str + refresh_token: Optional[str] = None + + +# 微信登录请求模式 +class WechatLogin(BaseModel): + code: str + user_info: Optional[dict] = None + + +# 分页响应模式 +class PaginationResponse(BaseModel): + page: int + page_size: int + total: int + total_pages: int + + +# 用户列表响应模式 +class UserListResponse(BaseModel): + users: List[UserResponse] + pagination: PaginationResponse + + +# 用户统计响应模式 +class UserStatistics(BaseModel): + total_users: int + farmers: int + merchants: int + admins: int + active_users: int + inactive_users: int + date: Optional[datetime] = None + + +# 批量更新用户状态请求模式 +class BatchUserStatusUpdate(BaseModel): + user_ids: List[int] + status: str + + @validator("status") + def validate_status(cls, v): + if v not in ["active", "inactive"]: + raise ValueError("状态必须是 'active' 或 'inactive'") + return v \ No newline at end of file diff --git a/fastapi-backend/app/utils/errors.py b/fastapi-backend/app/utils/errors.py new file mode 100644 index 0000000..599d063 --- /dev/null +++ b/fastapi-backend/app/utils/errors.py @@ -0,0 +1,59 @@ +from fastapi import HTTPException, status + + +class AppError(HTTPException): + """ + 应用程序自定义错误类 + """ + def __init__( + self, + detail: str, + status_code: int = status.HTTP_400_BAD_REQUEST, + headers: dict = None + ): + super().__init__(status_code=status_code, detail=detail, headers=headers) + + +# 常用错误 +class NotFoundError(AppError): + """ + 资源未找到错误 + """ + def __init__(self, detail: str = "资源未找到"): + super().__init__(detail=detail, status_code=status.HTTP_404_NOT_FOUND) + + +class UnauthorizedError(AppError): + """ + 未授权错误 + """ + def __init__(self, detail: str = "未授权"): + super().__init__( + detail=detail, + status_code=status.HTTP_401_UNAUTHORIZED, + headers={"WWW-Authenticate": "Bearer"} + ) + + +class ForbiddenError(AppError): + """ + 禁止访问错误 + """ + def __init__(self, detail: str = "禁止访问"): + super().__init__(detail=detail, status_code=status.HTTP_403_FORBIDDEN) + + +class BadRequestError(AppError): + """ + 请求参数错误 + """ + def __init__(self, detail: str = "请求参数错误"): + super().__init__(detail=detail, status_code=status.HTTP_400_BAD_REQUEST) + + +class ConflictError(AppError): + """ + 资源冲突错误 + """ + def __init__(self, detail: str = "资源冲突"): + super().__init__(detail=detail, status_code=status.HTTP_409_CONFLICT) \ No newline at end of file diff --git a/fastapi-backend/app/utils/response.py b/fastapi-backend/app/utils/response.py new file mode 100644 index 0000000..9d33794 --- /dev/null +++ b/fastapi-backend/app/utils/response.py @@ -0,0 +1,43 @@ +from typing import Any, Dict, Optional + + +def success_response( + data: Any = None, + message: Optional[str] = None, + code: int = 200 +) -> Dict[str, Any]: + """ + 标准成功响应格式 + """ + response = { + "success": True, + "code": code + } + + if data is not None: + response["data"] = data + + if message: + response["message"] = message + + return response + + +def error_response( + message: str, + code: int = 400, + data: Any = None +) -> Dict[str, Any]: + """ + 标准错误响应格式 + """ + response = { + "success": False, + "code": code, + "message": message + } + + if data is not None: + response["data"] = data + + return response \ No newline at end of file diff --git a/fastapi-backend/main.py b/fastapi-backend/main.py new file mode 100644 index 0000000..cbf0984 --- /dev/null +++ b/fastapi-backend/main.py @@ -0,0 +1,15 @@ +import uvicorn +from app.core.config import settings +from app.api.api import app as application + +# 导出应用实例 +app = application + +if __name__ == "__main__": + uvicorn.run( + "app.api.api:app", + host=settings.HOST, + port=settings.PORT, + reload=settings.DEBUG, + log_level="info" + ) \ No newline at end of file diff --git a/fastapi-backend/migrations/env.py b/fastapi-backend/migrations/env.py new file mode 100644 index 0000000..064d073 --- /dev/null +++ b/fastapi-backend/migrations/env.py @@ -0,0 +1,74 @@ +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool + +from alembic import context + +# 导入模型 +from app.models.user import Base + +# 导入配置 +from app.core.config import settings + +# 这是Alembic Config对象,它提供对.ini文件中值的访问 +config = context.config + +# 解释配置文件并设置日志记录器 +if config.config_file_name is not None: + fileConfig(config.config_file_name) + +# 添加你的模型元数据对象 +target_metadata = Base.metadata + +# 其他值来自config,可以通过以下方式定义: +# my_important_option = config.get_main_option("my_important_option") +# ... 等等。 + + +def run_migrations_offline() -> None: + """在'offline'模式下运行迁移。 + + 这配置了上下文,只需要一个URL,并且不要求引擎可用。 + 跳过引擎创建,甚至不需要DBAPI可用。 + + 调用context.execute()来执行迁移。 + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, + target_metadata=target_metadata, + literal_binds=True, + dialect_opts={"paramstyle": "named"}, + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online() -> None: + """在'online'模式下运行迁移。 + + 在这种情况下,我们创建了一个Engine并将其与迁移上下文关联。 + + """ + connectable = engine_from_config( + config.get_section(config.config_ini_section, {}), + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() \ No newline at end of file diff --git a/fastapi-backend/requirements.txt b/fastapi-backend/requirements.txt new file mode 100644 index 0000000..86c38d8 --- /dev/null +++ b/fastapi-backend/requirements.txt @@ -0,0 +1,16 @@ +fastapi==0.110.0 +uvicorn==0.27.1 +pydantic==2.6.1 +pydantic-settings==2.1.0 +sqlalchemy==2.0.27 +pymysql==1.1.0 +cryptography==42.0.2 +python-jose==3.3.0 +passlib==1.7.4 +python-multipart==0.0.9 +email-validator==2.1.0 +python-dotenv==1.0.1 +alembic==1.13.1 +pytest==7.4.3 +httpx==0.26.0 +bcrypt==4.1.2 \ No newline at end of file