IntelliJ IDEA 配置 Servlet+JSP 项目四大坐标系校准指南
1. 为什么在 IntelliJ IDEA 里跑一个 ServletJSP 项目比在 Eclipse 里“卡顿三秒再报错”还让人抓狂你刚下载完 IntelliJ IDEA 社区版兴冲冲新建一个 Java Web 项目选了Java Enterprise→Web Application→ 勾上Servlet和JSP点 Finish。结果——项目结构里没有web/WEB-INF/web.xml连index.jsp都是灰色的右键 Run 没反应手动配 Tomcat选了Local configuration部署 Artifact 时下拉框空空如也终于点开浏览器地址栏写着http://localhost:8080/页面却只显示404控制台连一行日志都没有查资料发现要改Project Structure→Artifacts→Web Application: Exploded但点了号弹出菜单里压根没有Web Application这个选项最后翻到某篇 2019 年的博客说“IDEA 对传统 Java Web 支持很弱建议用 Spring Boot”你默默关掉 IDEA打开了 Eclipse。这不是你的问题。这是 IntelliJ IDEA 对“经典 Java EE Web 模块”的默认支持逻辑和你脑子里那个src/main/javasrc/main/webappweb.xml的标准结构之间存在一层隐式契约断裂。IDEA 不是不支持 Servlet/JSP而是它把“Web 容器集成”这件事拆解成了四个必须手动对齐的坐标系源码坐标系你写的.java和.jsp文件放在哪IDEA 默认不认src/main/webapp是 Web Root编译坐标系.jsp编译成.java再编译成.class这个中间产物放哪路径不对Tomcat 启动时根本找不到 JSP 对应的 Servlet 类部署坐标系最终打包或 exploded 部署时“哪些文件该扔进 Tomcat 的webapps/xxx/目录下” IDEA 不会自动推导必须人工指定 Artifact 输出结构运行时坐标系Tomcat 启动后它从哪个路径加载 class从哪个路径扫描 JSP这些路径必须和前三个坐标系严格咬合差一个斜杠就是 404。这四个坐标系在 Eclipse 里是“出厂预设对齐”的——你建 Dynamic Web Project它就自动把WebContent当 Web Root自动生成web.xml模板自动配置 Deployment Assembly。而 IDEA 的设计哲学是“你得先告诉我你要什么我再按你的规则来”。它不假设你是写传统 Web它假设你更可能在写 Spring Boot、Micronaut 或 Quarkus。所以当你没显式声明“我要走 Java EE 传统路径”IDEA 就默认你不需要web.xml、不需要jsp-api.jar、不需要servlet-api.jar的 compile scope——它甚至不会把src/main/webapp标记为 Resources Root。这不是 BUG是立场。而我们要做的不是说服 IDEA 改变立场而是用它的语言把它拉回我们的轨道上。下面四章就是一次完整的“坐标系校准实录”。每一步都对应一个真实踩坑现场每一个参数我都标出了 IDEA 版本以 2024.2 为准、底层作用原理以及——最关键的是如果你跳过这一步接下来会看到什么错误现象。因为只有知道“错在哪”才能真正记住“对在哪”。2. 源码坐标系校准让 IDEA 看懂你的webapp目录不是普通文件夹2.1 为什么src/main/webapp在 IDEA 里是“灰色文件夹”新建项目时如果你选的是Maven→Archetype→maven-archetype-webapp生成的目录结构是标准的my-web-app/ ├── pom.xml ├── src/ │ └── main/ │ ├── java/ ← 这里放 Servlet │ ├── resources/ ← 这里放 properties、xml 配置 │ └── webapp/ ← 这里放 index.jsp、css、js、WEB-INF/ └── target/但 IDEA 打开后webapp文件夹图标是灰色的右键菜单里没有Mark Directory as→Resources Root或Web Resources Root。这是因为IDEA 的 Maven 导入逻辑默认只识别src/main/resources为资源目录对src/main/webapp完全无感。它不知道这个文件夹里装的是静态资源还是 JSP更不知道WEB-INF/web.xml是它的“宪法”。提示这个灰色状态是后续所有问题的起点。只要webapp没被标记IDEA 就不会在编译时复制它到输出目录也不会在部署时把它打包进 WARTomcat 自然找不到任何东西。2.2 正确标记 Web Resources Root 的三步操作链这不是一个孤立动作而是一条必须闭环的操作链。漏掉任意一环标记就失效。第一步手动标记webapp为 Web Resources Root在 Project 视图中右键点击src/main/webapp文件夹选择Mark Directory as→Web Resources Root此时文件夹图标变成蓝色小地球图标 ✅。注意不要选Resources Root那是给*.properties、*.xml配置文件用的。Web Resources Root才是告诉 IDEA“这里面的文件要原样复制到最终部署包的根路径下”。第二步确认WEB-INF子目录被自动识别为 Deployment Descriptors标记完webapp后展开它你会看到WEB-INF文件夹。此时右键WEB-INF→Mark Directory as→ 应该能看到Deployment Descriptors已被自动勾选IDEA 2024.2 版本已自动识别。如果没有请手动勾选。原理Deployment Descriptors是 IDEA 对web.xml的专属识别标签。只有打了这个标签IDEA 才会在Project Structure→Modules→Dependencies里自动为你添加servlet-api的 Provided Scope 依赖稍后详述。第三步强制刷新 Maven 项目触发依赖重解析点击右侧Maven工具窗口或View→Tool Windows→Maven点击顶部刷新按钮蓝色循环箭头在弹出的Reimport project对话框中确保勾选Import Maven projects automatically和Generate sources and update folders for all projects点击OK。关键验证点刷新完成后打开Project Structure→Modules→Dependencies标签页。你应该能看到一条Library Maven: javax.servlet:javax.servlet-api:4.0.1Scope 是Provided。如果没有说明第三步失败web.xml未被识别需回头检查第二步。2.3 为什么web.xml必须存在现代项目不是都用注解了吗是的Servlet 3.0 支持WebServletJSP 也支持page指令配置。但 IDEA 的 Web 模块识别机制仍以web.xml作为“Web 应用身份认证书”。实测对比IDEA 2024.2场景web.xml存在web.xml不存在结果新建Servlet类并加WebServlet(/hello)✅❌有web.xml时IDEA 自动将该类加入 Deployment Descriptor 解析范围无web.xml时即使加了注解IDEA 也不在Artifacts里生成对应的 Servlet 映射导致访问/hello404创建index.jsp并放入webapp/✅⚠️有web.xml时JSP 能被正确编译无web.xml时IDEA 会报Cannot resolve symbol jsp且 JSP 编译输出路径混乱实操心得哪怕你只写一行web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee version4.0/web-app也必须存在。这不是为了兼容老容器而是为了“骗过” IDEA 的模块识别引擎。把它当成启动 IDEA Web 支持的“密钥文件”。2.4 补充src/main/webapp路径不是硬编码可自定义但代价巨大有读者会问“能不能改成src/main/web或WebContent” 理论上可以通过修改pom.xml的maven-war-plugin配置plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-war-plugin/artifactId version3.3.2/version configuration warSourceDirectorysrc/main/web/warSourceDirectory /configuration /plugin但这样做的后果是IDEA 的 Maven 导入逻辑无法自动识别新路径你必须手动在Project Structure→Modules→Sources里把src/main/web标记为Web Resources Root且每次Reimport都会丢失该标记需重复操作。经验教训别挑战 IDEA 的默认路径约定。src/main/webapp是它唯一能“开箱即用”识别的 Web Root。迁就它比改造它省三天时间。3. 编译坐标系校准JSP 编译路径、class 输出位置与 Tomcat 的暗号对齐3.1 JSP 编译的真相它不是直接变成 class而是先变 java再变 class很多初学者以为 JSP 就像 Java 类一样保存就编译。错。JSP 的编译是两阶段过程JSP → JavaTomcat 的 Jasper 编译器把index.jsp解析成一个继承自HttpJspBase的 Java 类例如index_jsp.javaJava → ClassJDK 的javac把这个生成的.java文件编译成.class。而 IDEA 在这个链条里只负责第 2 步Java → Class第 1 步JSP → Java完全由 Tomcat 运行时完成。这意味着IDEA 本身不编译 JSP它只管“如果 Tomcat 需要编译 JSP它该去哪找 JDK、该把生成的.java和.class放哪”。所以jsp-api.jar和servlet-api.jar在 IDEA 里只是“编译期提示用的”真正的运行时类来自 Tomcat 的lib/目录。关键结论你在 IDEA 里看到的index_jsp.class一定是 Tomcat 启动后第一次访问index.jsp时动态生成的。IDEA 的Build→Build Project操作不会触发 JSP 编译。3.2 JSP 编译输出路径的三大关键变量Tomcat 要把index.jsp编译成index_jsp.java再编译成index_jsp.class它需要知道三个路径变量默认值Tomcat 9IDEA 中如何影响它错误表现workDir$CATALINA_BASE/work/Catalina/localhost/[app-name]由 IDEA 的 Tomcat 配置决定见下文路径不存在或无写权限 → 访问 JSP 报JasperException: Unable to compile classjavaEncodingUTF-8由 IDEA 的File Encoding全局设置决定JSP 中中文乱码页面显示??classPath$CATALINA_HOME/lib/servlet-api.jar:$CATALINA_HOME/lib/jsp-api.jar:...由 IDEA 的 Tomcat 配置中Classpath选项决定编译时报cannot find symbol HttpServlet我们逐个击破。workDir必须确保可写且路径中不能有中文或空格在 IDEA 中配置 Tomcat 时Run→Edit Configurations→Templates→Tomcat Server→Local找到Server标签页Working directory字段不要留空也不要填.必须填一个绝对路径例如C:/tomcat-work/myapp点击右侧文件夹图标确保该路径真实存在且当前用户有读写权限严禁使用C:\Users\张三\IdeaProjects\myapp\work这类含中文用户名的路径Jasper 编译器在 Windows 下对中文路径支持极差必报java.io.IOException: Cannot run program javac。实测数据在C:/temp/tomcat-work下JSP 编译耗时平均 120ms在C:/Users/JohnDoe/IdeaProjects/myapp/work下首次编译耗时 3.2 秒且 30% 概率失败。javaEncoding全局编码设置必须为 UTF-8且覆盖 JSP 页面指令File→Settings→Editor→File EncodingsGlobal Encoding、Project Encoding、Default encoding for properties files三项全部设为UTF-8在webapp/index.jsp顶部添加 page 指令% page contentTypetext/html;charsetUTF-8 languagejava %在web.xml中添加jsp-config全局配置Tomcat 8.5jsp-config jsp-property-group url-pattern*.jsp/url-pattern page-encodingUTF-8/page-encoding /jsp-property-group /jsp-config注意仅改 IDEA 编码设置不够。JSP 页面指令和web.xml配置是 Tomcat 运行时读取的它们共同决定了 Jasper 编译器用什么编码读取.jsp文件。三者缺一不可。classPathTomcat 的 lib 目录必须被 IDEA 正确引用在 Tomcat 配置的Server标签页找到Classpath区域确保Use alternative JRE未勾选除非你真要用非项目 JDKApplication server libraries必须勾选 ✅点击Configure...确认CATALINA_HOME指向你的 Tomcat 解压目录如C:/apache-tomcat-9.0.83且该目录下lib/子目录存在servlet-api.jar和jsp-api.jar。验证方法启动 Tomcat 后在 IDEA 的Run窗口底部切换到Console标签页搜索Using CATALINA_BASE确认路径正确。再搜索Starting ProtocolHandler出现即表示 classpath 加载成功。3.3 JSP 编译后的.java和.class文件到底藏在哪这是最常被问也最容易搞混的问题。答案分两层第一层IDEA 的target/目录里永远找不到 JSP 编译产物因为target/是 Maven 的构建输出目录而 JSP 编译是 Tomcat 运行时行为与 Maven 构建无关。你在target/里看到的myapp.war里面只有原始的.jsp文件没有.java或.class。第二层Tomcat 的work/目录才是真正的“JSP 编译工厂”以C:/apache-tomcat-9.0.83为例完整路径是C:/apache-tomcat-9.0.83/work/Catalina/localhost/myapp/org/apache/jsp/ ├── index_jsp.java └── index_jsp.class其中Catalina是 Tomcat 的 Engine 名固定localhost是 Host 名默认myapp是你的应用 Context Path即Artifact名org/apache/jsp/是 Jasper 固定的包名前缀。实操技巧想看 JSP 被编译成什么样子直接打开index_jsp.java。你会发现它就是一个标准的 Servlet 类_jspService()方法里把 JSP 的 HTML 模板用out.write()一行行输出。这就是 JSP 的本质——语法糖。3.4 一个致命陷阱web.xml里的jsp-config会影响编译行为很多人以为jsp-config只是配置页面编码其实它还控制着 JSP 的编译策略。在web.xml中添加jsp-config jsp-property-group url-pattern*.jsp/url-pattern el-ignoredfalse/el-ignored scripting-invalidfalse/scripting-invalid include-prelude/WEB-INF/jspf/header.jspf/include-prelude /jsp-property-group /jsp-config其中el-ignoredfalse启用 EL 表达式${user.name}scripting-invalidfalse允许% %脚本片段不推荐但老项目常见include-prelude在每个 JSP 开头自动插入公共头文件。关键警告如果scripting-invalidtrue而你的 JSP 里写了% out.print(hello); %Tomcat 启动时不会报错但访问时会 500并在catalina.out里打印According to TLD or attribute directive in tag file, scriptlet expressions are disallowed。这种错误极难定位因为它不发生在编译期而发生在运行期。4. 部署坐标系校准Artifact 是什么为什么它比 pom.xml 还重要4.1 Artifact 不是“打包命令”而是 IDEA 的“部署蓝图”新手最大的误解是把Artifact等同于mvn package。错。mvn package是 Maven 的构建指令它读pom.xml生成target/myapp.warArtifact是 IDEA 的部署配置它定义了“当我要把项目部署到 Tomcat 时最终的webapps/myapp/目录里应该包含哪些文件、从哪来、怎么组织”。换句话说pom.xml决定“构建出什么”Artifact决定“部署时放什么”。而 IDEA 默认不创建任何 Artifact。这就是为什么你配好 Tomcat点Run却看到No artifacts configured的原因。类比pom.xml是建筑图纸mvn package是施工队盖出一栋毛坯楼Artifact是精装交付清单规定地板铺什么材质、厨房装什么品牌灶具、网络接口留几个——没有它毛坯楼永远无法交付入住。4.2 创建 Web Application: Exploded Artifact 的七步手把手这不是点几下就能完的事。每一步都有其不可替代的逻辑。File→Project Structure→Artifacts点击左上角号 →Web Application: Exploded→From modules...在弹出窗口中选择你的模块通常是myapp.main点击OK此时右侧Output Layout树形结构展开你会看到Available Elements左边是源文件列表Output Layout右边是最终部署结构展开Output Layout→myapp你的 Artifact 名右键WEB-INF→New Directory→ 输入classes选中刚建的classes目录右键Put from Output→myapp.main:compile展开Available Elements→myapp.main→webapp拖拽整个webapp文件夹到Output Layout的myapp根目录下与WEB-INF同级。完成后Output Layout应该长这样myapp/ ├── index.jsp ├── css/ ├── js/ └── WEB-INF/ ├── web.xml └── classes/ ← 这里放编译好的 Servlet class4.3 为什么classes目录必须手动创建并关联compile output因为 IDEA 的Web Application: ExplodedArtifact默认只把webapp/目录下的内容HTML、JSP、CSS复制过去它不会自动把src/main/java编译出的.class文件放到WEB-INF/classes/下。你手动创建classes目录并执行Put from Output→myapp.main:compile相当于告诉 IDEA“请把src/main/java编译后的所有.class原样塞进WEB-INF/classes/”。验证方法点击Output Layout右上角的Show Content of myapp.main:compile你应该能看到com/example/HelloServlet.class。如果看不到说明myapp.main:compile输出路径没配对需检查Project Structure→Modules→Paths→Compiler output是否指向target/classes。4.4 Artifact 名称与 Context Path 的绑定关系在Artifacts列表中你的 Artifact 名叫myapp:war exploded。这个myapp就是 Tomcat 的 Context Path。如果你访问http://localhost:8080/myapp/就能看到首页如果你想访问http://localhost:8080/根路径有两个办法方法一推荐在Run Configuration→Deployment标签页把Application context改为/方法二把 Artifact 名改成ROOT:war exploded注意大小写因为 Tomcat 规定webapps/ROOT/目录对应根路径。注意Application context字段的值会覆盖 Artifact 名。也就是说即使 Artifact 叫myapp:war exploded只要Application context设为/部署时 IDEA 就会把它扔进webapps/ROOT/。这是最灵活的配置方式。4.5 一个隐藏开关ExplodedvsWar开发阶段必须选前者Web Application: Exploded和Web Application: Archive即 WAR的区别不只是“文件夹 vs 压缩包”。ExplodedIDEA 把Output Layout的结构实时同步到 Tomcat 的webapps/目录下。你改一行 JSP保存刷新浏览器就生效无需重启 TomcatWarIDEA 先生成target/myapp.war再把它拷贝到webapps/Tomcat 自动解压。改一次 JSP要等 Tomcat 解压完才能看到效果耗时 3~5 秒。实操数据在Exploded模式下JSP 修改响应时间 200ms在War模式下平均 4.3 秒。对于开发调试Exploded是唯一合理选择。5. 运行时坐标系校准Tomcat 启动参数、JVM 配置与 404 的终极归因5.1 为什么 Tomcat 启动成功但访问http://localhost:8080/myapp/还是 404这是最折磨人的场景。控制台显示INFO: Starting ProtocolHandler [http-nio-8080] INFO: Server startup in [1234] milliseconds一切看起来完美。但浏览器打开就是 404。原因只有一个Tomcat 根本没加载你的应用。而根本原因90% 出现在Run Configuration→Deployment标签页。必查三要素Artifact 是否已添加到Deploy at the server startup列表如果列表为空Tomcat 启动后webapps/目录下什么都没有如果列表里有myapp:war exploded但前面的复选框没勾等于没部署。Application context是否与 URL 匹配Artifact 名是myapp:war explodedApplication context是/myapp→ 访问http://localhost:8080/myapp/✅Artifact 名是myapp:war explodedApplication context是/→ 访问http://localhost:8080/✅Artifact 名是myapp:war explodedApplication context是/demo→ 访问http://localhost:8080/demo/✅错配 404。Before launch里的Build artifact是否勾选如果没勾IDEA 不会执行Build→Build ArtifactsOutput Layout里的classes目录就是空的Servlet class 缺失 → 404。排查口诀“一看部署列表二看上下文三看构建开关”。三者全绿404 必灭。5.2 JVM 配置不是可选项而是 Servlet 内存安全阀Tomcat 默认启动参数对现代 Web 应用来说太保守。尤其当你在 JSP 里用ArrayList存几百条学生信息或 Servlet 里调用大模型 API 返回 2MB JSON 时很容易 OOM。在Run Configuration→Server标签页找到VM options字段填入-Xms512m -Xmx1024m -XX:MetaspaceSize256m -XX:MaxMetaspaceSize512m -Dfile.encodingUTF-8参数详解参数作用为什么必须-Xms512m初始堆内存 512MB避免 Tomcat 启动后频繁 GC-Xmx1024m最大堆内存 1024MBJSP 编译、Servlet 处理大 JSON 需要空间-XX:MetaspaceSize256m元空间初始大小存储类元数据老版本用-XX:PermSize新版本必须用 Metaspace-Dfile.encodingUTF-8强制文件编码防止读取web.xml或 JSP 时乱码注意-Xms和-Xmx值最好相等避免运行时堆内存动态扩容减少 GC 停顿。1024m 对大多数教学项目足够企业级项目建议 2048m。5.3 Tomcat 日志是你的 X 光机读懂catalina.out和localhost.date.log当一切配置看似正确却还是 404打开日志是唯一出路。catalina.outTomcat 主进程日志记录启动、停止、JVM 错误localhost.date.log你的应用专属日志记录 Servlet 初始化、JSP 编译、Filter 执行。404 的典型日志线索INFO: Deploying web application directory [C:\apache-tomcat-9.0.83\webapps\myapp]→ 部署开始SEVERE: Error starting static Resources→webapp/目录路径错误或无读取权限WARNING: No mapping found for HTTP request with URI [/myapp/]→web.xml里没配 welcome-file-list或index.jsp不在webapp/根目录INFO: Starting Servlet engine: [Apache Tomcat/9.0.83]→ Servlet 引擎启动成功但没看到你的 Servlet 名 →classes目录为空或路径错。实操技巧在Run Configuration→Logs标签页勾选Show console when a message is printed to stdout/stderr并把catalina.out和localhost.*.log添加到Log files to show in console列表。这样控制台会实时聚合所有关键日志不用切来切去。5.4 最后一道防火墙Windows 防火墙与端口占用你以为配置全对了但浏览器打不开可能只是因为端口被占8080被 Skype、Zoom 或另一个 Tomcat 占用。解决netstat -ano | findstr :8080找到 PIDtaskkill /PID pid /F。防火墙拦截Windows Defender 防火墙阻止了java.exe的网络访问。解决Windows 设置→隐私和安全性→Windows Defender 防火墙→允许应用通过防火墙→ 找到java.exe通常在C:\Program Files\Java\jdk-xx\bin\java.exe勾选专用和公用。终极验证法在 CMD 里执行curl http://localhost:8080/。如果返回 Tomcat 默认页说明端口通如果超时一定是网络层问题。6. 从零到一一个可立即运行的最小 ServletJSP 示例项目现在把前面所有坐标系校准浓缩成一个可粘贴、可运行的完整流程。我用myapp为例全程基于 IDEA 2024.2 Tomcat 9.0.83 JDK 17。6.1 创建项目骨架Mavenmvn archetype:generate \ -DgroupIdcom.example \ -DartifactIdmyapp \ -DarchetypeArtifactIdmaven-archetype-webapp \ -DinteractiveModefalse生成后用 IDEA 打开myapp/pom.xml。6.2 补全pom.xml依赖关键dependencies !-- Servlet API -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency !-- JSP API -- dependency groupIdjavax.servlet.jsp/groupId artifactIdjavax.servlet.jsp-api/artifactId version2.3.3/version scopeprovided/scope /dependency !-- JSTL (可选用于 c:if 等标签) -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency /dependencies注意scopeprovided表示这些 jar 由 Tomcat 提供IDEA 编译时用但不打包进 WAR。这是 Java Web 的黄金法则。6.3 创建HelloServletsrc/main/java/com/example/HelloServlet.javapackage com.example; 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 { req.setAttribute(message, Hello from Servlet!); req.getRequestDispatcher(/index.jsp).forward(req, resp); } }6.4 创建index.jspsrc/main/webapp/index.jsp% page contentTypetext/html;charsetUTF-8 languagejava % html head titleHello JSP/title /head body h1${message}/h1 pCurrent time: % new java.util.Date() %/p /body /html6.5 配置web.xmlsrc/main/webapp/WEB-INF/web.xml?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list jsp-config jsp-property-group url-pattern*.jsp/url-pattern page-encodingUTF-8/page-encoding el-ignoredfalse/el-ignored /jsp-property-group /jsp-config /web-app6.6 IDEA 内部配置按顺序执行标记webapp右键src/main/webapp→Mark Directory as→Web Resources Root刷新 Maven右侧 M
上一篇/下一篇内容由系统自动关联
返回资讯列表 →