说实话,每次有人拿着IDEA 2024来问我“为什么我新建的Servlet项目总是404,或者Tomcat启动一闪就没”,我都想先让他停下来,把版本和部署方式理清楚。标题里这句话——“从0到1部署Tomcat和添加Servlet”——看着简单,实际涉及JDK、Tomcat、IDEA、Maven、Servlet容器、部署方方式这一整条链路。这篇教程就围绕这套完整流程展开,我会尽可能把每一步背后的逻辑讲透,尤其是IDEA 2024里的新变化和那些容易踩的坑。适合刚学Java Web的初学者,也适合之前只会把war包丢进webapps、却不知道项目在IDE里怎么关联Tomcat的开发者。
1. 项目拆解与整体思路
1.1 这个教程解决什么核心问题
很多人会把“部署Tomcat”理解成“把Tomcat解压出来、双击startup.bat,然后浏览器能打开小猫页”。但实际上,在IDEA 2024里开发Servlet,真正要做的是三件事:准备环境、创建Web项目、把项目挂到Tomcat上跑起来。任何一步没理清,都会让你卡在某个莫名其妙的报错里。
所以这篇教程不只是安装步骤,而是把一个Java Web项目从无到有的完整过程拆解给你看。我会基于一个最简单的需求做演示:浏览器输入一个地址,页面返回“Hello Servlet”。这个需求虽然小,但包含了Web项目结构、Servlet映射、Tomcat运行配置、请求处理这几个核心概念。把这个流程跑通,后面学Spring MVC、Spring Boot都会轻松很多。
1.2 版本选型:为什么Tomcat 9依然值得选
我把推荐版本组合放在下面这张表里,避免你踩“Tomcat 10后包名变了”这种最典型的坑。很多初学者随便下了最新版Tomcat 10或11,然后复制老教程里的javax.servlet.http.HttpServlet,编译直接报错,就是因为Tomcat 10开始已经切换到jakarta.servlet命名空间。
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | JDK 8 或 17 | 两者都行,本文示例使用JDK 17 |
| IDEA | IDEA 2024.x 任意版本 | 社区版也能完成本教程,但Smart Tomcat插件会更好用一点 |
| Tomcat | Tomcat 9.0.x | 稳定、教程多、使用javax.servlet,新手学习最稳妥 |
| Maven | Maven 3.9.x | IDEA 2024兼容性最好,不要用太老的3.5 |
| Servlet API | 4.0.1 | 对应Tomcat 9;如果你非要用Tomcat 10,则改用6.0版本的jakarta.servlet-api |
有人可能会问,为什么不直接上Tomcat 10或Tomcat 11?因为现在的网课、教材、旧项目大多基于Tomcat 8/9,javax.servlet写法更通用。先把这个命理清,以后遇到jakarta.servlet再迁移也容易。学习阶段不是追新版,而是求稳定、求理解。
1.3 部署方案的选型逻辑
Tomcat部署Web项目主要有三种方式:
- 把项目打成war包,直接复制到Tomcat的
webapps目录下; - 在IDEA里配置Tomcat Server,通过Artifact部署war或war exploded;
- 使用Smart Tomcat这类插件,让社区版也能方便部署。
这篇文章重点讲第二种,因为这是IDEA中最标准的方式。第三种会作为社区版用户的替代方案补充。第一种适合生产环境,不适合开发调试,因为你每次改代码都要重新打包,效率太低。
war是Web Application Archive的缩写,相当于一个压缩好的Web应用;war exploded是解压后的目录结构。开发时用exploded更方便,因为Tomcat可以直接读取编译后的classes和资源文件,配合IDEA的热更新开关,改完代码往往不用重启就能生效。这个细节在后面第4部分会再展开。
2. 环境准备与安装细节
2.1 JDK安装与IDEA 2024的关联
第一步不是下Tomcat,而是把JDK装对。IDEA 2024对JDK的识别非常敏感,如果Project SDK没有正确指向JDK,后面会莫名其妙出现“找不到或无法加载主类”之类的错误,虽然这类报错更多出现在Spring Boot项目里,但在Servlet运行时也容易因为编译版本不匹配而出问题。
去Oracle官网或Adoptium下载JDK 17,安装后配置环境变量。我习惯在Windows上设置JAVA_HOME指向JDK安装目录,并在Path里加入%JAVA_HOME%\bin。然后在命令行输入:
java -version能看到类似openjdk version "17.0.x"就说明环境变量生效。IDEA 2024里第一次打开项目时,在File -> Project Structure -> Project里设置SDK为17,语言级别也选17。如果你是JDK 8,语言级别选8。这里重点是保持三个地方一致:Project SDK、Java Compiler的Target bytecode version、Maven的编译器配置,否则编译出来class版本和运行时环境不匹配,Servlet容器启动时容易报各种二进制错误。
2.2 Tomcat下载与目录结构清单
进入Tomcat官网,下载Core分类下的Windows zip包。这里我建议下载Tomcat 9.0.x,解压后放到一个没有空格的路径,比如D:\tomcat-9.0.89。千万别放在C:\Program Files这种带空格的目录下,虽然不是100%出问题,但IDEA关联Tomcat时偶尔会因为路径空格找不到配置。
解压后重点看几个目录:
bin:启动和关闭脚本,Windows下是startup.bat和shutdown.bat;conf:核心配置,其中server.xml控制端口,web.xml是各Web应用的基础映射配置;webapps:存放可部署的Web应用,默认的ROOT目录就是打开首页看到的那个;lib:Tomcat运行依赖的jar包,后面Servlet API其实也包含在这里。
可以先手动双击startup.bat启动一次,看到黑窗口出现“Server startup”,说明Tomcat本身没问题。如果黑窗口一闪而过,大概率是JAVA_HOME没配置好,我后面第5部分还会专门讲。
2.3 Maven安装与IDEA 2024兼容配置
Servlet项目里最简单的做法是手动在WEB-INF/lib里放Servlet-api.jar,但那样既麻烦又容易漏。用Maven管理依赖更干净,所以我们需要把Maven配好。
去Maven官网下载3.9.x版本,解压后配置MAVEN_HOME和Path。然后在Maven的conf/settings.xml里做两件事:第一,设置localRepository为本地仓库路径,比如D:\maven-repo;第二,配置阿里云镜像,让依赖下载速度快一点,不然首次拉取Servlet依赖时可能等半天。
IDEA 2024里打开Settings -> Build, Execution, Deployment -> Build Tools -> Maven,把Maven home path指向本地解压目录,把User settings file指向你刚才修改的settings.xml。IDEA 2024兼容Maven 3.6以上版本,但我还是建议用3.9.x,因为部分3.8旧版在IDEA 2024中会出现配置文件读取异常或依赖树显示不全的问题。
3. 创建一个可部署的Servlet项目
3.1 IDEA 2024中新建Maven项目的关键步骤
打开IDEA 2024,点击New Project,左侧选择“Maven”,这里注意:不需要勾选“Create from archetype”。很多教程会教你选org.apache.maven.archetypes:maven-archetype-webapp,但IDEA 2024创建archetype时网络容易卡住,而且生成出来的目录结构也不是最新规范。我的方法是先建一个纯净的Maven项目,再手动补上Web目录。
创建完成后,默认目录是:
项目根目录/ ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ │ │ └── resources/在src/main下新建webapp目录,再在webapp下新建WEB-INF目录。IDEA会识别这个目录结构,并在项目图标上多出一个蓝色的Web标识。如果你看到webapp没有变成Web资源目录,右键webapp,选择Mark Directory as -> Resources Root也能解决部分问题,更规范的做法是在Facets里配置Web资源路径。
然后给pom.xml加上maven-war-plugin,否则默认打包结果是jar格式,Tomcat无法识别。在<build>节点里添加:
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.4.0</version> </plugin> </plugins>3.2 引入Servlet依赖:javax还是jakarta,这次彻底分清
这是整个教程里最容易踩坑的地方。你在网上搜索Servlet教程,大概率看到“javax.servlet.http.HttpServlet”这种导入,然后照抄到IDEA 2024里却发现找不到类。原因是Tomcat版本变了。
- Tomcat 9及以前:规范属于Java EE,包名是
javax.servlet.*; - Tomcat 10及以后:规范属于Jakarta EE,包名是
jakarta.servlet.*; - IDEA 2024里默认Maven中央仓库能下载到两种依赖,但你必须跟Tomcat版本匹配。
我用Tomcat 9,所以在pom.xml中添加:
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency>scope=provided的意思是编译时需要,但打包时不用包含,因为Tomcat自带了Servlet API。如果你不小心把scope写成compile,war包会把servlet-api.jar也带进去,运行时会和Tomcat自带的类冲突,可能导致一些奇怪的ClassCastException。这个细节很多人不注意,我单独提出来。
3.3 写第一个Servlet:注解方式够用吗
在src/main/java下建一个包,比如com.demo.servlet,然后创建HelloServlet.java。最简洁的写法是用注解@WebServlet:
package com.demo.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/hello") public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); resp.getWriter().write("<h1>Hello Servlet</h1>"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }注解方式省去了web.xml里的映射配置,适合新项目。@WebServlet("/hello")的意思是:这个Servlet响应所有指向/hello的请求。doGet处理GET请求,doPost处理POST请求,我这里让POST也复用GET的逻辑,方便测试。
3.4 传统web.xml方式:理解旧项目还靠它
虽然注解方式好用,但很多公司老项目还在用web.xml维护Servlet映射。我建议你也看一眼传统方式。在webapp/WEB-INF下新建web.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.demo.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>注意:如果你用了注解,又同时在web.xml里配置同一个Servlet,会有冲突。一个新项目建议只挑一种方式。我说“建议”,是因为有些框架或工具会扫描注解,老容器则配置优先。学习阶段,你完全可以用注解,把web.xml保留为一份空模板即可。
4. 把Tomcat挂到IDEA里并启动
4.1 配置本地Tomcat运行环境
这是IDEA专业版里的标准做法。打开顶部运行配置,默认是Current File,点下拉框选“Edit Configurations”,然后点加号,选择“Tomcat Server -> Local”。
此时真机界面会有个Configure按钮,点击后选择你Tomcat解压的目录,比如D:\tomcat-9.0.89。IDEA会识别conf/server.xml,自动填上端口号、HTTP端口等。接着切到Deployment页签,点加号选择“Artifact”,这时你会看到项目生成了两种Artifact:一个是xxx:war,另一个是xxx:war exploded。我建议选择war exploded。
选好后,在右侧把Application context设置为/,这样浏览器直接用http://localhost:8080/hello访问。如果你设置成/demo,访问地址就变成http://localhost:8080/demo/hello。这个“上下文路径”是新手经常搞混的地方。
回到Server页签,可以勾选“After launch”让IDEA启动Tomcat后自动打开浏览器。On frame deactivation建议选择“Update resources”,这样你切换到浏览器时,IDEA会自动把静态资源同步到Tomcat。改Java代码想热加载,就需要在Debug模式下才会更可靠。
4.2 war和war exploded怎么选
war就是一个压缩包。在IDEA里选择war部署时,Tomcat会先把war解压到webapps目录下再运行。每次重新构建都要走压缩、解压两步,慢,而且debug模式下修改代码后同步很别扭。war exploded是解压后的目录,IDEA直接让Tomcat跑这个目录里的class和资源文件,修改后更新速度非常快。开发阶段务必用exploded。
有人担心“我以后生产部署不都是war吗,现在用exploded是不是没意义”?其实生产部署打到war,和开发时用exploded,这两件事不冲突。IDEA里Artifact类型只是开发期打包方式,最终你执行mvn package照样能生成war包。放心用exploded。
4.3 社区版用户怎么办:Smart Tomcat插件
如果你用的是IDEA Community版,会发现运行配置列表里根本没有“Tomcat Server”这个选项。解决方案是装一个插件叫Smart Tomcat。
在Settings -> Plugins里搜索“Smart Tomcat”并安装。重启后打开“Edit Configurations”,点加号,这次能看到“Smart Tomcat”选项。配置界面里的Tomcat Server选择Tomcat主目录,Deployment Directory选择你项目的src/main/webapp,Context Path填/。
可以理解为Smart Tomcat用最简单的方式把webapp目录映射到Tomcat,不需要Artifact概念,也不需要maven-war-plugin参与。它的优势是社区版可用,缺点是热部署能力没有专业版强。但对学习Servlet来说完全够了。
4.4 启动后访问地址的完整组成
点击运行按钮,控制台输出started on port 8080后,浏览器访问:
http://localhost:8080/hello其中localhost:8080是Tomcat监听地址,/hello是Servlet映射路径。如果你的Application context设置成了/demo,那完整地址就是:
http://localhost:8080/demo/hellocontext path决定你的Web应用挂载在根路径的哪个目录下,servlet path决定具体由哪个Servlet来处理。这两层路径加在一起才是最终URL。很多404问题就出在这里:明明Servlet映射是/hello,但Application context设成了别的,或者访问时多打了一个斜杠,都会找不到。
5. 典型报错排查与技术要点
5.1 Tomcat启动成功,但Servlet访问404
这个问题最常见,基本是路径没有对齐。你可以按以下顺序排查:
- 看IDEA的Deployment配置里Artifact有没有加进去;
- 看Application context是不是
/,或者你是不是按这个路径拼URL; - 看Servlet注解或web.xml中的
url-pattern是否是/hello,前后有没有多空格; - 看IDEA控制台有没有包含“Deployment ... has finished”这类输出,如果Deployment没有完成,Tomcat根本没加载你的项目。
还有个小技巧:启动后直接查看Tomcat的webapps目录,如果用exploded方式,里面应该多出一个应用目录,如果你没看到,说明部署配置没生效。
5.2 Tomcat端口被占用
启动时报错:
Port 8080 was already in use.这种最直接的办法是找出占用进程。Windows下用命令:
netstat -ano | findstr 8080看到最后一列是PID,再用:
taskkill /F /PID 对应PID杀掉进程,或者直接修改Tomcat端口号。修改位置在conf/server.xml里的<Connector port="8080" protocol="HTTP/1.1"...>,把8080改成8081或9090。改完后IDEA的Tomcat配置会自动检测到,如果没检测到,重启IDEA或重新选择Tomcat目录。
5.3 Servlet类找不到:ClassNotFound和NoClassDefFoundError
如果你在运行时看到:
java.lang.ClassNotFoundException: com.demo.servlet.HelloServlet第一反应不是代码写错了,而是编译产物没进到Tomcat的部署路径里。解决方法是执行一次Build -> Build Artifacts -> Exploded,然后刷新浏览器。IDEA里Artifact不会自动实时编译,尤其在你手动改过源码后,有时候必须右键项目选择“Rebuild”,才能把最新的class生成到WEB-INF/classes下。
另一种情况是java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet,这说明项目里的servlet-api包没有正确进入运行时。最常见原因是依赖的scope不对,或者同一环境里存在多个Servlet API版本。检查pom.xml里是否只有一份依赖,scope是否为provided,然后执行mvn clean package,再重启Tomcat。
5.4 Tomcat启动一闪而过
如果你是在IDEA之外手动启动Tomcat,双击startup.bat黑窗口一闪就消失,基本可以确定是JAVA_HOME没有配置。Tomcat的启动脚本依赖JAVA_HOME环境变量去找java.exe,找不到就直接退出。
解决方法是确认环境变量里有没有JAVA_HOME,并且它指向的是JDK目录,不是JRE目录。配置好后再开一个新命令行窗口执行startup.bat,注意必须是新窗口,因为环境变量改了不会自动同步到已打开的窗口。启动成功后你会在窗口里看到类似:
[Tomcat] catalina.startup.Catalina.start Server startup in [xxx] milliseconds5.5 IDEA 2024运行卡顿或内存溢出
IDEA 2024本身比较吃内存,如果电脑配置一般,跑Tomcat + 项目后会明显卡顿。很多人的第一反应是换电脑,其实先改IDEA堆内存设置更实际。
在IDEA里按Ctrl+Shift+A,搜索“Change Memory Settings”,把堆内存调整到2048MB或更高。如果你电脑内存是16GB,建议设到4GB。还需要在Help -> Edit Custom VM Options里增加参数:
-Xms1024m -Xmx4096m -XX:ReservedCodeCacheSize=512m改完后重启IDEA。另外,IDEA默认会索引大量文件,排除不需要的目录可以显著提速:在Settings -> Directories里,把node_modules、target等目录标记为“Excluded”或“Resources”,不参与代码搜索和索引。
5.6 一个容易被忽略的问题:IDEA 2024与Maven的版本联动
IDEA 2024里面自带Maven,但如果你使用全局Maven与内置Maven版本冲突,经常出现“依赖已下载但IDEA识别不到”的诡异问题。我的经验是:统一使用你自己下载的Maven 3.9.x,然后在IDEA的Maven设置里关闭“Use Maven wrapper”,并确保“User settings file”指向本地配置文件。如果项目已经因为之前的错误配置产生了缓存,执行干净操作:
mvn clean再在IDEA侧点击Maven面板右上角的“Reload All Projects”。这种重置方式能解决很多依赖相关的小毛病。
6. 从Servlet出发,理解Java Web请求全流程
6.1 一个请求进来后,Tomcat到底做了什么
虽然这篇教程只写了一个最简单的Servlet,但它背后是整个Java Web处理链路的基础。输入http://localhost:8080/demo/hello后,浏览器把请求发送到8080端口,Tomcat收到后,会根据URL中的demo找到对应的Web应用,再根据/hello映射到HelloServlet这个类。
Tomcat内部会维护一个ServletContext,你可以把它理解为整个Web应用的大环境。Servlet的实例由容器管理,第一次请求时创建,之后复用单例对象。每次请求到达,容器封装出HttpServletRequest和HttpServletResponse对象,调用Servlet的service方法,service方法再根据HTTP方法类型调用对应的doGet或doPost。等Servlet处理完,把响应内容写进Response对象,容器负责把它发回浏览器。
理解这个链路,你就明白为什么Servlet类通常不需要你自己new,也不需要你手动关闭资源。容器把这些生命周期全管起来了。
6.2 后端框架做了那么多事,Servlet还有必要学吗
现在很多初学者上来就是Spring Boot,很少直接碰Servlet。但Spring Boot内置的Tomcat底层,以及Spring MVC入口DispatcherServlet,本质上就是一个Servlet。你写的Controller方法最终都是被这个总Servlet分发处理的。
所以我一直觉得,学Servlet不是让你以后写extends HttpServlet的代码,而是让你理解Java Web最底层的请求响应机制。你能分清楚context path、servlet path、DispatcherServlet和Root WebApplicationContext的关系后,再去看Spring MVC的请求流程会豁然开朗。这也是我在这个教程里反复强调“别急着跳到框架”的原因。
6.3 最后分享一个提高调试效率的小习惯
在IDEA里,我强烈建议你在Debug模式下运行Tomcat,而不是Run。第一次启动时,选择Debug按钮,然后在Run -> Edit Configurations里,把On frame deactivation设为Update resources。这样每次你切换到浏览器,IDEA会自动把webapp下修改过的静态资源和JSP同步给Tomcat,不用手动点更新按钮。
如果你改了Java代码,可以在Debug模式下点击Build -> Recompile(只编译当前文件),或者直接在Tomcat控制台左侧的“Update”按钮上选择Update classes and resources。大多数情况下,Servlet类改完也能实现准热部署,只有改web.xml、新增Servlet类这种结构性变化,才需要重启Tomcat。把这一步养成习惯,开发效率会高很多。
这个教程从环境版本选型,讲到创建Servlet项目,再讲到IDEA 2024里挂载和启动Tomcat,最后整理了常见报错。整个过程是我自己在学习和指导别人时反复走过的路径,细节上尽量说得直白。如果你按照这个顺序操作,应该能在半小时内看到浏览器里的“Hello Servlet”。之后无论你是继续写原生Servlet,还是进入Spring生态,至少部署这条路上的坑,已经提前排掉大半了。