全栈项目部署实战:从零到上线的完整指南

前言

本文记录了一个完整的全栈项目(Spring Boot + React)从本地开发到生产环境部署的全过程,包括遇到的所有问题及解决方案。项目最终部署在 CentOS 7 服务器上,通过 IP 地址直接访问。

项目技术栈:

  • 后端:Java 17 + Spring Boot 3.1.5 + Spring Security + JWT
  • 前端:React 18 + Ant Design + Vite
  • 服务器:CentOS 7 + Nginx + 宝塔面板

最终效果:

  • 访问地址: http://服务器IP
  • 前端和后端分离部署
  • Nginx 反向代理实现统一访问

一、服务器环境准备

1.1 服务器基本信息

操作系统:CentOS 7.9
管理工具:宝塔面板
服务器 IP:101.32.242.75(示例)

1.2 安装 Java 17

CentOS 7 默认的 Java 版本太低,需要手动安装 OpenJDK 17。

bash

# 1. 下载 OpenJDK 17
cd /opt
wget https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-x64_bin.tar.gz

# 2. 解压
tar -zxvf openjdk-17.0.2_linux-x64_bin.tar.gz

# 3. 配置环境变量
cat >> /etc/profile << 'EOF'
export JAVA_HOME=/opt/jdk-17.0.2
export PATH=$JAVA_HOME/bin:$PATH
EOF

# 4. 使配置生效
source /etc/profile

# 5. 验证安装
java -version
# 输出:openjdk version "17.0.2" 2022-01-18

⚠️ 常见问题: 文件名不匹配

解决方案:下载后先用 ls 查看实际文件名,再解压。

bash

