尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

JavaWeb项目打包部署全流程:war包制作、Tomcat配置与踩坑指南

JavaWeb项目打包部署全流程:war包制作、Tomcat配置与踩坑指南 开头JavaWeb项目从写完代码到能被浏览器访问中间隔着打包、部署、启动这三道坎。不少朋友在IDEA里跑得好好的项目一点问题没有可真到了要把war包丢进Tomcat、让项目在独立环境里跑起来的时候就开始发懵war包怎么打打完放哪个目录Tomcat怎么起日志里刷了一屏报错又该怎么定位这篇文章就是我这些年处理JavaWeb打包部署的完整流程复盘从原理到操作从命令到踩坑一路捋下来适合刚学完JavaWeb、还没独立部署过项目的同学也适合正在被Tomcat部署问题折腾的工程师。全文以经典JavaWeb项目Servlet JSP Maven构建为例Spring Boot项目虽然打包方式不同但底层思路完全可以参考。1. 摸清底细部署前必须搞清楚的三个基础1.1 JavaWeb应用在Tomcat里到底是怎么跑起来的先说一个容易被忽略的基础问题你的JavaWeb项目为什么一定要放在Tomcat里才能运行因为Tomcat本质是一个Servlet容器它负责接收HTTP请求、解析请求参数、按路径找到对应的Servlet或JSP、调用你的业务代码再把响应返回给浏览器。你的项目本身不是一个可执行程序它只是一堆class文件、配置文件、静态资源必须有一个壳帮它处理外部通信这个壳就是Tomcat。一个标准JavaWeb项目的内部结构在打成war包之后应该是这样的根目录下是静态资源HTML、CSS、JS、图片WEB-INF目录下放着web.xmlServlet规范要求的部署描述符、classes目录存放编译好的.class文件、lib目录存放项目依赖的jar包。Tomcat启动后会扫描webapps目录下的每个web应用根据WEB-INF/web.xml里的映射关系把URL请求路由到对应的Servlet类。所以你会发现部署时war包被Tomcat自动解压成目录这个目录本质上就是Tomcat在运行时为你构建的可执行环境。理解这点有个直接好处排查问题时你能判断错误发生在哪一层。如果请求能到达Tomcat但返回404多半是URL映射或web.xml问题如果Tomcat启动日志里就报ClassNotFound说明依赖jar没进lib目录。不懂运行原理的排查基本就是瞎猜。1.2 war包和jar包打包之前先选对格式很多初学者会问为什么别人部署Spring Boot项目是一个可执行的jar包我的JavaWeb项目却要打war包因为两者选型不同。经典JavaWeb项目Servlet JSP 外部Tomcat需要打成war包war包是一种Web应用归档它遵循Servlet规范内部结构要求明确外部容器比如Tomcat看到war包就知道怎么解压和运行。而Spring Boot项目默认内置了Tomcat引擎打出来的jar包自带启动类直接java -jar就能起服务不需要外部容器。选型建议如果你维护的是传统JavaWeb项目或者公司规定了必须使用外部Tomcat统一管理多个应用那就老老实实打war包。如果你在写新项目用Spring Boot的话直接打jar包更省心部署时一台机器上跑多个服务互不干扰。但要注意Spring Boot项目也可以打war包丢进外部Tomcat做法是把packaging改成war同时继承SpringBootServletInitializer并重写configure方法这一步很多新手经常漏掉结果打出来的war包丢进Tomcat后根本起不来日志里只看到404或者直接没有任何反应。就本文的经典JavaWeb项目而言目标产物就是war包后面所有操作都围绕这个产物展开。1.3 环境准备和版本选型别让坑埋在起跑线上部署之前先把环境捋一遍。JDK、Maven、Tomcat这三个东西的版本必须互相兼容这是最常被忽视但最关键的环节。我的建议是JDK 8配Tomcat 8.5/9.0JDK 11/17配Tomcat 9.0/10.1。Tomcat版本和Servlet规范的关系简单理解就是Tomcat 9对应Servlet 4.0规范Tomcat 10对应Servlet 5.0规范包名从javax.servlet变成了jakarta.servlet如果你的项目代码还在用javax别选Tomcat 10以上版本否则启动后必定报NoClassDefFoundError这个坑我见过太多次。Maven建议用3.6.x或3.8.x不要用太老也别追太新3.9系列在某些老旧项目上会遇到插件兼容性问题。下载地址直接去官网Windows环境解压后配置MAVEN_HOME环境变量Linux下配置到/etc/profile.d/maven.sh里。Tomcat同理配置CATALINA_HOME环境变量但这里有个细节CATALINA_HOME指向Tomcat的根目录而你在开发时如果直接在IDEA里集成TomcatCATALINA_BASE实例配置目录和CATALINA_HOME经常是分开的IDEA会单独复制一份配置到项目临时目录所以有时你改了conf/server.xml却感觉没生效先检查你改的是不是真正被用的那份配置。最后是网络问题。Maven拉依赖经常卡死我建议所有人在settings.xml里配置阿里云镜像这个配置一次就能省下大量时间。配置内容很简单mirrors mirror idaliyunmaven/id mirrorOf*/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror /mirrors顺便把本地仓库路径也改一下默认在C盘用户目录下系统盘空间紧张的话务必迁到其他盘。2. 打包实操从源码到可部署产物的完整流程2.1 Maven命令行打包最稳最推荐的方式打包这件事命令行永远是最可靠的。IDE的图形化按钮本质也是执行Maven命令但有时候IDE会缓存旧状态导致打包结果不新鲜所以我建议第一步先掌握命令行方式。进到项目根目录pom.xml所在的层级执行mvn clean packageclean会删除target目录package会执行编译、测试、打包三个阶段。命令跑完后在target目录下会看到一个xxx.war文件这个就是最终产物。如果不想跑测试用例比如测试类里有数据库连接导致打包失败加参数跳过mvn clean package -DskipTests-DskipTests是跳过测试的执行但会编译测试类如果你连测试代码的编译都要跳过用-Dmaven.test.skiptrue。日常打包推荐前者既能加快速度又保留测试代码的编译校验。关于mvn package和mvn install的区别也顺带说清楚package只是把项目打包到项目的target目录install会在此基础上把war/jar安装到本地Maven仓库供同一个机器上其他项目依赖。如果你的项目是模块化的父模块依赖子模块就必须先mvn install子模块否则父模块编译时会提示找不到依赖的jar包这个坑在多模块项目里尤其常见。打包过程中你会看到Maven输出一长串日志下载依赖时会反复出现Downloading开头的行如果网络不好还会看到红色ERROR不要立刻慌。先看最后面有没有BUILD SUCCESS。只要出现BUILD SUCCESS不管中间有多少黄色警告产物都是可用的。只有BUILD FAILURE才说明打包失败。2.2 IDEA图形化打包开发场景下的省事操作IDEA里打包有两种常见路径第一种是右侧Maven面板展开你的项目找到Lifecycle目录双击clean再双击package效果和命令行完全一致控制台窗口里能看到同样的Maven日志。第二种是在IDEA的Artifacts配置里手动指定打包内容这个适合需要定制war内容的场景新手不推荐因为配置错一个路径打出来的war包就是缺胳膊少腿的。我实际使用中更推荐第一种理由很简单Maven面板里的操作完全基于pom.xml不会有额外配置干扰。双击clean之后再双击package右侧面板的target目录下就会刷新出新war包配合IDEA的自动构建开发中频繁打包验证非常顺手。但注意一个细节IDEA里双击package时如果项目设置了多环境配置比如dev、prod需要在打包前确认激活哪个profile否则打出来的包可能带着开发环境的数据库连接、日志级别等配置。命令行对应写法是mvn clean package -Pprod这里-P指定profile如果你的pom.xml里没配置这种多环境profile这步忽略即可。还有一个IDEA特有的坑项目里引入了某个jar包代码里用得好好的但打完包后运行时报ClassNotFound。这种大概率是依赖scope配错了比如把某个依赖配成了scopeprovided/scopeprovided在打包时不包含进war包但编译期能用。Tomcat自带的servlet-api就属于这个范畴你用的时候没问题但打成war包后如果再依赖它部署到Tomcat上就会和容器自带的类冲突。排查思路很简单解压war包看WEB-INF/lib下的jar是否齐全。2.3 打包报错高频问题程序包不存在、编码GBK、依赖拉不下来打包报错是高频问题这里集中讲三个最常见的。第一个是程序包xxx不存在或找不到符号。这通常不是真的缺依赖而是多模块项目里子模块没有先install或者私服公司内部Maven仓库里的快照包没更新。解决办法先mvn clean install -DskipTests把依赖模块装进本地仓库再回到当前模块打包。如果是远程仓库里的最新快照版本加-U参数强制更新mvn clean package -U第二个是编码GBK的不可映射字符。源码里写了中文注释而项目文件编码和Maven编译时的编码设置不一致。最稳妥的做法是在pom.xml里显式声明编码properties project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties同时确保IDEA的File Encoding设置为UTF-8在IDEA右下角可以直接看到和修改。如果项目历史文件本来就是GBK编码那就别一刀切改UTF-8否则老文件全乱码这种情况应该把源码转为UTF-8后统一设置转码操作用IDEA自带的File - File Properties - File Encoding来逐个处理。第三个是依赖下载不完整报错信息里会出现Could not resolve dependencies或Failure to transfer。常见原因是网络波动导致jar包下载到一半就中断了本地仓库里留下了一个损坏的.lastUpdated文件。处理方式删除本地仓库对应目录下的.lastUpdated文件然后再重新打包。find ~/.m2/repository -name *.lastUpdated -exec rm -rf {} \;如果你在Windows上路径换成自己配置的本地仓库路径。然后再打包Maven就会重新下载完整依赖。这里多说一句maven本地仓库里的损坏jar包是不会自动修复的不清掉就会一直报同样的错这是很多人反复打包失败却找不到原因的关键。3. 部署落地war包拷贝、IDEA集成与Linux服务器部署3.1 最简单的方式把war包丢进webapps目录拿到war包之后最简单也最经典的部署方式就是把它放到Tomcat的webapps目录下然后启动Tomcat。Tomcat启动时会自动扫描webapps目录遇到war包会自动解压成同名目录并加载整个过程不需要任何额外配置。具体操作先确认Tomcat是否在运行如果在运行先执行shutdown脚本停掉然后把war包拷贝到webapps目录再执行startup脚本启动。为什么强调先停止再拷贝因为Tomcat运行中如果你直接覆盖war包它可能不会自动重新加载或者解压到一半造成目录不完整最后结果就是访问时404。稳妥的标准流程是停Tomcat、清掉旧的解压目录、放新的war包、启动Tomcat。war包的命名决定了访问路径。比如你放了myapp.warTomcat启动后会解压成myapp目录访问地址是http://localhost:8080/myapp。如果想通过根路径直接访问http://localhost:8080/可以把war包改名为ROOT.war这样Tomcat会把它当作根应用来部署。这个细节在交付测试时尤其重要测试同学经常直接把链接写成http://ip:8080/结果看到404其实是上下文路径没对上。有人可能在conf/server.xml里配置过Context标签来指定应用路径这个做法能用但不推荐。原因是server.xml是Tomcat的核心配置文件改动一旦出错整个Tomcat起不来而且每次部署升级都会增加出错概率。现代部署方式就是在webapps里放war包让Tomcat自动管理简单可控。3.2 IDEA集成Tomcat开发阶段的部署调试技巧在开发阶段你没必要每次都手动拷贝war包到Tomcat目录IDEA可以直接和本地Tomcat集成一键部署、一键启动、热部署效率高得多。配置步骤打开Run/Debug Configurations窗口点左上角加号找到Tomcat Server - Local注意老版本IDEA可能需要先安装Smart Tomcat插件新版IDEA企业版自带。在Configure里指定Tomcat主目录和JRE版本然后切到Deployment选项卡点加号选择Artifact把war包/war exploded加进去。这里会出现两个选项war和war exploded。war方式会打包并上传到Tomcat临时目录war exploded方式直接以文件夹形式部署支持JSP和静态资源的热更新开发调试推荐用exploded。Application context这个参数对应访问路径默认跟着项目名走你可以改成/表示根路径或者改成/myapp按需设置。设置完成后点运行IDEA会自动启动Tomcat并把项目部署进去浏览器自动打开首页。控制台你会看到Tomcat启动日志留意Deploying web application archive和Server startup in这两行出现后者说明启动成功。但这个方案有个隐形问题IDEA启动的Tomcat实例是IDEA替你建的临时实例配置数据默认放在IDEA的临时目录里不是你本机配置的Tomcat目录。所以你在IDEA里改的端口、数据源跟命令行手动启动Tomcat玩的是两套环境。判断标准很简单看启动日志里的Catalina.base路径指向哪。这个问题不是bug知道有这回事就行避免两边配置不一致时来回怀疑人生。3.3 Linux服务器部署与Tomcat调整服务器上实战从开发机走向服务器操作逻辑一样但细节完全不同。首先把war包上传到服务器可以用scp、sftp或者直接用宝塔面板的文件管理。上传到Tomcat的webapps目录后同样先保证Tomcat处于停止状态再启动。服务器上Tomcat启动时的一个常见坑是权限问题。如果你用非root用户启动Tomcatwebapps目录或logs目录的属主不是当前用户启动时可能报权限不足日志写不进去应用也没有部署权限。解决方式就是给当前用户授权chown -R youruser:yourgroup /opt/tomcat或者干脆把webapps和logs目录的权限放开chmod -R 755 /opt/tomcat/webapps /opt/tomcat/logs然后修改端口。默认8080端口在服务器上经常跟其他服务冲突或者因为安全考虑要换成别的端口。修改方式是编辑conf/server.xml找到Connector节点Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 /这里的port就是HTTP访问端口。改完之后千万别忘了检查服务器的防火墙和云安全组。很多人明明Tomcat已经启动了本地curlhttp://localhost:8080也能通但外网就是访问不了十有八九是安全组没放行端口。腾讯云、阿里云的控制台都要单独配置。防火墙方面CentOS常用firewall-cmd --zonepublic --add-port8080/tcp --permanent firewall-cmd --reload还有个服务器上强烈建议做的事设置JVM内存。默认情况下Tomcat的启动脚本不会分配太多堆内存项目稍大一点就频繁FullGC甚至OOM。在Tomcat的bin目录下新建一个setenv.shWindows是setenv.batTomcat启动时会自动加载这个文件里面写JAVA_OPTS-Xms512m -Xmx1024m -XX:MetaspaceSize128m -XX:MaxMetaspaceSize256m-Xms是初始堆大小-Xmx是最大堆大小两者设为相同值可以避免运行中堆扩容带来的性能损耗。MetaspaceSize是JVM元空间类加载信息、方法信息的初始大小项目依赖多、运行时间长的话这个值要给足否则报java.lang.OutOfMemoryError: Metaspace。这里的数值根据服务器内存调整比如服务器有4G内存给Tomcat 2G堆是合理的别把内存全塞给Tomcat操作系统和其他进程还需要余量。这里插一个热搜里典型的问题在setenv.sh里配置了运行内存之后用systemctl命令启动Tomcat失败。原因是systemd启动服务时并不会执行setenv.sh这个脚本它读的是systemd service文件里的配置。如果你用systemd管理Tomcat应该直接在service文件里写EnvironmentEnvironmentJAVA_OPTS-Xms512m -Xmx1024m或者干脆修改service文件里的ExecStart行把参数直接传给catalina.sh。所以解决方案不是删掉setenv.sh而是要搞清楚Tomcat到底由谁拉起。如果手上项目的Tomcat是用bin/startup.sh启动的setenv.sh一定生效如果是systemd或docker启动的就得改对应配置文件。这个区分能省掉你大半天排查时间。4. 启动验证与问题排查从踩坑到顺手4.1 正确启动Tomcat的方式与日志解读Tomcat启动脚本在bin目录下。Windows双击startup.bat或命令行执行Linux执行startup.shcd /opt/tomcat/bin ./startup.sh执行后终端会提示Tomcat started.但这行提示只说明Tomcat进程被拉起了不代表项目部署成功。启动和项目部署是两个动作Tomcat进程启动后才会去扫描webapps目录逐个加载应用整个过程需要几秒到几十秒不等。真正判断启动成功的标准有两条一是日志里出现Server startup in [xxx] milliseconds二是访问地址能正常返回页面。日志是排查问题的第一入口。Tomcat的logs目录下有几类关键日志catalina.out是Tomcat的核心日志启动过程、容器错误、严重异常都在这localhost.log记录特定应用上下文Context的日志通常一个应用一个文件格式是localhost.2025-01-15.log应用加载失败时错误信息多半在它里面catalina.date.log是按日期滚动的catalina日志。另外还有manager.log和host-manager.log分别对应管理后台的访问和操作日志。一个实用技巧启动Tomcat后先不动浏览器直接去看catalina.out的末尾几十行。如果看到Exception、SEVERE、Deployment error之类关键字直接沿着堆栈第一行去定位。如果看到Server startup in再去看localhost日志里应用上下文是否正常加载。按这个顺序排查基本不会漏掉问题。日志文件很大时用tail -100 /opt/tomcat/logs/catalina.out只关注最新的日志不要傻乎乎翻几万行。4.2 高频故障排查速查表部署这块的故障其实就那几类我把这几年遇到的高频问题整理成一张速查表遇到问题直接对着定位。现象常见原因排查与解决办法双击startup.bat窗口一闪就没了未配置JAVA_HOME或CATALINA_HOME命令行运行java -version看是否识别检查系统环境变量JAVA_HOME、CATALINA_HOME是否配置并指向正确目录启动报Address already in use: JVM_Bind端口被占用Windows执行netstat -ano访问项目返回404但Tomcat首页能开上下文路径不对或war包未解压成功查看webapps目录下是否有对应的解压目录检查访问URL是否带上下文路径返回403且提示Access denied访问了Tomcat Manager页面但没有权限检查conf/tomcat-users.xml是否配置了manager-gui角色和用户启动报LifecycleException: Failed to start componentweb.xml配置错误或Servlet初始化异常看完整堆栈通常后面跟着具体的类名或XML行号重点排查Servlet映射、Filter加载顺序应用能启动但访问时ClassNotFoundException缺少依赖jar包解压war包检查WEB-INF/lib里的jar是否齐全确认依赖scope是否为provided导致未打包数据库连接报错或连接池初始化失败数据库不在同一网络或连接配置错误检查jdbc配置里的IP、端口、账号密码服务器上执行telnet 数据库IP 3306测试连通性页面中文乱码编码不统一Tomcat 8底层默认UTF-8但响应头、JSP pageEncoding、数据库连接url里的characterEncoding需要统一设置为UTF-8OutOfMemoryError: PermGen space元空间不足常见于老版本JDKJDK8及以上改为Metaspace在setenv.sh中增大-XX:MaxMetaspaceSize这里必须多说一句的是404问题很多新手分不清Tomcat能访问但项目404和整个Tomcat都访问不了。前者说明Tomcat正常是应用路径没对上后者说明Tomcat本身没起来或端口不通。排查思路完全不同先分清到底是哪一层再去开对应的药方。另外有时候项目启动时日志里没有明显报错但访问就是白屏或空响应这种大概率是Servlet初始化时抛了异常但被吞了或者前端静态资源路径不对。看localhost日志里有没有局部异常同时用浏览器的F12开发者工具看网络请求返回的状态码200、302、500、404分别对应不同的排查方向。不要盯着页面看要看浏览器发出的每个请求。4.3 Tomcat应用迁移实战换服务器的注意事项热搜里有个问题问得很好如何将一个Tomcat应用迁移到另一台服务器上。这个问题不只是在做物理机搬迁时才用到日常换测试环境、搭灾备、扩充环境时都是同一套流程。先说迁移的核心原则把所有非默认配置和外部依赖全部盘点清楚再动环境。很多人只拷贝了webapps目录里的war包结果新环境起不来了回头再看发现少了自定义的配置文件、连接了旧服务器的数据库地址、甚至忘了上传第三方支付的证书文件。我一般按这个清单来迁移应用产物webapps目录下每个应用的war包或解压目录。如果你有多个应用且依赖版本不同建议全部带上。Tomcat配置文件conf/server.xml、conf/web.xml、conf/tomcat-users.xml。特别是server.xml里如果你改过端口、加过虚拟主机、AJP配置不拷贝就全丢了。公共jar包如果你在Tomcat的lib目录下放过自定义第三方jar要一并迁移。这个目录和应用的WEB-INF/lib不同Tomcat 9的lib目录由所有应用共享放进去的jar包所有应用都能用。外部依赖数据库连接信息、Redis地址、文件上传目录、日志目录。这部分最常见的坑是代码里写死了绝对路径比如/home/upload新环境这个目录不存在或权限不对应用启动时没什么异常但用户上传文件时就报错。迁移前用一条命令搜一下代码里的绝对路径grep -r /home/ --include*.java --include*.xml --include*.properties .环境变量服务器上是否配过JAVA_HOME、CATALINA_HOME、MAVEN_HOME等环境变量新服务器要重新设置。特别是JDK版本老环境是JDK8新环境默认装了JDK17你的项目如果用老版本的cglib或某些反射框架在JDK17上会直接报模块访问错误。迁移之后不能只验证能启动就完事我的验证清单比这个长应用首页能打开登录功能能走通有数据库连接的功能比如列表查询能查出数据如果有文件上传下载的功能实测一次上传确认目录权限和路径配置正确如果对接了微信支付或短信接口用一个测试账号调一次。这五步走完才算真正迁移完成。经常有人迁移完连登录都过不了因为数据库连接串还指向旧环境的IP这种问题在启动阶段是看不出来的只有请求实际触发了数据库操作才会暴露。写在最后的话这几年帮同事排查Tomcat部署问题最大的感慨是大多数诡异问题最后都能归结到三件事环境不一致、日志没看全、路径没对上。JDK版本差了、配置文件改错了位置、war包没更新这类问题占了八成。所以我的习惯是每次部署前先在命令行里确认java -version和echo $CATALINA_HOME部署时永远先停Tomcat再换war包启动后第一件事看catalina.out的末尾而不是直接开浏览器。这套动作看起来笨但稳。最后分享一个我一直在用的小技巧在webapps目录里保留一个bak文件夹每次替换war包前先把旧war包和对应的解压目录改名为带日期的备份比如myapp.war.bak.20250115。这个习惯成本极低但在你需要紧急回滚的时候能救命——所有人都经历过新版本上线后一堆问题、又找不到旧包在哪的窘境。部署这件事稳比快重要有这个备份机制你就能安心地改新版本了。
返回列表