尧图精选

IDEA 启动传统 SpringMVC:Artifact 与 Tomcat 配置

🕒 发布时间:2026/10/1 1:25:02 📁 来源:尧图网络
1. 传统SpringMVC项目在IDEA里启动为什么总出问题如果你手上有一个用XML配置的老SpringMVC项目之前一直在Eclipse或者MyEclipse里跑现在换到IntelliJ IDEA第一次点启动大概率是跑不起来的——要么404要么ClassNotFoundException要么Tomcat起来了但控制台一片红。这不是你的代码有问题而是IDEA对项目的识别方式和Eclipse完全不同加上SpringMVC这类传统Web项目依赖web.xml、WEB-INF目录结构、Artifact打包这几个环节任何一环没对齐application就起不来。这篇内容我想聊的就是怎么在IDEA里把一个传统SpringMVC项目配置到能正常通过Tomcat启动包括工程导入、Artifact配置、Tomcat Server运行配置、web.xml加载顺序、常见启动报错排查这一整套流程。适合手上有遗留SpringMVC项目、需要在本机跑起来做维护或二次开发的同学也适合刚接触IDEA、还不太清楚Artifact和Deployment之间关系的开发者。如果你已经在用SpringBoot那这篇里的部分内容可以作为了解底层原理的参考因为SpringBoot本质上也是把这些配置自动化了。先明确一个前提SpringMVC项目在IDEA里的启动本质上是“把编译产物按照Web应用的标准目录结构打包成一个Artifact再交给Tomcat容器去加载”。理解这句话后面所有的配置都是围绕它展开的。很多人配不明白是因为把IDEA当成了Eclipse——Eclipse里项目天然就是Web项目右键Run on Server就行IDEA里你需要显式告诉它哪些目录是源码、哪些是资源、编译后的class放哪、WEB-INF里的jar怎么组织、上下文路径叫什么。这些信息IDE不会替你猜尤其是从外部导入的工程。另外要说清楚一点这里讨论的“application启动”指的是通过Tomcat容器把整个Web应用跑起来而不是SpringBoot那种main方法直接启动。两者的启动入口、类加载顺序、上下文初始化时机都不一样混着理解很容易绕进去。下面我按实际操作的顺序从环境准备一路讲到报错排查。2. 工程导入与运行环境准备的关键动作2.1 JDK、Tomcat、Maven三者的版本对齐老SpringMVC项目对版本是敏感的尤其是JDK。很多2015年前后的项目跑在JDK 7或JDK 8上Spring 4.x对JDK 9以上的模块化机制兼容性很差你直接拿JDK 17去跑大概率在类加载阶段就崩。所以第一步是确认项目原本的JDK版本通常看pom.xml里的maven.compiler.source或者看项目里有没有.classpath文件标注的JRE版本。Tomcat的选择同样有讲究。SpringMVC项目一般用Tomcat 7、8、8.5这几个版本居多。Tomcat 9之后对Servlet API做了一些调整老项目里的某些jar可能对javax.servlet包的依赖方式和Tomcat 10的jakarta.servlet不兼容。我个人的建议是如果项目原本用的是Tomcat 8就继续用8或8.5别图新。可以在IDEA里配置多个Tomcat版本不同项目用不同的。Maven这边主要看仓库能不能拉到依赖。老项目经常依赖一些已经下架的私服jar或者公司内网的snapshot。导入之后先执行一次mvn clean install -DskipTests看依赖能不能全部解析。如果报某个jar找不到优先确认是不是仓库地址配置在settings.xml里被覆盖了。这个问题在实际维护老项目时出现频率非常高我踩过好几次最后发现是IDEA自带的Maven用了默认的central仓库没读你本地的settings.xml。注意IDEA默认可能使用Bundled Maven路径在Settings Build Tools Maven里。老项目建议改成自己本地安装的Maven并把User settings file指向你日常用的settings.xml避免依赖拉取行为不一致。版本对齐这件事说到底是让“编译环境”和“运行环境”一致。IDEA里可以给每个项目单独设置Language Level和SDK在File Project Structure Project里设定。别小看这一步我见过太多“本地编译过、一启动就NoSuchMethodError”的案例根源就是编译用的JDK和Tomcat运行时用的JDK不是同一个大版本。2.2 从Eclipse工程导入IDEA时的三个关键识别点Eclipse项目和IDEA项目的元数据文件格式不同前者是.project和.classpath后者是.idea目录和*.iml。导入的时候IDEA会尝试解析Eclipse的配置但经常解析不全尤其是源码目录Source Root和资源目录Resources Root的标记。第一个识别点是src/main/java之外的自定义源码目录。有些老项目为了兼容Eclipse会把Java源码放在src根目录下而不是标准的Maven目录结构。导入后你要手动在Project Structure Modules Sources里把这些目录标记成Sources否则IDEA不编译它们启动时自然就报ClassNotFound。第二个识别点是web目录的位置。传统SpringMVC项目的Web根目录可能叫WebContent、webapp、WebRoot位置也未必在src/main下。这个目录必须被明确识别为Web Resource DirectoryIDEA才知道WEB-INF和web.xml在哪。正确做法是在Project Structure Facets里添加Web Facet然后把Web Resource Directory指向你的实际目录Deployment Descriptor指向web.xml。第三个识别点是依赖jar的引用方式。Eclipse项目里依赖经常放在WebContent/WEB-INF/lib目录下直接以物理jar存在而不是走Maven。IDEA导入这种项目时需要把这些jar加到模块依赖里同时在Artifact配置里确保它们被放进WEB-INF/lib。这一步漏了启动时就会报各种NoClassDefFoundError。提示导入完成后先别急着配Tomcat先在Project Structure Modules Dependencies里过一遍看看有没有红色的、标着“missing”的依赖。有就先解决别带着问题往下走。我个人习惯是导入后立刻做一次“全量体检”SDK版本对不对、源码目录标记全不全、依赖有没有缺失、Web Facet有没有加上。这四件事做完后面配置Tomcat会顺很多。很多同学跳过这步直接去配Server结果启动报错又回头查依赖来回折腾。3. Application启动配置的核心步骤拆解3.1 Artifact配置WEB-INF目录结构的组装逻辑Artifact是IDEA里最容易让人懵的概念。简单说它是“把项目编译产物按照一个特定目录结构组装起来的一份输出”。对Web项目来说这个目录结构必须符合Servlet规范根目录下有WEB-INFWEB-INF下有classes、lib、web.xml。Tomcat加载的就是这个Artifact。配置入口在File Project Structure Artifacts点加号选Web Application: Exploded。这里有个选择Exploded和Archive。Exploded是展开的目录形式改代码后重新编译就能生效调试方便Archive是打成war包适合部署。本地开发一律选Exploded别选错。创建之后要检查右侧的布局标准结构应该是这样WEB-INF/classes指向模块的编译输出目录compiler outputWEB-INF/lib包含所有依赖jar根目录包含web.xml所在的Web Resource Directory内容我见过最常见的错误是WEB-INF/classes这一项缺失或者指错了地方。如果它没指向target/classesMaven项目或模块的output目录Tomcat启动时WEB-INF下就没有classSpring的ContextLoaderListener加载web.xml里配置的contextConfigLocation时就会找不到类直接抛异常。还有一点是Available Elements面板里的库要手动双击加到WEB-INF/lib下。IDEA不会自动帮你加你只把模块依赖配好了Artifact里不体现打包出来就是缺jar。这一步是纯粹的“手工活”但必须做。3.2 Tomcat Server运行配置的细节Artifact配好之后去Run Edit Configurations点加号选Tomcat Server Local。这里有几个关键项第一是Application server指向你本地的Tomcat安装目录。IDEA会自动读取它的lib用来做编译期依赖。第二是Deployment标签页点加号把刚才配的Artifact加进去然后设置Application context。这个context就是访问路径的前缀比如设成/myapp那你访问的URL就是http://localhost:8080/myapp/xxx。很多404问题的根源就是这里要么context设成了/但代码里写死了别的路径要么设成了项目名但浏览器访问时没带。第三是Server标签页里的端口和JVM参数。端口默认8080冲突了就改。JVM参数这块老项目经常需要调大内存因为Spring容器启动时加载的bean多Metaspace容易爆。可以在VM options里加-Xms512m -Xmx1024m -XX:MaxMetaspaceSize256m这类参数。另外如果项目有编码问题加上-Dfile.encodingUTF-8。第四是On Update action建议设成Update classes and resources。这样你改完Java代码点一下更新按钮或者CtrlF10Tomcat会热更新class和JSP不用重启。对调试效率提升非常大。不过要注意改XML配置和Spring的bean定义时热更新不一定生效该重启还是得重启。3.3 web.xml与Spring容器的加载顺序Tomcat启动一个Web应用的流程简单说是读取web.xml按listener和context-param的顺序初始化然后加载servlet。SpringMVC项目通常配两个东西一个是ContextLoaderListener负责加载Spring的根容器service、dao这些一个是DispatcherServlet负责加载SpringMVC的子容器controller、视图解析器这些。这两者的加载顺序有讲究。ContextLoaderListener先启动读contextConfigLocation里配的applicationContext.xml然后DispatcherServlet启动自己的contextConfigLocation指向spring-mvc.xml。子容器能访问父容器的bean反过来不行。如果你把service的bean定义在了spring-mvc.xml里controller里能注入但ContextLoaderListener里的其他bean就找不到它——这是设计上的隔离不是bug。启动报错里有一类就是“父子容器加载顺序错乱导致bean找不到”。比如在applicationContext.xml里配了一个Autowired的bean但那个bean实际定义在spring-mvc.xml里启动时根容器先初始化找不到依赖就报错。排查这类问题先看两个配置文件的bean扫描范围有没有重叠或遗漏。web.xml里context-param和listener的先后也有关系。context-param必须写在listener之前否则Listener读不到参数。这个规则IDE不会帮你检查写反了启动才报错。我一开始就栽过这个坑排查了半天才发现是标签顺序问题。4. 三种启动方式的实操对比与选择4.1 IDEA内置Tomcat部署推荐用于日常开发这是最常用的方式配置好Artifact和Server之后直接点绿色三角。它的好处是集成度高控制台输出、热更新、断点调试都在IDE里完成改代码见效快。具体操作路径Edit Configurations Tomcat Server Local 配置Application server Deployment里加Artifact 设context path 启动。启动后控制台会打印Tomcat的启动日志和Spring的初始化日志从里面能看到容器有没有正常加载bean、有没有映射URL。有一个细节要注意IDEA内置Tomcat启动时用的工作目录和“独立安装的Tomcat”不一样它会在C:\Users\你的用户名\AppData\Local\JetBrains\...\tomcat\下生成一套临时目录把Artifact复制过去运行。所以你改Artifact配置后有时候需要重启才生效。另外日志文件也会在这个临时目录里排查启动问题时可以去那找完整日志。4.2 打War包丢进外部Tomcat这种方式适合需要验证“最终部署形态”或者需要跟生产环境保持一致的情况。在Maven项目里执行mvn clean package生成的war丢进Tomcat的webapps目录启动Tomcat的bin/startup脚本。这种方式的坑在于IDEA里编译通过不代表打包后的war能跑。尤其是依赖scope的问题——如果某个jar在pom里写的是provided打包时不会被放进WEB-INF/lib运行时就找不到。Tomcat本身提供的servlet-api、jsp-api用provided是对的但如果你不小心把业务依赖也写成了provided部署时就炸。提示打包后可以先解压war看一眼确认WEB-INF/lib下的jar数量跟你预期一致WEB-INF/classes下有class文件。这一步花不了两分钟能避免很多“部署后报错、本地却正常”的困惑。4.3 用Maven插件启动tomcat7-maven-plugin如果项目pom里配了tomcat7-maven-plugin可以直接用mvn tomcat7:run启动不依赖IDEA的Tomcat配置也不依赖本地安装的Tomcat。这种方式的好处是轻量、可脚本化适合快速验证。配置大概是这样plugin groupIdorg.apache.tomcat.maven/groupId artifactIdtomcat7-maven-plugin/artifactId version2.2/version configuration port8080/port path/myapp/path uriEncodingUTF-8/uriEncoding /configuration /pluginuriEncoding这个参数建议一定加上否则URL里的中文参数会乱码这是很多老项目在GET请求里传中文时踩的坑。path对应访问路径前缀跟IDEA里配context path是一个意思。需要注意的是这个插件内置的Tomcat版本比较老只到Tomcat 7对Servlet 3.1以上的特性支持有限。如果你的项目用了较新的API可能跑不起来。它更像是“快速冒烟测试”用的正式开发调试我还是推荐IDEA内置Tomcat。三种方式对比一下启动方式适用场景优点缺点IDEA内置Tomcat日常开发调试集成度高热更新方便断点调试顺畅工作目录是临时的配置分散外部Tomcat部署war验证生产形态、联调接近真实部署环境打包环节多排查不便Maven插件启动快速验证、CI脚本无需本地Tomcat命令简单Tomcat版本老功能受限5. 启动报错排查实录与高频问题速查5.1 启动即报ClassNotFoundException的排查路径这类错误几乎都跟Artifact配置有关。按顺序查三处一看WEB-INF/classes有没有指向正确的编译输出目录。进Artifact配置看布局项确认它是module xxx compile output。如果Module的output目录本身是空的说明源码没编译先执行一次Build Rebuild Project。二看WEB-INF/lib里有没有你的依赖jar。在Available Elements里把需要的库双击加过去。注意某些jar可能是providedscopeIDEA不会默认加进去你需要手动添加到Artifact或者改pom里的scope。三看web.xml里listener和context-param指向的类名有没有写错。尤其是包名重构过之后web.xml里的全限定类名可能还是旧的。这种错误很隐蔽因为IDE不会校验XML里的字符串。我遇到过一次特别典型的情况项目在Eclipse里跑得好好的导入IDEA后启动报ClassNotFoundException: org.springframework.web.context.ContextLoaderListener最后发现是Artifact里WEB-INF/lib下压根没有spring-web的jar因为pom里spring-web的scope被写成provided了。改回默认scope重新构建Artifact问题解决。5.2 404问题的四种成因与区分方法404分两类一类是Tomcat起来了但访问的URL没映射到任何servlet另一类是应用根本没部署成功。区分方法很简单看访问根路径。比如你的context是/myapp访问http://localhost:8080/myapp如果返回Tomcat的欢迎页或目录列表说明应用部署了是URL映射问题如果返回404且控制台有部署失败的日志那是部署问题。部署成功但404的常见成因DispatcherServlet的url-pattern配的是/还是*.do。配/表示拦截所有请求静态资源除外需额外处理配*.do表示只拦截.do结尾。访问路径跟这个必须匹配。Controller上的RequestMapping路径和实际访问路径不一致尤其是带了context path后容易多写或少写。视图解析器的前后缀配置和实际JSP文件位置对不上。这种情况一般不是404而是500但如果视图没找到也可能报渲染错误。context path设成了/但代码或页面里写死了项目名作为前缀。排查404最快的方式是看启动日志里有没有Mapped {[/xxx],methods[GET]}这样的映射记录。有说明URL注册成功了问题在访问路径写法没有说明Controller没被扫描到检查context:component-scan base-package的范围。5.3 中文乱码与编码相关的配置项老项目里乱码是高发问题根源通常在三个地方Tomcat的URI编码、Spring的字符编码过滤器、页面的编码声明。Tomcat 8之后默认URI编码是UTF-8但有些老项目配的Tomcat是7或者更早默认是ISO-8859-1GET请求的中文就乱。解决办法是在server.xml的Connector上加URIEncodingUTF-8或者在IDEA运行配置的VM options里加参数。Spring这边web.xml里通常会配一个CharacterEncodingFilter设置encoding为UTF-8并强制forceEncoding为true。如果这个filter没配或者位置不对必须放在所有filter最前面请求参数的中文就会乱。页面层面JSP顶部要有% page contentTypetext/html;charsetUTF-8 %HTML里要有meta charsetUTF-8。响应头里的Content-Type也要对。这三者有一个不对都可能出现乱码。注意如果是POST请求乱码多半是CharacterEncodingFilter的问题如果是GET请求乱码优先查Tomcat的URIEncoding。这两者的处理位置不同别混着改。5.4 常见问题速查表报错现象可能原因排查方向ClassNotFoundExceptionArtifact缺classes或lib检查WEB-INF布局404且访问根路径也404应用未部署成功看控制台部署日志404但根路径正常URL映射不匹配对比DispatcherServlet url-pattern与访问路径NoSuchMethodError依赖版本冲突用mvn dependency:tree看是否有重复jarBeanCreationException父子容器bean扫描范围问题检查两个contextConfigLocation的扫描包启动卡住不动内存不足或数据源连接超时调大Metaspace检查数据库连接配置中文乱码编码配置缺失分GET/POST分别排查filter和URIEncoding6. 从SpringMVC平滑改造到SpringBoot的过渡思路很多同学配SpringMVC的初衷其实是想把老项目迁到SpringBoot上。这里说几个实操层面的过渡思路不涉及具体代码改写。第一先别动源码先在SpringMVC项目上把功能跑通、把依赖关系理清楚。你只有完全理解现有项目的Web配置web.xml、spring-mvc.xml、applicationContext.xml的职责划分改造时才知道哪些要搬到SpringBoot的application.yml里哪些要写成Configuration类。第二改造的顺序建议是先加一个SpringBoot的启动类带SpringBootApplication把原web.xml里ContextLoaderListener和DispatcherServlet对应的配置拆成WebMvcConfigurer实现和Bean定义然后把JSP或视图解析的配置搬过去最后处理静态资源和拦截器。别一上来就删web.xml让它和SpringBoot启动类共存一段时间逐步迁移。第三注意SpringBoot默认内嵌Tomcat端口、context path、编码这些都在配置文件里改跟原来在IDEA里点Server配置的体验完全不同。比如原来在IDEA里设Application contextSpringBoot里对应的是server.servlet.context-path。原来VM参数调的JVM内存SpringBoot里还是靠启动参数或脚本。第四老项目里依赖的第三方jar如果和SpringBoot的依赖有冲突用exclusions排除或者用dependencyManagement锁版本。这一步往往是改造中最耗时的需要反复用mvn dependency:tree对比。我个人做过几个这种迁移体会是把SpringMVC配明白这件事本身就是迁移的前置功课。你在IDEA里每解决一个启动报错其实就是在理解SpringBoot帮你还原了什么配置。等你把Artifact、web.xml、父子容器这套东西理顺了看SpringBoot的自动配置就不再是黑盒。最后分享一个我在排查启动问题时的小习惯每次启动失败不要急着改代码先把控制台日志从头到尾读一遍找到第一个Caused by那个才是根因。后面的一长串异常往往都是它引发的连锁反应。很多人倒着看从最后一个异常开始改改了半天才发现方向错了。这个方法帮我省下的时间比任何配置技巧都多。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →