做后台管理系统开发的朋友,对若伊框架应该都不陌生。这套基于Spring Boot的快速开发平台,在中小型项目和企业内部系统里出镜率极高,前一段时间我连续帮两个团队处理过部署问题,一个直接用Tomcat,一个上了Nginx做前置代理,踩了不少坑,也把整套链路摸清了。今天专门聊聊若伊框架的部署,重点就是两个方向:单Tomcat怎么搞,Tomcat+Nginx怎么搞,各自的配置要点、常见报错、选型逻辑,一次讲透。
先交代一下背景:我这里说的若伊框架,以最常见的RuoYi-Vue单体版本为例,技术栈是Spring Boot 2.x + Vue + MySQL + Redis。部署环境我默认是Linux服务器,Windows上思路完全一样,命令换成对应的脚本就行。适合谁看?刚接触若伊框架、不知道怎么把项目从开发环境搬到服务器的同学,以及正在纠结要不要上Nginx、或者已经上了Nginx但遇到404/502问题的朋友。这篇文章不是教科书,就是我实战过程的一次完整复盘。
1. 部署前先搞懂:若伊框架到底该用什么方式跑起来
1.1 若伊框架的技术底座与两种部署形态
若伊框架的核心是Spring Boot,而Spring Boot自带内嵌Tomcat。这意味着一个打包好的Jar包,直接java -jar就能跑,根本不需要额外装Tomcat。那为什么市面上还会大量存在“把war包丢进外置Tomcat”的部署方式?因为很多公司的运维体系是围绕Tomcat建的:统一的应用目录、统一的启动脚本、统一的端口管理,甚至日志收集、监控报警都基于Tomcat的目录结构。在这种情况下,让开发把项目打成war包,塞进既有Tomcat里,是运维成本最低的选择。
所以你会看到两种主流部署形态:
- Jar包方式:
nohup java -jar ruoyi-admin.jar --server.port=8080 &,适合个人学习、Docker容器、纯内网小规模部署。 - War包方式:把Spring Boot项目的打包方式改成war,放到Tomcat的webapps目录,由外置Tomcat启动,适合既有运维体系、需要多应用共存的场景。
而Tomcat+Nginx的组合,本质上是在war包方式之上再加一层前置服务,负责静态资源托管、反向代理、负载均衡、HTTPS终结。本文的核心脉络,就是先把war包方式的Tomcat部署讲清楚,再叠加Nginx,讲生产环境的完整架构。
1.2 选Tomcat还是直接Java -jar?场景决定方案
很多刚接触若伊框架的人会问:Spring Boot都内嵌Tomcat了,为什么还要单独装一个?我的回答是:单独装Tomcat,不是为了“多此一举”,而是为了“可控”。直接Java -jar虽然简单,但应用进程和前端的静态资源全部挤在一个端口上,上传文件路径、静态资源路径、接口路径全混在一起,线上出了问题不好定位。
举一个很实际的例子:若伊框架的前端是Vue打包后的dist目录,如果直接扔进Jar包里访问,Tomcat要同时处理接口请求和静态文件读取。一旦访问量上来,IO会成为瓶颈。而引入Nginx之后,静态资源交给Nginx处理,Tomcat专心跑Java接口,两边各司其职,这就是生产环境推荐Tomcat+Nginx的根本原因。
所以我的建议很直接:个人学习、测试环境,用Java -jar跑最快;公司服务器、正式项目,优先考虑Tomcat+war包,再在前面挂Nginx。
2. 环境准备:从零装好JDK、Maven、Tomcat与Nginx
2.1 JDK版本与Maven构建环境
若伊框架RuoYi-Vue对应的是Spring Boot 2.x,官方要求JDK 1.8,实际用JDK 8或JDK 11都能跑。但这里有个隐藏雷区:Tomcat的版本兼容性。Tomcat 9及以下用的是javax.servlet命名空间,Tomcat 10开始换成了jakarta.servlet。而若伊框架老版本里的Servlet依赖通通是javax,所以如果装了Tomcat 10,war包部署后大概率直接启动失败,报各种NoClassDefFoundError。结论:部署若伊框架,老老实实用Tomcat 8.5或9.0。
环境变量方面,Linux下建议把Java和Tomcat的路径写进/etc/profile:
export JAVA_HOME=/usr/local/jdk1.8.0_202 export CATALINA_HOME=/usr/local/tomcat9 export PATH=$JAVA_HOME/bin:$CATALINA_HOME/bin:$PATHMaven版本建议3.6以上。构建前检查一下settings.xml,把中央仓库换成阿里云镜像,否则拉Spring Boot依赖的时候,那个速度会让人怀疑人生。
<mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> </mirror>2.2 Tomcat安装及配置教程:从下载到启动
Tomcat的安装本身不复杂,难的是理解它的目录结构。下载地址是tomcat.apache.org,注意选择Core里的tar.gz或zip包,Windows直接解压,Linux解压到指定的/usr/local/tomcat9目录即可。
启动关闭的命令:
/usr/local/tomcat9/bin/startup.sh /usr/local/tomcat9/bin/shutdown.shWindows对应的是startup.bat和shutdown.bat。启动后怎么判断是否成功?先看日志:
tail -f /usr/local/tomcat9/logs/catalina.out出现Server startup in [xxx] milliseconds基本就稳了,再访问http://localhost:8080,能看到Tomcat默认首页说明安装成功。
2.3 Nginx下载与安装:Windows和Linux两条路线
Nginx的高频玩法是反向代理和静态资源托管。Windows下直接到nginx.org下载Windows版zip,解压后结构很简洁,nginx.exe双击就运行,默认监听80端口。Linux下推荐用系统包管理器,比如AlmaLinux 9:
dnf install -y nginx systemctl enable nginx --now装完先不急着配置,用nginx -t测试配置语法,通过后再systemctl reload nginx重载。
这里要特别强调:Nginx的配置文件在/etc/nginx/conf.d/下,强烈建议为若伊框架单独建一个配置文件,比如ruoyi.conf,不要全部堆在nginx.conf里,否则后期维护非常痛苦。我见过太多人把所有server块全写进主配置文件,改一个站点要重启整个Nginx,风险极高。
3. 若伊框架打包实操:从源码到可部署产物
3.1 源码结构解析与打包命令
若伊框架的源码结构很清晰,核心模块包括:ruoyi-admin(后台管理入口)、ruoyi-framework(框架核心)、ruoyi-system(系统管理模块)、ruoyi-common(公共模块)、ruoyi-quartz(定时任务)、ruoyi-generator(代码生成)。打包时通常只关注顶层父工程和ruoyi-admin模块,因为admin是最后的启动入口。
命令行进入项目根目录:
mvn clean package -Dmaven.test.skip=true构建完成后,ruoyi-admin/target目录下会生成可部署产物。默认情况下若伊框架是Jar包,如果要部署到外置Tomcat,必须做两件事:
第一,在ruoyi-admin/pom.xml里,把打包方式从jar改成war:
<packaging>war</packaging>第二,修改启动类RuoYiApplication.java,让它继承SpringBootServletInitializer并重写configure方法:
@SpringBootApplication public class RuoYiApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(RuoYiApplication.class); } }这两个改动缺一不可。我自己第一次改的时候只改了pom.xml,结果启动类还是原来的写法,war包虽然在Tomcat里解压了,但应用始终没有起来,日志里也没有任何明显报错,最后排查半天才反应过来,是启动类没有适配Servlet容器环境。
3.2 数据库初始化与Redis配置
若伊框架部署前必须初始化数据库。源码的sql目录下有两个文件:一个是以ry_开头的系统表初始化脚本,比如ry_2021xxxx.sql;另一个是quartz.sql,负责定时任务所需的表。用命令行导入MySQL:
mysql -u root -p create database ry default character set utf8mb4; use ry; source /path/to/sql/ry_2021xxxx.sql; source /path/to/sql/quartz.sql;数据库编码强烈建议统一utf8mb4,不只是因为表情符号,更关键的是中文排序和存储兼容性。等数据库建好,再打开ruoyi-admin/src/main/resources/application-druid.yml,确认连接串:
url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8 username: root password: your_passwordRedis的配置在application.yml里:
redis: host: localhost port: 6379 password:这里有个部署新手必踩的坑:Tomcat起来了,前端页面也打开了,但验证码出不来,点登录一直转圈。十有八九是Redis没启动或者密码不对。若伊框架的验证码、会话缓存全都要用Redis,Redis挂了,系统就瘫痪。
3.3 修改application.yml中的关键参数
打包前还有一个容易被忽略的配置项:文件上传路径。若伊框架上传的头像、图片等文件,默认存放位置是当前项目目录下的profile文件夹。开发环境无所谓,生产环境如果直接跑,重启或升级war包时,上传文件很可能丢失。所以一定要改成服务器上的绝对路径:
ruoyi: profile: /data/ruoyi/upload另外,启动端口server.port在war包部署到外置Tomcat的环境下会失效,因为对外端口由Tomcat决定。很多人改完application.yml里的8081端口,发现Tomcat还是8080,还以为没生效,其实是理解错了:war包部署模式下,内嵌容器的配置被外置Tomcat覆盖了,这个逻辑要提前搞清楚。
4. Tomcat部署若伊框架的完整过程
4.1 war包部署步骤
打包成功后,ruoyi-admin/target/ruoyi-admin.war就是我们要的产物。把它拷贝到Tomcat的webapps目录下,启动Tomcat后,它会自动解压出一个同名目录。
这一步的默认访问路径是:
http://服务器IP:8080/ruoyi-admin/注意路径里必须带应用上下文名称ruoyi-admin。如果你希望直接通过根路径访问,也就是http://服务器IP:8080/直达登录页,有几种做法:
- 把war包重命名为
ROOT.war再放入webapps,这是最省事的方式。 - 修改
server.xml里的Host配置,添加Context,指定docBase为解压后的目录。
实际项目里,我一般会把war包改成ROOT.war,这样路径最短,Nginx反向代理配置也简单很多。
4.2 JVM内存与Tomcat启动参数调优
默认Tomcat的JVM参数非常保守,启动内存只有256M左右。若伊框架包含定时任务、代码生成、接口服务,跑一段时间后就可能内存不足,严重的直接OOM崩溃。部署时建议调整JVM参数。
Linux下在Tomcat的bin目录新建一个setenv.sh文件:
export JAVA_OPTS="-Xms1024m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"Tomcat启动时如果检测到setenv.sh,会自动读取里面的JAVA_OPTS,无需修改启动脚本。这个参数怎么定?建议根据服务器内存来:4G内存的机器,-Xms和-Xmx可以设2048M;8G内存的机器,设4096M。JVM参数设置过大反而会造成浪费,太小又扛不住并发,这个度要结合你实际部署的服务器配置来调。
4.3 启动日志与访问验证
部署后的验证流程很重要。启动Tomcat后,不要急着打开浏览器,先看日志:
tail -f /usr/local/tomcat9/logs/catalina.out看到Deployment of web application archive [webapps/ROOT.war] has finished,说明war包部署完成。然后访问http://localhost:8080/,页面能出现若伊框架的登录页,再用默认账号admin / admin123登录。
如果登录时验证码能出来、密码也对,但一直卡在登录请求上,那就检查Redis连接。如果页面能打开但样式错乱或者接口404,那就是打包时前端静态资源没打进war包,或者Nginx路径配置有问题,这一块放到后面单独说。
5. Tomcat+Nginx组合部署:生产环境的标配
5.1 为什么生产环境要引入Nginx
Tomcat单独能跑,但离“生产可用”还差几步:第一,HTTPS证书的配置在Tomcat里虽然能做,但证书续期、多域名管理都比较笨重,Nginx处理证书要灵活得多;第二,若伊框架的前端是静态资源,由Nginx直接返回要比Tomcat处理快得多;第三,一旦未来需要扩容,Nginx可以轻松配置多台Tomcat做负载均衡,而Tomcat本身做负载均衡要引入额外组件。
所以我的建议是:单机测试用Tomcat,正式环境必须上Nginx。这不是炫技,而是让每个组件做自己最擅长的事。
5.2 Nginx详细配置教程:server与location的规划
一份可以套用的Nginx配置,放在/etc/nginx/conf.d/ruoyi.conf:
server { listen 80; server_name yourdomain.com; # 前端静态资源 location / { root /data/ruoyi/dist; index index.html; try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /prod-api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # 上传文件访问 location /profile/ { proxy_pass http://127.0.0.1:8080/profile/; } }逐行解释一下:location /匹配前端页面请求,root指向Vue打包后的目录,try_files这一行很关键,它保证Vue Router在history模式下,刷新非首页路径不会出现404。location /prod-api/是若伊框架默认的接口前缀,前端所有Ajax请求都带这个前缀,这里通过proxy_pass转发到Tomcat,且末尾的/会把/prod-api/前缀替换掉,后端Controller直接按/路径接收请求,不用改路由。
这里有个细节非常容易出错:proxy_pass http://127.0.0.1:8080/;末尾的斜杠,和proxy_pass http://127.0.0.1:8080;不带斜杠,效果完全不一样。带斜杠表示把/prod-api/xxx转发成/xxx,不带斜杠会保留完整路径。项目里一定要根据你后端实际的路由来决定,否则就是404和接口地址对不上的问题。
5.3 静态资源与接口分离后的路径问题
引入Nginx后,常见的路径问题有三个。
第一个是前端请求接口的baseURL。Vue项目里,环境变量文件.env.production中会配置:
VUE_APP_BASE_API = '/prod-api'这个前缀必须和Nginx里location /prod-api/对应上,否则前端请求发出去根本到不了后端。
第二个是上传文件的访问路径。若伊框架上传图片后,前端访问路径通常是/profile/upload/xxx.jpg,所以Nginx里需要额外加一条location /profile/转发到Tomcat。如果连这层图片访问都想省掉Tomcat的IO,可以直接用alias指向本地磁盘目录:
location /profile/ { alias /data/ruoyi/upload/; }这样图片由Nginx直接返回文件,不再经过Java进程,性能最好。
第三个是跨域。如果开发环境是localhost:8080前端直连后端,生产环境通过Nginx同域部署,跨域问题通常自动消失。但如果你用了独立域名做API服务,比如api.yourdomain.com,那就需要在Nginx或后端单独配CORS,这个要提前设计好。
6. 常见问题与排查技巧实录
6.1 Tomcat启动出现异常的处理
部署中最常见的问题是Tomcat版本不兼容。Tomcat 10的用户会发现war包无法启动,日志里报java.lang.NoClassDefFoundError: javax/servlet/...,这就是因为Spring Boot 2.x若伊框架用的是javax命名空间,Tomcat 10换成了jakarta,彻底不兼容。解决办法很简单:降级到Tomcat 9。
第二个常见问题是端口被占用。Linux下先查端口:
netstat -tlnp | grep 8080 lsof -i:8080找到占用进程后,要么kill,要么修改Tomcat的server.xml里Connector的port。Windows下用netstat -ano | findstr 8080查PID,再到任务管理器里结束进程。
6.2 中文乱码、数据库连接失败与端口占用
中文乱码分两类。第一类是Tomcat日志乱码,Windows下尤为普遍。打开conf/logging.properties,把java.util.logging.ConsoleHandler.encoding改成UTF-8,再重启Tomcat。第二类是数据库中文乱码,通常有两种原因:一种是连接串没加characterEncoding=utf8,另一种是数据库表本身就是latin1编码。解决方式是把库表和连接串都统一成utf8mb4。
数据库连接失败是另一个高频问题。报错一般类似Access denied for user 'root'@'localhost'或Communications link failure。前者是账号密码或权限问题,后者是连接地址不对,或者MySQL服务没启动。建议先用命令行工具在服务器本机试一下:
mysql -u root -p能连上数据库,再看应用配置;连不上,就先去解决MySQL本身的问题。这个方法能帮你快速缩小排查范围。
6.3 反向代理后的404与502排查
Nginx+Tomcat部署后,浏览器打开页面正常,但一调接口就404,这基本是proxy_pass路径拼接的问题。想快速验证,可以用curl模拟:
curl http://127.0.0.1:8080/system/user/list如果后端直接访问正常,而通过Nginx访问404,那一定是proxy_pass末尾的斜杠问题。记住一个口诀:location带前缀、proxy_pass带斜杠,去掉前缀;不带斜杠,保留前缀。
502 Bad Gateway则是反向代理中最常见的错误。502表示Nginx能连到上游,但上游没响应,通常原因包括:Tomcat没启动、Tomcat启动失败、Tomcat端口写错。排查顺序是:先看Tomcat进程是否存在,再curl后端端口是否通,最后看Nginx配置文件里的地址和端口是否和Tomcat一致。
6.4 关于Tomcat与Nginx配合的面试考点
顺带说一句,很多读者是在准备面试时搜到这篇博文的。围绕Tomcat和Nginx,面试官喜欢问的无非是:
- 反向代理和正向代理的区别。
- Nginx负载均衡的几种策略:轮询、权重、ip_hash、fair。
- Tomcat的默认端口为什么是8080,Connector运行模式有哪些。
- Nginx如何处理高并发,为什么能比Tomcat抗压。
这些问题的答案网上都有,但真正能讲出细节的人不多。我建议你在本地完整部署一遍Tomcat+Nginx环境,亲手配置一次反向代理,感受一下proxy_pass两种写法导致的路径差异。面试时能把这个细节讲清楚,比背一百道八股文都管用。
7. 部署方案对比与影响范围分析
7.1 三种部署方式的成本与适用场景
最后用一张表格梳理一下几种部署方式的差异:
| 部署方式 | 上手难度 | 启动速度 | 静态资源性能 | 多实例扩展 | HTTPS支持 | 适用场景 |
|---|---|---|---|---|---|---|
| Java -jar 直接跑 | 最低 | 快 | 一般 | 需自行处理 | 需自行配置 | 学习、测试、Docker |
| 单Tomcat部署war包 | 较低 | 中 | 一般 | 较难 | 配置麻烦 | 小规模内网系统 |
| Tomcat+Nginx | 中等 | 中 | 好 | 方便 | 灵活 | 正式生产环境 |
从成本角度看,单Tomcat的维护成本最低,但对将来扩展不友好;Tomcat+Nginx前期多了一层配置,但换来的是更清晰的架构、更灵活的静态资源处理、更平滑的扩容能力。如果项目上线后有明确的用户增长预期,我建议从一开始就上Nginx,省得后面再改架构。
7.2 对运维和开发的影响范围
部署方案的选型,直接影响的不只是服务器,还有前后端团队的协作方式。上了Nginx之后,前端发布只需要把新的dist目录替换到Nginx的root路径,整个发布过程可以不重启Tomcat;后端发布则只需要替换war包,配合Tomcat的优雅停机,能做到很短的窗口期。这对发布流程的改善非常明显。
另外,上传文件的存储位置如果规划到Nginx的alias目录,备份、迁移、磁盘扩容都会变得简单。记录访问日志时,Nginx的access.log可以单独记录静态资源请求和接口请求,做安全审计、访问分析时数据也更干净。所以,别小看一个Nginx,它对整个项目的影响范围比想象中大得多。
如果以后再遇到部署问题,我个人的建议是:先理清架构,再动手配置,最后用日志验证。Java -jar适合跑通流程,Tomcat适合传统运维,Nginx+Tomcat适合正式生产。没有绝对的正确答案,只有最适合当前环境的选择。