【无标题】

Java Web项目部署完整笔记:Windows单体/聚合项目 + 云服务器部署指南

整理了一下近期做Java Web项目部署的实操笔记,从最基础的Windows本地单体SSM项目,到多模块聚合项目,再到云服务器上线,把核心步骤和容易踩坑的地方都补全了,留作复盘也分享给大家。


一、Windows 环境:单体 SSM 项目部署

以经典的SSM项目为例,单体项目是最基础的部署形态,核心逻辑可以概括为:Maven打war包 → 放入Tomcat容器 → 启动验证访问

1. 先搞懂:Maven 打包的核心逻辑

Maven是我们打包的核心工具,先理清两个核心点:标准生命周期和打包产物结构。

(1)Maven 标准生命周期

执行打包命令时,Maven会按顺序执行以下阶段,前一个执行完成才会进入下一个:

  • clean:清理上一次打包生成的target目录
  • validate:校验项目结构是否正确、所有必要信息是否完整
  • compile:编译项目的源代码
  • test:运行项目中的单元测试
  • package:将编译后的代码打包成可分发的格式(Web项目对应war包)
  • verify:运行合规检查,确保包符合质量标准
  • install:将打好的包安装到本地仓库,供本地其他项目依赖使用
  • site:生成项目的站点文档
  • deploy:将最终的包部署到远程私服仓库

日常部署最常用的命令是 mvn clean install,可以一键完成清理、编译、测试、打包并安装到本地仓库。支撑这套流程的是Maven的三大核心:插件 (执行每个阶段的具体逻辑)、依赖项 (项目引入的第三方jar包)、仓库 (本地/中央/远程仓库,存放依赖和自建包)。

(2)打包后的 target 目录结构

执行完install后,项目根目录会生成target文件夹,里面是打包的全部产物:

  • classes:编译后的Java字节码文件和项目资源文件
  • generated-sources / generated-test-sources:自动生成的源码目录
  • test-classes:编译后的测试类文件
  • surefire-reports:单元测试执行结果报告
  • 项目名.war:最终用于部署的应用包,比如ssm.war

2. 部署到 Tomcat 完整步骤

  1. 找到本地Tomcat安装目录,进入webapps文件夹(这是Tomcat默认的应用部署目录)
  2. 把target目录下生成的ssm.war复制粘贴到webapps目录中
  3. 进入Tomcat的bin目录,双击startup.bat启动Tomcat服务
  4. 启动过程中Tomcat会自动解压war包,生成同名的项目文件夹
  5. 打开浏览器访问:http://localhost:8080/ssm(8080是Tomcat默认HTTP端口,ssm对应你的项目名)

💡 小提示:Tomcat默认端口是8080,如果启动失败大概率是端口被占用,可以去conf/server.xml里修改Connector的port值。


二、Windows 环境:聚合项目部署

聚合项目就是一个父工程下管理多个子模块,每个子模块可以独立打包成一个war包,对应不同的业务系统(比如后台管理端、文件服务、门户前端)。

1. 打包:和单体项目逻辑一致

在父工程根目录执行mvn clean install,Maven会按依赖顺序自动编译所有子模块,最终每个子模块的target目录下都会生成自己独立的war包,例如:

  • hami-console-1.0-SNAPSHOT.war(管理控制台端)
  • hami-file-1.0-SNAPSHOT.war(文件服务模块)
  • hami-portal-1.0-SNAPSHOT.war(用户门户端)

2. 重点:多项目共存的 Tomcat 配置

如果把多个war包都丢进同一个Tomcat的webapps、共用同一个端口,会出现访问路径冲突、资源竞争的问题。更稳妥的方案是在一个Tomcat里配置多个Service,每个Service对应一个项目、独占一个端口

配置文件位置:Tomcat安装目录/conf/server.xml

配置核心规则(踩坑总结)
  • 每个<Service>name属性必须全局唯一
  • 每个Service内的HTTP端口、AJP端口都不能和其他Service重复
  • 每个Service内的<Engine>name要和Service名称对应
  • <Context>docBase要和webapps下的war包名(或解压后的文件夹名)完全一致
完整配置示例
复制代码
<!-- 第一个项目:管理控制台端 -->
<Service name="Catalina1">
    <!-- HTTP端口:8085 -->
    <Connector port="8085" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URLEncoding="UTF-8"/>
    <!-- AJP端口:8010 -->
    <Connector port="8010" protocol="AJP/1.3" redirectPort="8443" secretRequired=""/>

    <Engine name="Catalina1" defaultHost="localhost">
        <Realm className="org.apache.catalina.realm.LockOutRealm">
            <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                   resourceName="UserDatabase"/>
        </Realm>

        <Host name="localhost"  appBase="webapps"
              unpackWARs="true" autoDeploy="true">
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                   prefix="localhost_access_log" suffix=".txt"
                   pattern="%h %l %u %t &quot;%r&quot; %s %b" />
            <!-- docBase对应war包名,path="/"表示直接用根路径访问 -->
            <Context docBase="hami-console-1.0-SNAPSHOT" path="/" reloadable="true"/>
        </Host>
    </Engine>
</Service>

