IDEA 2024 配置 Tomcat 与 Servlet 全攻略:从版本选型到部署运行 第一次接触 Tomcat 和 Servlet很多人都会在 IDEA 里兜圈子代码明明照着写了点运行却跳出 404或者明明用的是老教程放进新版 IDEA 却直接编译失败。 这类事情我前前后后折腾过很多回每次帮朋友排查最后几乎都会落到同一个原因IDEA 2024 这个版本默认环境和老的 Tomcat 9 javax.servlet 教程完全是两套逻辑。 如果你也卡在“部署完访问不到”“Servlet 找不到类”这一步这篇应该能帮你把从建项目到配服务器的整条路走通一遍。这篇内容适合刚学 Java Web、第一次用 IDEA 建动态 Web 项目、或者以前用过 Eclipse / 老版本 IDEA 想切到最新版的人。我会把版本选型、建项目、写 Servlet、连 Tomcat、部署运行、报错排查这几个环节串在一篇文章里写好重点说清楚为什么这么做而不只是给一串点击步骤。1. 环境准备与版本选型这一步错了后面全白搭1.1 为什么 IDEA 2024 里的坑和以前不一样用 IDEA 2024 和网上大量旧教程碰到的最大的差异出在 Servlet API 的命名空间上。 Tomcat 9 及更早版本用的是javax.servlet但从 Tomcat 10 开始官方把包名改成了jakarta.servlet。IDEA 2024 新建项目时默认引用的组件、以及你手工下载当前版 Tomcat 时拿到的几乎都是 Tomcat 10.1 或更高版本于是老代码里的import javax.servlet.http.HttpServlet就会直接标红或者在部署时抛NoClassDefFoundError。我实际推荐两种最稳妥的组合二选一组合JDKTomcat 版本Servlet 依赖包名适用场景保守方案JDK 8 或 JDK 11Tomcat 9.xjavax.servlet-api跟着老教材学公司老项目维护主流方案JDK 17Tomcat 10.1.xjakarta.servlet-apiIDEA 2024 默认环境推荐新手我自己现在默认走的是第二种也就是 JDK 17 Tomcat 10.1 jakarta.servlet-api。不是因为它比老的先进多少而是 IDEA 2024 对这套组合识别得最顺Maven 创建项目时不会因为包名不一致报一堆红线。如果你手头已经有 Tomcat 9那把依赖换成javax.servlet-api也完全没问题下面的步骤全部通用只有 import 的包名前缀不一样。1.2 JDK 与 Tomcat 到底要不要配环境变量很多教程第一步就让你去系统里设置JAVA_HOME和CATALINA_HOME。如果你只是在 IDEA 里跑本地开发这一步我建议跳过不要配。 IDEA 自己会识别它内置的 JBR 运行时也可以直接用你在 Project Structure 里指定的 JDK不需要在系统层面做任何干预。 反倒是你手动改了全局环境变量很可能和 IDEA 自带的 JDK 版本冲突出现“IDEA 里能编译命令行启动 Tomcat 却报版本错误”的怪问题。真正要用到的是你在创建项目时Project SDK 明确选择成你安装的 JDK然后在 Tomcat 的配置界面里确认所选 JDK 和项目一致。这比设什么环境变量都实在。如果你一定要在命令行里验证一下环境可以执行下面两条命令看到版本号就说明没问题java -versionTomcat 本身也不需要手动设置 CATALINA_HOMEIDEA 配置 Tomcat Server 的时候只需要指定 Tomcat 安装目录它自己会去找里面的bin/catalina.bat。2. 在 IDEA 2024 里创建 Web 工程别用错了模板2.1 为什么优先用 Maven 生成项目我见过不少朋友建 Java Web 项目是直接在 IDEA 里选Java Enterprise或者手动创建目录再补web文件夹。不是说不能用而是 IDEA 2024 里新建 Maven 项目最省事依赖管理清晰打包 war 也简单后面部署的时候能少踩一堆坑。 Maven 会帮你自动建出标准的src/main/java、src/main/resources和src/main/webapp结构你不用自己记哪里该放代码、哪里该放页面。实际操作流程是打开 IDEA选择New Project左侧选Generators里的Maven。设置好项目名。Project SDK 选 JDK 17。不要勾选模板里的任何骨架比如maven-archetype-webappIDEA 2024 生成的普通 Maven 项目反而够干净。创建完成后手工在src/main下新建webapp目录这就是之后放 JSP、HTML、静态资源的地方。这样得到的项目结构如下项目根目录 ├── pom.xml └── src └── main ├── java ├── resources └── webapp如果你已经建好了一个 Maven 项目也不用推翻重来直接在 Project Structure 里给模块添加一个 Web Facet再把 Web Resource Directory 指向src/main/webapp效果一样。只是对新手而言直接在创建时规划好更不容易漏。2.2 pom.xml 里的 Servlet 依赖照着抄也得看版本建好 Maven 项目后第一件事是把pom.xml里的依赖加上。下面这段是 Tomcat 10.1 对应的 Servlet 6.0 依赖dependencies dependency groupIdjakarta.servlet/groupId artifactIdjakarta.servlet-api/artifactId version6.0.0/version scopeprovided/scope /dependency /dependencies如果你用的是 Tomcat 9把这段换成dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency这里的scopeprovided/scope很关键。它的意思是编译的时候用这份依赖但最后打成 war 包时不要把它打进去。因为 Tomcat 自己本来就带了一套 Servlet 实现你再塞一份进去启动时反而可能因为 jar 包冲突报各种奇怪错误。 不少新手就是漏了这一步部署后 Tomcat 一启动就报ClassCastException或者LinkageError原因就是 lib 里放了多份 Servlet API。2.3 约定优于配置用 WebServlet 注解代替 web.xml以前写 Servlet 都要在web.xml里手动配置servlet和servlet-mapping一个类一行配置类一多就长到没法看。Servlet 3.0 之后引入了注解WebServlet可以直接写在类上省掉 web.xml 的重复劳动。IDEA 2024 里新建项目默认是支持注解扫描的所以你只需要在类上写好 URL 映射不用再手动维护 web.xml。我这里明确一点只要你没在项目中创建web.xmlTomcat 就会自动扫描WebServlet 如果你保留了 web.xml而且里面连 content 版本都没写对反而可能拦截扫描导致你的注解不生效。 这个细节我栽过一次项目里有个历史遗留的空 web.xml结果加了注解的新 Servlet 怎么访问都是 404最后把 web.xml 删掉就好了。3. 第一个 Servlet从写代码到请求被正确处理3.1 用代码理解 Servlet 生命周期Servlet 说白了就是一个能处理 HTTP 请求的 Java 类。它本身没有 main 方法Tomcat 负责创建它的实例并在合适的时机调用它的init、service、destroy这些方法。 你可以把它理解成 Tomcat 给你提供的服务员模板你负责写清楚“收到请求后该干什么”Tomcat 负责把客人领到你面前。一个最小可用的 Servlet 长这样import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.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;charsetUTF-8); resp.getWriter().write(h1Hello, Servlet!/h1); } }新建类的时候注意jakarta.servlet开头确认和 pom 里的依赖一致。写完这个类之后Maven 会自动编译IDEA 里如果没有红线就可以进入部署环节了。3.2 GET 和 POST 请求的分流处理HttpServlet父类已经在底层帮你做好了service方法的路由根据 HTTP 请求的 method 自动调doGet或doPost。你在子类里重写哪个方法就代表处理哪种请求。一个最典型的场景浏览器直接在地址栏输入 URL 访问是 GET表单直接提交也是 GET。而用 POST 提交一般是为了传数据比如登录、注册、上传。 新手容易犯的错是 HTML 表单设置了methodpost后端却只写了doGet结果点击提交后收到的要么是 405 错误要么是空白页。建议你一上来就把两个方法都写上哪怕是先写在同一套处理逻辑里Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { process(req, resp); } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { process(req, resp); } private void process(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setContentType(text/html;charsetUTF-8); String name req.getParameter(name); resp.getWriter().write(收到的 name 是 name); }这样不管 GET 还是 POST 都能跑到同一个业务方法排查问题范围更小也不容易因为方法漏写出现 405。3.3 请求参数怎么拿响应中文怎么不乱码拿到 URL 里的参数通常用req.getParameter(参数名)这个方法同时兼容 GET 的 query string 和 POST 的 form body。 但如果你用 POST 提交中文不设置编码很容易出现乱码。正确做法是在读取任何参数之前先设置req.setCharacterEncoding(UTF-8);响应的中文乱码则是另一回事必须设置响应类型也就是resp.setContentType(text/html;charsetUTF-8)。我见过有人只在 resp 里设置了编码却在 req 里忘了设置导致“请求中文乱响应中文正常”的情况。 两个地方都要设置不要偷懒只写一处。下表可以当成速查情况设置位置代码表单提交中文变乱码读取参数前req.setCharacterEncoding(UTF-8)页面输出中文变乱码获取 Writer 前resp.setContentType(text/html;charsetUTF-8)4. 在 IDEA 2024 里连接 Tomcat 并启动部署4.1 配置 Tomcat Server 的完整路径写好了代码接下来就是把项目“接”到 Tomcat 上跑起来。IDEA 里这一步叫Run/Debug Configurations快捷键可以直接用右上角的服务器下拉框选Edit Configurations。点击左上角加号找到Tomcat Server - Local。如果你是第一次配置IDEA 会要求你指定Tomcat Home或者Application server路径直接选到你解压 Tomcat 的目录比如D:\apache-tomcat-10.1.28。IDEA 会自动识别版本。这里有一个重点新添加的配置里面不会帮你自动部署项目。你必须在Deployment选项卡里加一个 Artifact否则运行的时候 Tomcat 是起来了但访问你的项目路径只会看到 Tomcat 的默认首页或者 404。4.2 选择 war 还是 war exploded在 Deployment 选项卡里点击加号Artifact下通常会出现两个选择项目名:war和项目名:war exploded。war把整个项目打包成一个 war 文件再复制到 Tomcat 的 webapps 目录下解压运行。它更接近真实部署但修改代码后需要重新打包速度慢。war exploded把项目按解压后的目录结构直接当作 Web 应用来跑修改静态页面和 Java 代码后经常能实现热更新开发时更方便。我本地开发一律选war exploded迭代速度快很多。 尤其是你改一个 JSP 或者静态资源有时候连重启都不用刷新页面就能看到效果。添加好后下面会有一个Application context输入框默认是/项目名。 这个路径决定了你访问应用的前缀比如项目名是demo那你访问的完整地址就是http://localhost:8080/demo/hello前缀路径经常是新手找不到 Servlet 的主要原因只记得/hello忘了前面还要带/项目名。 你把它改成/也可以这样访问时就变成http://localhost:8080/hello但一般不建议因为一个 Tomcat 实例跑多个项目时容易冲突。4.3 运行前检查端口和 provided 依赖配置好之后一般不建议直接点运行先检查三件事Tomcat 默认端口是不是 8080是否已经被占用。 如果 8080 被别的进程占用了有两个办法换端口或者杀掉占用进程。换端口最快在Server选项卡里找到HTTP port改成8081。杀占用进程的办法我放在后面常见问题里写。部署项目的 URL 路径里有没有 application context。确认 pom 里的 Servlet 依赖 scope 还是 provided。 如果之前误写成了 compile运行后很可能在 Tomcat 的 lib 下出现重复的 Servlet jar。点运行之后IDEA 下方会跳出一个 Tomcat 的日志窗口。看到类似下面的日志就说明启动成功了Server startup in [xxx] milliseconds这时候打开浏览器访问 http://localhost:8080/demo/hello 如果页面出现“Hello, Servlet!”第一个 Servlet 就跑通了。 如果没出来也别急着改代码先去看日志里的关键字绝大部分问题都能在日志里找到答案。5. 运行阶段的常见报错与排查思路5.1 访问 404先区分是哪个层级的 404看到 404 是最容易慌的但其实只要分清“Tomcat 都起来了只是应用没找到”和“应用找到了Servlet 路径没匹配上”这两种情况处理起来就清晰了。先访问http://localhost:8080如果能看到 Tomcat 默认首页说明服务器本身没问题。再访问http://localhost:8080/demo/如果能出现项目下的 index.jsp 或目录列表说明项目部署成功问题在 Servlet 的路径映射上。 如果连/demo/都 404那就是 Deployment 的 Application context 和你输入的路径不一致或者 Artifact 没有正确添加。常见对应关系如下访问结果大概原因处理方向8080 正常/demo404应用没部署或 context 对不上检查 Deployment 里的 Artifact 和 Application context/demo正常/demo/hello404注解映射路径不对检查WebServlet(/hello)是否写成/hello.do或漏了斜杠所有路径都 404 且日志无异常web.xml 干扰了注解扫描删除或清空 web.xml5.2 500 和 NoClassDefFoundError多半是包名或依赖冲突如果你启动时报的是NoClassDefFoundError: javax/servlet/...那么原因基本可以锁定为你用的 Tomcat 是 10 以上版本但代码里引用的是javax.servlet。 反过来如果你用的 Tomcat 9但依赖引的是jakarta.servlet同样地址找不到类。遇到这个别去改代码硬凑先确认组合是不是一致。 简单判断方式就是看 import 语句的前缀Tomcat 10.1 jakarta.servlet.http.HttpServletTomcat 9 javax.servlet.http.HttpServlet两个前缀混用就会出现编译时好好的、运行时发现 Tomcat 的类加载器里根本没有对应类的情况。 这类错误日志通常会显示Caused by: java.lang.ClassNotFoundException顺着 Caused by 看最快。5.3 端口被占用怎么快速定位和释放IDEA 启动 Tomcat 时经常报这样的错误Port 8080 was already in use. Tomcat cannot be started.原因大概率是你之前启动过另一个 Tomcat 实例没关干净或者别的程序占了 8080。 在命令行里执行下面两条命令就能查到谁在用这个端口netstat -ano | findstr 8080找到 PID 后用任务管理器结束对应进程或者用命令taskkill /pid 进程号 /f如果你还在用 Mac 或 Linux可以用lsof -i:8080查看然后用kill -9 进程号结束。 要是你不想跟别人抢端口省事的办法是在 Tomcat 配置里把 HTTP port 改成 8081重启就行。 我自己的习惯是如果这个端口以后要跑别的服务就先找出进程杀掉如果是自己本地练习直接换端口也不丢人。5.4 改了代码却看不到效果多半是热部署没生效IDEA 的war exploded虽然支持热部署但默认设置不一定开全。 如果你改了 Servlet 代码后重新请求还是旧结果先看控制台有没有重新编译的日志。 如果没动静可以手动在Build - Rebuild Project强制重新编译一下再访问页面。如果你想尽量接近“改完就生效”可以在这个运行配置的Server选项卡里把On frame deactivation设置成Update classes and resources。 这样你从 IDEA 切回浏览器时IDEA 会自动把更新的 class 和静态资源同步到 Tomcat 的部署目录。 不过改类名、改方法签名这类结构级改动还是建议直接重启 Tomcat因为热部署遇到类结构变化时容易出现内存里残留旧类行为变得诡异。个人经验是页面样式、JSP、简单的返回值改动交给热部署没问题一旦要加变量、改函数签名果断重启省下的时间比等热部署出问题后再排查多得多。写到这里最基本的 Tomcat 部署和第一个 Servlet 应该能跑通了。再顺手补充一个我常用的习惯每次启动前看日志的时候别只盯着红色 ERROR 那几行重点是Caused by后面跟的内容。 很多新手喜欢只看最上面的红色段落结果问题根源在日志中间一看日志长度就放弃了。 Tomcat 给的报错其实已经一步步把原因写在里面了顺着Caused by逐层往下基本都能找到真正的问题出在哪个 jar、哪个类、哪一行。另外后续如果你想接着往下扩展可以顺手在同一个项目里加几个普通的 HTML 页面再试着用表单 POST 到同一个 Servlet体验一下 GET/POST 的分发逻辑。第一次可以慢点来但把日志和请求路径看明白后面加拦截器、过滤器、数据库连接的时候就会顺很多。