ls -lh /opt/*.tar.gz
tar -zxvf openjdk-17.0.2_linux-x64_bin.tar.gz  # 使用实际文件名

1.3 安装 Maven

bash

# 1. 下载 Maven 3.9.9
cd /opt
wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz

# 2. 解压
tar -zxvf apache-maven-3.9.9-bin.tar.gz

# 3. 配置环境变量
cat >> /etc/profile << 'EOF'
export MAVEN_HOME=/opt/apache-maven-3.9.9
export PATH=$MAVEN_HOME/bin:$PATH
EOF

# 4. 使配置生效
source /etc/profile

# 5. 验证安装
mvn -version

优化建议: 配置国内镜像加速依赖下载

bash

cat > ~/.m2/settings.xml << 'EOF'
<settings>
  <mirrors>
    <mirror>
      <id>aliyun</id>
      <mirrorOf>central</mirrorOf>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
  </mirrors>
</settings>
EOF

1.4 安装 Nginx

通过宝塔面板安装 Nginx:

  1. 登录宝塔面板: http://服务器IP:8888
  2. 软件商店 → 搜索 Nginx → 安装

或者命令行安装:

bash

yum install -y nginx
systemctl start nginx
systemctl enable nginx

二、后端部署

2.1 上传代码到服务器

bash

# 在服务器上创建项目目录
mkdir -p /home/restaurant-reservation

# 从本地上传后端代码
cd ~/Desktop/restaurant-reservation
scp -r backend root@服务器IP:/home/restaurant-reservation/

2.2 编译后端项目

bash

# SSH 连接到服务器
ssh root@服务器IP

# 进入后端目录
cd /home/restaurant-reservation/backend

# 编译项目(跳过测试)
mvn clean package -DskipTests

# 编译完成后检查 jar 文件
ls -lh target/*.jar

输出示例:

-rw-r--r-- 1 root root 50M Dec 10 18:00 reservation-system-1.0.0.jar

⚠️ 常见问题: 编译超时或依赖下载失败

解决方案: 确保已配置 Maven 阿里云镜像(见 1.3 节)

三、前端部署

3.1 为什么要在本地构建?

CentOS 7 的 glibc 版本过低,无法很好地支持最新的 Node.js 和 Vite,在服务器上构建前端会遇到以下错误:

bash

error during build:
TypeError: crypto$2.getRandomValues is not a function

最佳实践: 在本地 Mac/Windows 上构建,然后上传到服务器。

3.2 本地构建前端

bash

# 在本地进入前端目录
cd ~/Desktop/restaurant-reservation/frontend

# 安装依赖(首次)
npm install

# 构建生产版本
npm run build

# 构建成功后,dist 目录包含所有静态文件
ls -lh dist/

构建输出示例:

dist/index.html                     0.58 kB │ gzip:   0.44 kB
dist/assets/index-BOrl-zwt.css      0.27 kB │ gzip:   0.22 kB
dist/assets/index-DlJaEm6z.js   2,717.96 kB │ gzip: 834.43 kB
✓ built in 13.07s

3.3 上传到服务器

bash

# 上传构建好的 dist 目录
scp -r dist root@服务器IP:/home/restaurant-reservation/frontend/

# 输入密码,等待上传完成

💡 提示: 输入密码时不会显示任何字符,这是正常的。

四、配置 Nginx

4.1 创建 Nginx 配置文件

bash

# SSH 到服务器
ssh root@服务器IP

# 创建配置文件
cat > /www/server/panel/vhost/nginx/restaurant.conf << 'EOF'
server {
    listen 80;
    server_name 服务器IP;

    # 前端静态文件
    root /home/restaurant-reservation/frontend/dist;
    index index.html;

    # 前端路由(SPA)
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 后端 API 代理
    location /api/ {
        proxy_pass http://127.0.0.1:8080/api/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
EOF

配置说明:

  • listen 80 :监听 80 端口(HTTP)
  • root :前端静态文件目录
  • location / :处理前端路由,所有路径都返回 index.html(SPA 必需)
  • location /api/ :反向代理后端 API,前端通过 /api/xxx 访问后端

4.2 测试并重启 Nginx

bash

# 测试配置文件语法
nginx -t
# 输出:nginx: configuration file test is successful

# 重启 Nginx
/etc/init.d/nginx restart

⚠️ 常见问题: nginx: [error] invalid PID number

解决方案: 使用宝塔提供的启动脚本,不要用 nginx -s reload

bash

/etc/init.d/nginx restart

五、启动服务

5.1 创建一键启动脚本

bash

cat > /home/restaurant-reservation/start-server.sh << 'EOF'
#!/bin/bash

echo "=========================================="
echo "启动餐厅预订系统"
echo "=========================================="

# 设置 Java 17
export JAVA_HOME=/opt/jdk-17.0.2
export PATH=$JAVA_HOME/bin:$PATH

# 重启 Nginx
echo "1. 重启 Nginx..."
/etc/init.d/nginx restart
sleep 2

# 停止旧的后端进程
echo "2. 停止旧的后端进程..."
pkill -f 'reservation-system'
sleep 2

# 启动后端服务
echo "3. 启动后端服务..."
cd /home/restaurant-reservation
nohup java -jar backend/target/reservation-system-1.0.0.jar > backend.log 2>&1 &
echo "后端进程 PID: $!"

# 等待启动
echo "4. 等待后端启动(15秒)..."
sleep 15

# 检查服务状态
echo "5. 检查服务状态..."
ps aux | grep nginx | grep -v grep | head -n 2
ps aux | grep java | grep reservation | grep -v grep

echo ""
echo "=========================================="
echo "✅ 系统启动完成!"
echo "=========================================="
echo "访问地址: http://服务器IP"
echo "查看日志: tail -f /home/restaurant-reservation/backend.log"
EOF

# 赋予执行权限
chmod +x /home/restaurant-reservation/start-server.sh

5.2 启动系统

bash

/home/restaurant-reservation/start-server.sh

输出示例:

==========================================
启动餐厅预订系统
==========================================

使用 Java 版本:
openjdk version "17.0.2" 2022-01-18

==========================================
1. 重启 Nginx...
==========================================
Starting nginx...  done

==========================================
2. 停止旧的后端进程...
==========================================

==========================================
3. 启动后端服务...
==========================================
后端进程 PID: 25544

==========================================
4. 等待后端启动(15秒)...
==========================================

==========================================
5. 检查服务状态...
==========================================

Nginx 进程:
root     25519  0.0  0.2 143312  4804 ?        Ss   18:16   0:00 nginx: master process

后端进程:
root     25544  132 13.8 3229216 282728 pts/1  Sl+  18:16   0:19 java -jar backend/target/reservation-system-1.0.0.jar

==========================================
✅ 系统启动完成!
==========================================
访问地址: http://服务器IP
查看日志: tail -f /home/restaurant-reservation/backend.log

六、验证部署

6.1 测试前端

bash

curl -I http://localhost:80

期望输出:

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html

6.2 测试后端 API

bash

# 测试登录接口
curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"user1","password":"123456"}'

期望输出:

json

{
  "token": "eyJhbGciOiJIUzI1NiJ9...",
  "type": "Bearer",
  "user": {
    "id": 1,
    "username": "user1",
    "role": "USER"
  }
}

6.3 浏览器访问

打开浏览器,访问: http://服务器IP

如果能看到登录页面,说明部署成功!

七、实战中遇到的问题及解决方案

问题 1:找不到 jar 文件

错误信息:

Error: Unable to access jarfile backend/target/reservation-system-1.0-SNAPSHOT.jar

原因: 启动脚本中的 jar 文件名与实际编译出的文件名不一致。

解决方案:

bash

# 1. 查找实际的 jar 文件
find /home/restaurant-reservation -name "*.jar" -type f

# 2. 修改启动脚本中的文件名,使用实际文件名
# 例如:reservation-system-1.0.0.jar 而不是 reservation-system-1.0-SNAPSHOT.jar

问题 2:前端构建失败

错误信息:

error during build:
TypeError: crypto$2.getRandomValues is not a function

原因: CentOS 7 的 glibc 版本过低,不支持新版 Node.js 和 Vite。

解决方案: 在本地构建,然后上传(见第三章)。

问题 3:API 返回 403 Forbidden

测试命令:

bash

curl http://localhost:8080/api/restaurants

返回:

json

{"timestamp":"2025-12-10T10:16:24.638+00:00","status":403,"error":"Forbidden","path":"/api/restaurants"}

说明: 这是正常现象!该接口需要 JWT 认证。公开接口(如登录接口)不会返回 403。

问题 4:Nginx PID 错误

错误信息:

nginx: [error] invalid PID number "" in "/www/server/nginx/logs/nginx.pid"

解决方案:

bash

# 不要使用 nginx -s reload
# 使用宝塔提供的启动脚本
/etc/init.d/nginx restart

问题 5:scp 上传失败

错误信息:

Permission denied, please try again.
ssh_dispatch_run_fatal: Connection to 服务器IP port 22: Broken pipe

解决方案:

  1. 确认密码正确(输入时不显示任何字符)
  2. 如果多次失败,使用宝塔面板的文件管理功能上传
  3. 访问宝塔面板 → 文件 → 上传

八、运维管理

8.1 常用命令

bash

# 启动系统
/home/restaurant-reservation/start-server.sh

# 停止后端
pkill -f 'reservation-system'

# 重启 Nginx
/etc/init.d/nginx restart

# 查看后端日志
tail -f /home/restaurant-reservation/backend.log

# 查看最后 100 行日志
tail -n 100 /home/restaurant-reservation/backend.log

# 查看进程状态
ps aux | grep java
ps aux | grep nginx

# 查看端口占用
netstat -tlnp | grep 8080
netstat -tlnp | grep 80

8.2 更新部署

更新后端:

bash

# 1. 上传新代码
scp -r backend root@服务器IP:/home/restaurant-reservation/

# 2. SSH 到服务器
ssh root@服务器IP

# 3. 重新编译
cd /home/restaurant-reservation/backend
mvn clean package -DskipTests

# 4. 重启服务
/home/restaurant-reservation/start-server.sh

更新前端:

bash

# 1. 本地构建
cd ~/Desktop/restaurant-reservation/frontend
npm run build

# 2. 上传到服务器
scp -r dist root@服务器IP:/home/restaurant-reservation/frontend/

# 3. 重启 Nginx
ssh root@服务器IP
/etc/init.d/nginx restart

九、架构说明

9.1 请求流程

用户浏览器
    ↓
http://服务器IP
    ↓
Nginx (端口 80)
    ├─ / → 前端静态文件 (React)
    └─ /api/ → 反向代理到 http://127.0.0.1:8080/api/
           ↓
       Spring Boot 后端 (端口 8080)
           ↓
       H2 内存数据库

9.2 目录结构

/home/restaurant-reservation/
├── backend/
│   ├── src/
│   ├── pom.xml
│   └── target/
│       └── reservation-system-1.0.0.jar
├── frontend/
│   └── dist/
│       ├── index.html
│       └── assets/
├── backend.log
└── start-server.sh

十、总结

10.1 关键点回顾

  1. 环境准备是基础
    • Java 17(不能用默认的 Java 8)
    • Maven 3.9+
    • Nginx
  2. 前端构建要灵活
    • 服务器环境受限时,本地构建是最优解
    • dist 目录是纯静态文件,可直接上传使用
  3. Nginx 配置是核心
    • 前端静态文件服务
    • 后端 API 反向代理
    • SPA 路由支持(try_files)
  4. 自动化脚本很重要
    • 减少手动操作
    • 避免遗漏步骤
    • 提高部署效率
  5. 日志是排查问题的关键
    • 实时查看日志: tail -f backend.log
    • 搜索错误: grep -i "error" backend.log

10.2 优化建议

生产环境建议:

  1. 使用域名nginxserver_name yourdomain.com;
  2. 启用 HTTPSnginxlisten 443 ssl; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem;
  3. 使用 MySQL 替代 H2yamlspring: datasource: url: jdbc:mysql://localhost:3306/restaurant username: root password: your_password
  4. 配置防火墙bashfirewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload
  5. 设置进程守护
    • 使用 systemd 或 supervisor 管理后端进程
    • 进程意外退出时自动重启

10.3 经验总结

  1. 遇到问题不要慌,先查日志
  2. 文件名、路径要仔细核对
  3. 环境变量配置后要 source 生效
  4. 本地能跑通,服务器就能跑通(环境一致的前提下)
  5. 写好脚本,一键部署才是王道

附录:快速部署检查清单

□ 服务器准备
  □ Java 17 安装并配置环境变量
  □ Maven 安装并配置镜像
  □ Nginx 安装

□ 后端部署
  □ 代码上传到服务器
  □ mvn clean package -DskipTests
  □ 确认 jar 文件存在

□ 前端部署
  □ 本地 npm run build
  □ 上传 dist 目录到服务器

□ Nginx 配置
  □ 创建配置文件
  □ nginx -t 测试
  □ 重启 Nginx

□ 启动服务
  □ 创建启动脚本
  □ 执行启动脚本
  □ 检查进程是否运行

□ 验证
  □ 浏览器访问 IP
  □ 测试登录功能
  □ 查看后端日志

Leave a Comment

您的邮箱地址不会被公开。 必填项已用 * 标注