<!-- 第二个项目:用户门户端 -->
<Service name="Catalina2">
    <Connector port="8082" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URLEncoding="UTF-8"/>
    <Connector port="8011" protocol="AJP/1.3" redirectPort="8443" secretRequired=""/>

    <Engine name="Catalina2" defaultHost="localhost">
        <Realm className="org.apache.catalina.realm.LockOutRealm">
            <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                   resourceName="UserDatabase"/>
        </Realm>

        <Host name="localhost"  appBase="webapps"
              unpackWARs="true" autoDeploy="true">
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                   prefix="localhost_access_log" suffix=".txt"
                   pattern="%h %l %u %t &quot;%r&quot; %s %b" />
            <Context docBase="hami-portal-1.0-SNAPSHOT.war" path="/" reloadable="true"/>
        </Host>
    </Engine>
</Service>

<!-- 第三个项目:文件服务模块 -->
<Service name="Catalina3">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URLEncoding="UTF-8"/>
    <Connector port="8012" protocol="AJP/1.3" redirectPort="8443" secretRequired=""/>

    <Engine name="Catalina3" defaultHost="localhost">
        <Realm className="org.apache.catalina.realm.LockOutRealm">
            <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
                   resourceName="UserDatabase"/>
        </Realm>

        <Host name="localhost"  appBase="webapps"
              unpackWARs="true" autoDeploy="true">
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                   prefix="localhost_access_log" suffix=".txt"
                   pattern="%h %l %u %t &quot;%r&quot; %s %b" />
            <Context docBase="hami-file-1.0-SNAPSHOT.war" path="/" reloadable="true"/>
        </Host>
    </Engine>
</Service>

配置完成后启动Tomcat,三个项目会同时启动,分别通过不同端口访问:

  • 管理控制台:http://localhost:8085
  • 用户门户端:http://localhost:8082
  • 文件服务:http://localhost:8080

💡 补充说明:URLEncoding="UTF-8"建议一定要加上,否则GET请求传中文会出现乱码;unpackWARs="true"表示启动时自动解压war包,autoDeploy="true"开启应用热部署能力。


三、云服务器部署:单体/聚合项目通用

把项目放到云服务器上运行,核心流程和Windows本地几乎一致,最大的区别是前置环境安装访问方式,还有几个非常容易忽略的网络配置坑。

1. 前置:服务器基础环境安装

先在云服务器上把基础环境装好,版本尽量和本地开发环境保持一致,避免兼容性问题:

  • JDK:推荐和本地同版本(比如JDK8),配置好JAVA_HOME环境变量
  • MySQL:安装对应版本的数据库,导入项目需要的库表和数据
  • Tomcat:和本地版本保持一致,上传解压即可使用

如果是Linux服务器,一般用tar.gz解压安装的方式,环境变量配置在/etc/profile中;Windows服务器操作就和本地完全一致。

2. 部署流程

  1. 把本地打好的war包,通过Xshell、FileZilla等工具上传到服务器Tomcat的webapps目录
  2. 如果是聚合项目,按照上面的方法修改服务器上的conf/server.xml,配置多Service多端口
  3. 修改项目内的配置:比如数据库连接地址,从localhost:3306改成服务器地址(推荐用内网IP)
  4. 启动Tomcat(Linux下执行bin/startup.sh,Windows下双击startup.bat

3. 访问方式

本地调试用的是localhost,服务器上就替换成服务器公网IP + 端口号 ,例如:

http://120.xx.xx.xx:8080/项目名

4. 最容易踩的坑:网络与权限

  1. 安全组端口放行:云服务器控制台的安全组规则里,一定要放开所有用到的端口(比如8080、8082、8085、3306等),否则浏览器完全访问不到
  2. 服务器防火墙:Linux的firewalld、iptables,Windows的系统防火墙,都要放行对应端口
  3. MySQL远程访问:如果需要远程连接服务器上的MySQL,需要开启对应用户的远程访问权限
  4. 路径兼容问题 :Linux的路径分隔符是/,Windows是\,项目里如果写死了文件路径,一定要改成适配Linux的格式

四、常见问题快速排查

  1. Tomcat启动闪退:大概率是JDK环境变量配置错误,或者端口被占用,去logs目录查看catalina日志可以精准定位
  2. 访问返回404:检查Context的docBase和path是否写错,war包是否正常解压完成
  3. 页面中文乱码 :server.xml的Connector节点加上URLEncoding="UTF-8",同时检查项目内的编码过滤器是否正常配置
  4. 数据库连接失败:核对连接地址、端口、账号密码,确认服务器MySQL是否允许远程访问,以及安全组3306端口是否放行

整体下来,部署的核心逻辑其实并不复杂,就是「打包 → 放入容器 → 调整配置 → 启动验证」,麻烦的大多是各种环境差异和配置细节,多踩两次坑自然就熟练了。

相关推荐
陈皮波比茶32 分钟前
java日志框架
java
典典分享指南37 分钟前
飞书 + 企业微信 + 微信文档多端协同实践指南
汇编·flask·intellij-idea·fastapi
thefool1122661 小时前
随机链表的复制
java
jvmind_dev1 小时前
SWT 堆外内存泄漏排查实录:一次 PNG 保存泄漏一张图,一行 g_free 治好
java·后端
CodeStats1 小时前
《源纹天书》第三百四十六章至第三百五十章:边界的扩张、跨宇宙通信的尝试、其他宇宙的回应、新网络的形成、宇宙网络的创始者!
java·源纹天书
古法安卓2 小时前
Android-显示流程
android·java·android studio
l1t2 小时前
DeepSeek总结的DuckDB 如何更快地运行递归 CTE
java·开发语言·数据库·mysql·duckdb
小手cool3 小时前
使用递归对数组进行反转操作
java·数据结构·算法
MetaLite3 小时前
SpringBoot分页接口怎么设计-pageSize不设上限会发生什么
java·spring boot·后端