Spring MVC项目Dispatcher Servlet未初始化引发404错误求助
我正在跟随Udemy的Spring与Spring Boot课程搭建Web应用,使用Tomcat 9.0和Spring Boot Suite部署,日志显示应用已成功部署到INFORMAZIONI: Deploying web application directory [C:\Users\Fabrizio\Documents\Spring\Udemy - Guida Completa\apache-tomcat-9.0.71\webapps\ROOT],访问http://localhost:8080可正常显示Tomcat首页,但访问http://localhost:8080/rest/welcome时出现404错误。
课程视频中的控制台会输出Initializing Spring DispatcherServlet 'dispatcher'日志,但我的控制台没有该日志,推测Dispatcher Servlet未初始化是导致控制器无法处理请求的原因。已尝试删除并重启服务器,但问题依旧。
已编写的类
WebConfig.java
package it.fogliafabrizio.corso.web; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @Configuration @EnableWebMvc @ComponentScan(basePackages = "it.fogliafabrizio.corso.web.controller") //自动检测控制器并将其作为bean管理 public class WebConfig { }
AppInitializer.java
package it.fogliafabrizio.corso.web; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.FrameworkServlet; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // TODO 自动生成方法存根 return null; } @Override protected Class<?>[] getServletConfigClasses() { /* 指定用于访问Web应用所有配置的类 */ return new Class<?>[] {WebConfig.class}; //返回配置类的泛型Class数组 } @Override protected String[] getServletMappings() { /* 指定DispatcherServlet在应用中需要拦截的路径 */ return new String[]{"/"}; //应用收到的所有请求都需被处理 } @Override /* 右键 > 源码 > 重写/实现方法 * AbstractDispatcherInitializer -> 找到接收WebApplicationContext的方法 */ protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) { /* 创建DispatcherServlet实例,传入应用上下文 * 设置setThrowExceptionIfNoHandlerFound为true,使Web应用抛出异常而非返回404错误 * 并返回该实例 */ DispatcherServlet ds = new DispatcherServlet(servletAppContext); ds.setThrowExceptionIfNoHandlerFound(true); return ds; } }
控制器示例:WelcomeRestController.java
package it.fogliafabrizio.corso.web.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/rest") public class WelcomeRestController { @RequestMapping("/welcome") public String welcome() { return "{message: Welcome}"; //示例JSON } }
pom.xml配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>it.fogliafabrizio.corso.web</groupId> <artifactId>corsospringweb</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>corsospringweb</name> <dependencies> <dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>6.0.4</version> </dependency> <dependency> <!-- 核心模块 --> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>6.0.4</version> </dependency> <dependency> <!-- Beans模块 --> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>6.0.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>6.0.4</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>6.0.4</version> </dependency> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.10.1</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.10.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
问题排查与解决方案
1. 版本兼容性问题
Spring 6.0+ 依赖Jakarta EE 9+(使用jakarta.servlet包),但Tomcat 9.0仅支持Jakarta EE 8(对应javax.servlet包),版本不匹配会导致DispatcherServlet无法被Tomcat正确初始化。
解决方法:
- 降级Spring版本到5.3.x系列(兼容Tomcat 9和javax.servlet),或者
- 升级Tomcat到10.0+版本(支持Jakarta EE 9+)
2. 编译版本与Spring版本不兼容
Spring 6.0要求Java版本至少为17,但你的pom.xml中指定了source和target为1.8,这会导致类加载异常,进而影响DispatcherServlet初始化。
解决方法:
如果选择保留Spring 6.0,修改maven-compiler-plugin的配置为Java 17+:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.10.1</version> <configuration> <source>17</source> <target>17</target> </configuration> </plugin>
同时确保你的开发环境(JDK)版本为17+。
3. 验证DispatcherServlet初始化日志级别
确保日志级别设置为INFO,否则Initializing Spring DispatcherServlet日志可能不会显示。可以在项目中添加logback或log4j配置,将org.springframework.web的日志级别设为INFO。
4. 检查项目部署结构
确认打包后的war包中包含所有必要的class文件:
WEB-INF/classes下应有it.fogliafabrizio.corso.web和it.fogliafabrizio.corso.web.controller包的class文件WEB-INF/lib下包含所有依赖的jar包
5. 替换AppInitializer的实现(可选)
如果上述方法无效,可以尝试使用WebApplicationInitializer接口直接实现,替代AbstractAnnotationConfigDispatcherServletInitializer:
package it.fogliafabrizio.corso.web; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import jakarta.servlet.ServletContext; import jakarta.servlet.ServletRegistration; public class AppInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(WebConfig.class); DispatcherServlet dispatcherServlet = new DispatcherServlet(context); dispatcherServlet.setThrowExceptionIfNoHandlerFound(true); ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcher", dispatcherServlet); registration.setLoadOnStartup(1); registration.addMapping("/"); } }
内容的提问来源于stack exchange,提问作者Fabrizio Foglia

