Java Web War包详解:结构规范、Eclipse导出与Tomcat部署全解析

发布时间:2026/9/18 6:04:22
Java Web War包详解:结构规范、Eclipse导出与Tomcat部署全解析
1. 这不是“点几下就完事”的打包而是Java Web项目生命周期的关键交接点你有没有遇到过这样的场景在 Eclipse 里调试好一个 JSP 页面本地 Tomcat 跑得飞起表单提交、数据库查询、跳转逻辑全都没问题可一到同事的机器上或者部署到测试服务器页面直接 404控制台报ClassNotFoundException甚至连web.xml都没被识别——不是代码写错了是打包环节出了系统性偏差。这背后根本不是“Eclipse 导出 War 包”这个按钮按得对不对的问题而是你是否真正理解了 Java Web 应用的编译-组织-加载-运行四层契约关系。War 包不是压缩包它是 Java EE 规范定义的可部署单元Deployable Unit它强制要求目录结构、类路径、资源位置、描述符格式全部符合 Servlet 容器比如 Tomcat的预期。Eclipse 只是工具Tomcat 只是容器而 War 是它们之间唯一被认可的“通用语言”。我带过的十几个团队里80% 的部署失败都卡在 War 包结构不合规上WEB-INF/classes下少了一个log4j2.xmllib目录里多了一个开发用的junit.jarweb.xml的servlet-mapping路径和实际 JSP 文件名大小写不一致……这些细节在 IDE 里被自动掩盖但一旦脱离开发环境就会立刻暴露。所以这篇内容不是教你“怎么导出”而是带你亲手拆开 War 包的每一层看清META-INF/MANIFEST.MF里写了什么、WEB-INF/web.xml如何决定请求路由、WEB-INF/lib里的 jar 包为什么不能随便删、JSP 编译后的.java和.class文件到底藏在哪。适合正在从学生项目转向真实企业 Web 开发的 Java 初学者也适合那些常年用 Spring Boot 内嵌 Tomcat、已经忘了传统 WAR 部署底层逻辑的中级开发者。你不需要会写框架但必须知道你的代码最终是怎么变成 URL 被浏览器访问到的。2. War 包的本质一个被 Servlet 规范严格定义的 ZIP 结构体2.1 War 包不是 ZIP而是遵循 JSR 340Servlet 3.1规范的标准化归档格式很多人把 War 包简单理解为“带特定文件夹的 ZIP”这是危险的认知起点。WarWeb Application Archive是 Java EE现 Jakarta EE规范中明确定义的归档类型其结构、文件命名、路径层级、元数据格式全部由Servlet 规范强制约束。Tomcat 作为 Servlet 容器启动时会逐层校验 War 包是否满足这些硬性条件。举个最典型的例子如果你把web.xml放在src/main/webapp/WEB-INF/下Eclipse 编译时会自动把它复制到输出目录这没问题但如果你手动把它拖进src/main/resources再通过 Maven 的resources插件 copy 过去Eclipse 默认不会识别这个路径结果 War 包里压根没有WEB-INF/web.xml——Tomcat 启动时不会报错但所有 Servlet 和 Filter 都不会注册整个应用形同虚设。这就是“结构即契约”的体现。War 包的根目录等价于 Web 应用的上下文根Context Root/就是你的http://localhost:8080/yourapp/中的yourapp。所有静态资源HTML、CSS、JS、图片必须放在根目录或其子目录下所有受保护的资源Java 类、配置文件、第三方库必须严格放在WEB-INF/及其子目录内WEB-INF/外的任何文件只要路径不以/开头都会被容器视为可公开访问的资源。这种设计不是为了增加复杂度而是为了安全隔离WEB-INF/classes下的类可以被 Servlet 加载但无法被浏览器直接请求WEB-INF/lib下的 jar 包参与类加载但其内部的META-INF/MANIFEST.MF不会被外部读取。理解这一点你就明白为什么 Eclipse 的“Export as War”功能背后要调用org.eclipse.jst.j2ee.internal.deployables.J2EEFlexProjDeployable这个内部类——它不是在打包是在校验并生成符合规范的结构体。2.2 标准 War 包的七层结构解析从根目录到最深的 class 文件一个合规的 War 包解压后必须呈现以下标准结构以myapp.war为例myapp/ ├── index.jsp # 根目录下的静态/动态资源可被直接访问 ├── css/ │ └── style.css # 静态资源子目录路径与 URL 一一对应 ├── images/ │ └── logo.png ├── WEB-INF/ # 核心保护目录所有内容不可被浏览器直接访问 │ ├── web.xml # 部署描述符定义 Servlet、Filter、Listener、欢迎页等 │ ├── classes/ # 编译后的 Java 类文件.class按包路径组织 │ │ ├── com/example/MyServlet.class │ │ └── config/app.properties │ ├── lib/ # 第三方依赖 jar 包Tomcat 启动时自动加入 classpath │ │ ├── spring-core-5.3.30.jar │ │ └── mysql-connector-java-8.0.33.jar │ └── tags/ # 自定义 JSP Tag Library 描述符.tld 文件 ├── META-INF/ # 元数据目录包含归档信息 │ └── MANIFEST.MF # 清单文件记录创建者、主类、依赖等对 War 非必需但推荐 └── resources/ # 注意此目录若存在会被视为根目录下的普通资源非标准位置关键点解析WEB-INF/classes和WEB-INF/lib共同构成 Web 应用的运行时 classpath。Tomcat 的WebAppClassLoader会优先从classes加载再从lib中的 jar 加载。这意味着如果你在classes下放了一个和lib中同名的类比如自己重写了StringUtils它会覆盖 jar 包里的版本——这是调试时常用的“热替换”技巧但上线前必须清理。web.xml的版本声明至关重要。Servlet 3.0 支持注解驱动WebServlet但很多老项目仍依赖web.xml。如果web.xml的version2.5而你用了WebFilterTomcat 会忽略该注解因为 2.5 版本不支持。Eclipse 在新建 Dynamic Web Project 时会让你选“Dynamic Web Module Version”这个选择直接决定了web.xml的 schema 和容器行为。META-INF/MANIFEST.MF虽然对 War 不是强制要求但强烈建议填写。例如添加Implementation-Title: My Enterprise App和Implementation-Version: 1.2.3这样在 Tomcat Manager 页面能看到清晰的版本号运维排查时一目了然。Eclipse 导出时默认不生成你需要在导出向导的“Manifest file”选项里勾选“Generate default manifest file”。2.3 Eclipse 的“Dynamic Web Project”与标准 War 的映射关系Eclipse 并不是直接操作文件系统来构建 War而是通过Project Facet项目特性机制将开发视图映射到标准结构。当你创建一个 Dynamic Web ProjectEclipse 会在.settings/org.eclipse.wst.common.project.facet.core.xml中记录installed facetjst.web version4.0/ installed facetjst.java version17/ installed facetwst.jsdt.web version1.0/这里的jst.webversion4.0对应 Servlet 4.0 规范它决定了默认的web.xmlschema 是http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsdsrc/main/java下的类会被编译到WEB-INF/classesWebContent/或你自定义的WebRoot目录被视为 Web 应用的根目录其内容直接映射到 War 包根WebContent/WEB-INF/lib下的 jar 会被自动加入构建路径且打包时复制到 War 的WEB-INF/lib提示Eclipse 的WebContent目录名是可以改的右键项目 → Properties → Project Facets → Java Web Module → Content directory但改完后必须手动调整所有引用路径否则web.xml里的welcome-file-list会找不到index.jsp。我见过最坑的案例是有人把WebContent改成src/main/webapp模仿 Maven 结构结果 Eclipse 的部署器找不到web.xml因为 Facet 配置没同步更新。3. 从 Eclipse 到 Tomcat三步走的实操链路与每个环节的陷阱排查3.1 步骤一确保 Eclipse 项目本身是“可部署”的——检查 Facet、Build Path 和 Deployment Assembly在点击“Export”之前90% 的失败源于项目配置错误。这不是导出环节的问题而是源头没对齐。检查 Facet项目特性右键项目 → Properties → Project Facets。确认Dynamic Web Module已勾选且版本与你的 Tomcat 版本匹配Tomcat 9 对应 Servlet 4.0Tomcat 10 对应 Servlet 5.0/Jakarta EE 9注意包名从javax.servlet变为jakarta.servletJava版本与你安装的 JDK 一致如项目用 JDK 17Facet 里Java必须是17否则编译的.class文件 Tomcat 无法加载如果用了 MavenJava Build Path里的Libraries应该只包含 JDK 和Maven Dependencies不要手动添加WEB-INF/lib下的 jar——Eclipse 会认为这是重复依赖导致 War 包里出现两份相同 jar。检查 Deployment Assembly部署程序集这是 Eclipse 打包逻辑的核心控制器。右键项目 → Properties → Deployment Assembly。这里定义了“哪些源文件夹、哪些库以什么路径打包进 War”。默认配置通常是Source列/src→Deploy Path列WEB-INF/classesJava 源码编译后放这里Source列/WebContent→Deploy Path列/Web 根目录Source列/WebContent/WEB-INF/lib→Deploy Path列WEB-INF/lib第三方库但常见陷阱如果你把log4j2.xml放在src/main/resources而 Deployment Assembly 里没有这一项它就不会被打包进WEB-INF/classes导致日志初始化失败如果你用了 MavenMaven Dependencies默认会出现在 Deployment Assembly 里路径是WEB-INF/lib这是正确的但如果手动添加了WEB-INF/lib下的 jarDeployment Assembly 里就会出现两条指向同一个 jar 的条目导出时会重复打包体积翻倍且可能冲突。实操心得我习惯在 Deployment Assembly 里点击 “Add…” → “Folder”然后选择src/main/resourcesDeploy Path 设为WEB-INF/classes。这样所有resources下的配置文件application.properties、log4j2.xml都能精准落入WEB-INF/classes无需担心路径错乱。这个操作比修改build path更直接、更可控。3.2 步骤二正确执行 Eclipse 导出 War 包——避开向导里的三个隐藏开关Eclipse 的导出向导File → Export → Web → WAR file看似简单但有三个关键选项极易被忽略1. “Destination” 路径必须是绝对路径且文件名以.war结尾错误做法填myappEclipse 会生成myapp文件无扩展名Tomcat 无法识别正确做法填D:/deploy/myapp.war或/home/user/deploy/myapp.war。Linux 下注意路径权限确保 Tomcat 进程有读取权限。2. “Select the resources to export” —— 勾选“Overwrite existing files”这个选项默认不勾选。如果你之前导出过同名 War新版本不会覆盖Tomcat 会部署旧包。我踩过一次坑改了web.xml的 welcome-file导出时没勾选覆盖结果 Tomcat 重启后还是显示老页面查了半小时才发现 War 文件时间戳没变。3. “WAR file options” 里的 “Generate web.xml deployment descriptor”如果你的项目没有web.xml纯注解开发这个选项必须勾选否则导出的 War 包里WEB-INF目录为空Tomcat 会拒绝部署如果你的项目有web.xml这个选项必须不勾选否则 Eclipse 会用默认模板覆盖你手写的web.xml所有 Servlet 映射、Filter 配置全丢。注意导出过程中的 “Problems” 视图会实时显示警告。最常见的警告是 “Resource is out of sync with the file system”这是因为 Eclipse 的工作区缓存和磁盘文件不同步。解决方法右键项目 → Refresh或者关闭 “Build Automatically”再导出。别忽视这些警告它们往往是部署失败的先兆。3.3 步骤三Tomcat 部署与验证——不只是把 War 放进 webapps 目录那么简单把myapp.war丢进$CATALINA_HOME/webapps/目录Tomcat 确实会自动解压并部署但这只是“能跑”不是“跑对”。真正的验证需要三层检查第一层检查 Tomcat 日志确认部署成功启动 Tomcatbin/startup.bat或bin/startup.sh观察logs/catalina.out成功标志INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [D:\apache-tomcat-9.0.83\webapps\myapp.war]随后是INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [D:\apache-tomcat-9.0.83\webapps\myapp.war] has finished in 2,345 ms失败标志SEVERE [main] org.apache.catalina.startup.HostConfig.deployWAR Error deploying web application archive [D:\apache-tomcat-9.0.83\webapps\myapp.war]后面跟着Caused by: java.lang.ClassNotFoundException: com.example.MyServlet或org.xml.sax.SAXParseException; lineNumber: 10; columnNumber: 25; cvc-complex-type.2.4.a: Invalid content was found starting with element servlet-mappingXML 格式错误。第二层检查解压后的目录结构确认 War 内容合规Tomcat 部署时会自动解压 War 到webapps/myapp/去掉.war后缀。进入该目录用命令行或文件管理器检查WEB-INF/web.xml是否存在内容是否完整servlet-class的全限定名是否拼写正确注意大小写com.example.myservlet和com.example.MyServlet是两个类WEB-INF/classes/com/example/MyServlet.class是否存在用javap -v查看其major version是否匹配 Tomcat 的 JDKJDK 17 编译的 class major version 是 61JDK 11 是 55WEB-INF/lib/下的 jar 包数量是否合理一个只有几个 JSP 的小项目lib目录里却有 50 个 jar大概率是 Maven 依赖传递没处理好会导致类加载冲突。第三层用浏览器和 curl 进行端到端功能验证访问http://localhost:8080/myapp/看是否返回index.jsp的内容访问http://localhost:8080/myapp/servlet/test假设你有一个WebServlet(/servlet/test)看是否触发 Servlet 的doGet方法用curl -I http://localhost:8080/myapp/images/logo.png检查 HTTP 状态码是否为200 OK确认静态资源服务正常如果有数据库操作检查 Tomcat 日志里是否有SQLException或连接超时。实操心得我习惯在webapps/myapp/目录下放一个test.jsp内容就一行% new java.util.Date() %。每次部署后第一时间访问这个 URL如果时间能刷新说明 JSP 引擎、类加载、EL 表达式解析全部正常。这比检查日志快得多是快速验证“基础链路”的黄金标准。4. 常见问题与排查技巧实录从 404 到 ClassNotFound 的实战诊断手册4.1 问题速查表症状、原因、定位命令、解决方案症状可能原因快速定位命令/方法解决方案访问http://localhost:8080/myapp/返回 4041. War 包未被 Tomcat 识别文件名不是.war或权限不足2.web.xml中welcome-file-list指定的文件不存在3. Tomcat 的server.xml中Host的appBase路径配置错误ls -l $CATALINA_HOME/webapps/看myapp.war是否存在且大小 0cat $CATALINA_HOME/webapps/myapp/WEB-INF/web.xml | grep welcomegrep appBase $CATALINA_HOME/conf/server.xml1. 确保 War 文件名正确Linux 下chmod 644 myapp.war2. 检查web.xml的welcome-file是否与WebContent/下的文件名完全一致包括大小写3. 确认appBasewebapps且路径正确访问http://localhost:8080/myapp/servlet/test返回 4041.web.xml中servlet-mapping的url-pattern路径错误2. Servlet 类未编译进WEB-INF/classes3. 使用了注解但web.xml的version太低cat $CATALINA_HOME/webapps/myapp/WEB-INF/web.xml检查servlet和servlet-mapping的url-pattern是否匹配ls -R $CATALINA_HOME/webapps/myapp/WEB-INF/classes/com/example/看MyServlet.class是否存在1.url-pattern/servlet/test/url-pattern必须与 URL 完全一致2. 检查 Eclipse 的 Deployment Assembly确保src目录映射到WEB-INF/classes3. 将web.xml的version升级到3.0或更高Tomcat 启动时报ClassNotFoundException: com.example.MyServlet1.MyServlet.class文件缺失或路径错误包名与目录结构不匹配2.WEB-INF/lib中缺少该 Servlet 依赖的 jar如用了 Spring但spring-web.jar没打包3. JDK 版本不兼容高版本编译低版本 Tomcat 运行jar -tf myapp.war | grep MyServlet看 class 文件是否在WEB-INF/classes/com/example/MyServlet.classjar -tf myapp.war | grep spring-webjava -version和javac -version对比1. 确保 Java 源文件的package com.example;与src/com/example/MyServlet.java的物理路径一致2. 在 Deployment Assembly 中添加缺失的 jar3. 统一 JDK 版本或在 Eclipse 的 Java Compiler 设置中将Compiler compliance level设为与 Tomcat JDK 相同JSP 页面显示源码而不是渲染结果1. Tomcat 的 JSP Servlet 未启用web.xml中注释了servlet配置2.web.xml的version低于 2.3JSP 1.2 要求3.WEB-INF/web.xml文件损坏或编码错误cat $CATALINA_HOME/conf/web.xml | grep -A 10 jsp看全局 JSP Servlet 配置head -n 5 $CATALINA_HOME/webapps/myapp/WEB-INF/web.xml看 XML 声明是否正确1. 确保$CATALINA_HOME/conf/web.xml中的servlet和servlet-mapping未被注释2. 将myapp的web.xmlversion设为2.4或更高3. 用 UTF-8 编码保存web.xml避免 BOM 头4.2 深度排查技巧用jar命令和javap命令做外科手术式诊断当图形界面和日志无法定位问题时命令行是终极武器。技巧一用jar -tf快速窥探 War 包内部结构# 列出 War 包所有文件搜索关键路径 jar -tf myapp.war | grep -E (web.xml|MyServlet|log4j|classes/) # 输出示例 # WEB-INF/web.xml # WEB-INF/classes/com/example/MyServlet.class # WEB-INF/classes/log4j2.xml # WEB-INF/lib/spring-core-5.3.30.jar # 检查某个 class 文件是否存在且路径正确 jar -tf myapp.war | grep MyServlet.class # 如果输出为空说明 class 没打包进去如果输出是 com/example/MyServlet.class没有 WEB-INF/classes/ 前缀说明路径错了。技巧二用javap -v查看 class 文件的详细信息# 从 War 包中解压出 class 文件先解压 War或用 jar -xvf jar -xvf myapp.war WEB-INF/classes/com/example/MyServlet.class # 查看 class 的版本和常量池 javap -v WEB-INF/classes/com/example/MyServlet.class | head -n 20 # 关键输出 # minor version: 0 # major version: 61 # 这表示 JDK 17 编译61 17 44 # flags: (0x0021) ACC_PUBLIC, ACC_SUPER # this_class: #5 # 本类名 # super_class: #6 # 父类名通常是 javax.servlet.http.HttpServlet # 如果 major version 是 61而你的 Tomcat 运行在 JDK 11最大支持 55就会 ClassNotFound。技巧三用curl -v模拟浏览器请求查看完整 HTTP 交互# 查看请求头、响应头、状态码、重定向链 curl -v http://localhost:8080/myapp/ # 如果返回 302 重定向看 Location 头指向哪里 # 如果返回 404看 Server 头是否是 Apache-Coyote/1.1确认是 Tomcat # 检查静态资源 MIME 类型是否正确 curl -I http://localhost:8080/myapp/css/style.css # 正确响应头应包含Content-Type: text/css # 如果是 application/octet-stream说明 Tomcat 没识别 CSS 类型需检查 web.xml 的 mime-mapping。4.3 那些年我们踩过的坑来自真实项目的血泪经验坑一“Eclipse 自动构建”和 “Tomcat 自动部署” 的双重缓冲导致“假成功”现象改了 JSP刷新页面没变化改了 Java 类重启 Tomcat 后还是旧逻辑。原因Eclipse 的Build Automatically会把编译结果写入build/classes而 Tomcat 的autoDeploy会监控webapps/目录。如果 Eclipse 的Deployment Assembly把build/classes映射到WEB-INF/classes但你又手动把 War 包丢进webappsTomcat 就会部署 War 里的旧 class忽略 Eclipse 的实时编译。解决方案永远只用一种部署方式。要么全程用 Eclipse 的Servers视图右键 Tomcat → Add and Remove → 添加项目让 Eclipse 控制部署要么彻底禁用 Eclipse 自动构建手动导出 War 再丢进webapps。二者混用是灾难之源。坑二“中文路径”和 “空格” 在 Windows 下的隐形杀手现象War 包在 Eclipse 里导出成功但放到D:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps\下Tomcat 启动时报java.io.FileNotFoundException: D:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps\myapp.war (系统找不到指定的路径)。原因Windows 的Program Files路径含空格Tomcat 的某些旧版本脚本尤其是catalina.bat没有对路径加引号导致命令行解析失败。解决方案Tomcat 安装路径绝对不要有空格和中文。推荐路径D:\tomcat9或C:\servers\tomcat9。这是 Windows 下部署 Java Web 的铁律。坑三“JSP 编译缓存” 导致的页面不更新现象改了index.jsp重启 Tomcat 后页面还是旧的。原因Tomcat 会把 JSP 编译成 Servlet.java和.class并缓存在work/Catalina/localhost/myapp/目录下。即使 War 包更新了旧的编译文件还在。解决方案每次部署新 War 前清空work目录。rm -rf $CATALINA_HOME/work/*Linux或del /q /s %CATALINA_HOME%\work\*.*Windows。这是最简单、最有效的 JSP 热更新保障。5. 进阶实践从手动导出到自动化构建的平滑演进5.1 当项目变大为什么 Eclipse 导出 War 包不再可靠一个 5 人团队维护的电商后台模块超过 20 个依赖 jar 包 150每天合并代码 50 次。这时还靠 Eclipse 手动导出 War会遇到三大瓶颈一致性失控张三导出时勾选了 “Overwrite”李四没勾王五用了不同的 JDK 版本三个 War 包表面一样内部 class 版本不同可追溯性缺失War 包里没有版本号、构建时间、Git Commit ID线上出问题无法快速定位是哪个分支、哪次提交导致的流程不可控测试环境部署依赖人工操作漏步骤、错顺序、忘清理缓存成为发布事故的温床。这时候必须引入Maven作为构建中枢。Eclipse 只是编辑器Maven 才是构建引擎。5.2 Maven 构建 War 包pom.xml的核心配置与原理一个标准的 Web 项目pom.xml关键配置如下project modelVersion4.0.0/modelVersion groupIdcom.example/groupId artifactIdmyapp/artifactId version1.0.0-SNAPSHOT/version packagingwar/packaging !-- 这是核心告诉 Maven 打成 War -- properties maven.compiler.source17/maven.compiler.source maven.compiler.target17/maven.compiler.target project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties dependencies !-- Servlet APIprovided 表示由 Tomcat 提供不打入 War -- dependency groupIdjakarta.servlet/groupId artifactIdjakarta.servlet-api/artifactId version5.0.0/version scopeprovided/scope /dependency !-- JSP API -- dependency groupIdjakarta.servlet.jsp/groupId artifactIdjakarta.servlet.jsp-api/artifactId version3.0.0/version scopeprovided/scope /dependency !-- 其他业务依赖如 Spring、MyBatis -- dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.3.30/version /dependency /dependencies build finalNamemyapp/finalName !-- War 包名不带版本号 -- plugins !-- Maven War Plugin控制 War 打包行为 -- plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-war-plugin/artifactId version3.3.2/version configuration failOnMissingWebXmlfalse/failOnMissingWebXml !-- 允许无 web.xml -- warSourceDirectorysrc/main/webapp/warSourceDirectory !-- 指定 Web 根目录 -- /configuration /plugin !-- Maven Resources Plugin确保 resources 下的文件打入 classes -- plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-resources-plugin/artifactId version3.3.1/version configuration encodingUTF-8/encoding /configuration /plugin /plugins /build /project关键点解读packagingwar/packaging是 Maven 的“契约”它激活maven-war-plugin并约定src/main/webapp为 Web 根目录scopeprovided/scope的依赖如servlet-api不会被打包进WEB-INF/lib因为 Tomcat 已经提供了重复打包会导致ClassCastExceptionfinalNamemyapp/finalName决定了生成的 War 包名是myapp.war而不是默认的myapp-1.0.0-SNAPSHOT.warmaven-war-plugin的failOnMissingWebXml设为false是为了支持 Servlet 3.0 的注解驱动避免没有web.xml时构建失败。5.3 一条命令完成构建与部署mvn clean package tomcat7:deploy的真相Maven 的强大在于插件生态。虽然tomcat7-maven-plugin已停止维护但它的原理值得学习plugin groupIdorg.apache.tomcat.maven/groupId artifactIdtomcat7-maven-plugin/artifactId version2.2/version configuration urlhttp://localhost:8080/manager/text/url servertomcat-server/server !-- 对应 ~/.m2/settings.xml 中的 server id -- path/myapp/path /configuration /plugin执行mvn clean package tomcat7:deploy时Maven 会clean删除target/目录package编译 Java、拷贝资源、打包成target/myapp.wartomcat7:deploy读取settings.xml中的用户名密码调用 Tomcat Manager 的 REST APIPOST /manager/text/deploy?path/myapp上传 War 包并部署。注意这要求 Tomcat 的conf/tomcat-users.xml中配置了manager-script角色的用户并且conf/Catalina/localhost/manager.xml允许远程访问。生产环境严禁开启 Manager这只适用于开发和测试。5.4 生产级部署的终极形态CI/CD 流水线中的 War 包交付在 Jenkins 或 GitLab CI 中一个典型的 Web 项目构建流水线是stages: - build - test - deploy build-job: stage: build script: - mvn clean package -Dmaven.test.skiptrue - cp target/myapp.war /tmp/deploy/ artifacts: - target/myapp.war deploy-to-test: stage: deploy script: - scp /tmp/deploy/myapp.war usertest-server:/opt/tomcat/webapps/ - ssh usertest-server cd /opt/tomcat ./bin/shutdown.sh sleep 5 ./bin/startup.sh这个流程保证了可重现性每次构建都从干净的 Git 仓库开始mvn clean package确保无缓存干扰可追溯性War 包的MANIFEST.MF可以注入 Git Commit IDplugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven