1. 项目概述
作为一名Java后端开发者,我经常被问到如何快速上手Spring MVC框架。今天我就用最接地气的方式,带大家从零搭建一个能"打招呼"的Spring MVC项目。这个项目虽然简单,但涵盖了Spring MVC最核心的组件和工作流程,是理解这个框架的绝佳切入点。
Spring MVC作为Spring框架的Web模块,采用了经典的前端控制器模式。它的核心思想是将请求处理流程分解为多个职责分明的组件,每个组件只关注自己的特定功能。这种设计使得整个框架既灵活又易于扩展,这也是为什么它能在企业级开发中如此流行。
2. 环境准备
2.1 开发工具选择
对于这个入门项目,我推荐使用以下工具组合:
- IDE:IntelliJ IDEA(社区版就够用)或Eclipse
- 构建工具:Maven(版本3.6+)
- JDK:Java 8或11
- Servlet容器:内嵌Tomcat(通过Maven插件运行)
提示:如果你刚开始学习Java Web开发,建议直接使用IntelliJ IDEA,它对Maven和Spring的支持非常友好,能减少很多配置上的麻烦。
2.2 项目结构规划
在开始编码前,我们先规划下项目的基本结构。一个标准的Maven Web项目通常包含以下目录:
springmvc-demo ├── src │ ├── main │ │ ├── java # Java源代码 │ │ ├── resources # 配置文件 │ │ └── webapp # Web资源 │ │ ├── WEB-INF │ │ └── index.jsp └── pom.xml # Maven配置文件3. 项目搭建
3.1 创建Maven项目
首先,在你的IDE中创建一个新的Maven项目。选择maven-archetype-webapp作为原型,这会自动生成基本的Web项目结构。
3.2 配置pom.xml
接下来是配置项目的核心依赖。打开pom.xml文件,添加以下内容:
<project> <!-- 基本项目信息 --> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>springmvc-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.3.20</spring.version> </properties> <dependencies> <!-- Spring MVC核心依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- JSP支持 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!-- 内嵌Tomcat插件 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> <version>9.0.62</version> </dependency> </dependencies> <build> <plugins> <!-- 用于运行项目的Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> </configuration> </plugin> </plugins> </build> </project>注意:这里我们使用了Spring 5.3.20版本,这是目前比较稳定的一个版本。如果你需要与其他Spring组件(如Spring Security)集成,建议保持所有Spring依赖的版本一致。
4. 核心组件实现
4.1 创建首页(index.jsp)
在src/main/webapp目录下创建index.jsp文件:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC Demo</title> </head> <body> <h2>Spring MVC入门示例</h2> <a href="hello">点击这里向师姐打招呼</a> </body> </html>这个简单的JSP页面包含一个超链接,点击后会向/hello路径发送请求。
4.2 创建控制器(HelloController)
在src/main/java下创建包com.example.controller,然后新建HelloController类:
package com.example.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class HelloController { @GetMapping("/hello") public String sayHello(Model model) { // 向模型中添加属性 model.addAttribute("message", "师姐你好!"); // 返回视图名称 return "success"; } }这个控制器类有几个关键点需要注意:
@Controller注解标识这是一个Spring MVC控制器@GetMapping("/hello")映射HTTP GET请求到sayHello方法Model参数用于向视图传递数据- 方法返回的字符串"success"对应视图名称
4.3 配置Spring MVC(springmvc.xml)
在src/main/resources目录下创建springmvc.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 开启注解扫描 --> <context:component-scan base-package="com.example.controller"/> <!-- 开启MVC注解驱动 --> <mvc:annotation-driven/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> </beans>这个配置文件做了三件重要的事情:
- 启用组件扫描,自动发现带有
@Controller注解的类 - 启用Spring MVC注解驱动
- 配置视图解析器,将逻辑视图名解析为具体的JSP文件路径
4.4 配置web.xml
在src/main/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"> <!-- 配置DispatcherServlet --> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- 映射所有请求到DispatcherServlet --> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>这个配置的核心是声明了Spring MVC的DispatcherServlet,它是整个框架的入口点,负责接收所有请求并将其分发给相应的处理器。
4.5 创建视图页面(success.jsp)
在src/main/webapp/WEB-INF/pages目录下创建success.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>打招呼</title> </head> <body> <h1>${message}</h1> </body> </html>这个JSP页面会显示控制器传递过来的message属性值。注意我们使用了JSTL的表达式语言${message}来访问模型数据。
5. 运行与测试
5.1 启动项目
在项目根目录下执行以下Maven命令:
mvn tomcat7:run或者直接在IDE中配置Tomcat插件运行。启动后,控制台会显示类似如下的信息:
[INFO] Starting Tomcat... [INFO] Starting Servlet Engine: Apache Tomcat/7.0.47 [INFO] Starting ProtocolHandler ["http-bio-8080"]5.2 访问应用
打开浏览器,访问http://localhost:8080,你应该能看到首页。点击"向师姐打招呼"链接,页面应该跳转并显示"师姐你好!"。
6. Spring MVC核心组件详解
6.1 DispatcherServlet(前端控制器)
这是Spring MVC的核心,负责接收所有HTTP请求并将它们分发给适当的处理器。你可以把它想象成公司的前台接待员,所有来访者(请求)都必须先经过它。
6.2 HandlerMapping(处理器映射器)
它负责确定哪个控制器方法应该处理当前请求。Spring提供了多种实现,最常用的是基于注解的RequestMappingHandlerMapping,它会查找带有@RequestMapping及其变体(如@GetMapping)的方法。
6.3 HandlerAdapter(处理器适配器)
这个组件负责实际调用处理器方法。对于注解式控制器,使用的是RequestMappingHandlerAdapter。它处理方法的参数解析和返回值处理。
6.4 ViewResolver(视图解析器)
视图解析器将控制器返回的逻辑视图名解析为实际的视图实现。我们配置的InternalResourceViewResolver会将"success"解析为"/WEB-INF/pages/success.jsp"。
6.5 View(视图)
视图负责渲染模型数据。在我们的例子中,JSP页面就是视图实现,它使用JSTL表达式显示控制器传递的数据。
7. 常见问题与解决方案
7.1 404错误
问题描述:访问页面时出现404错误。
可能原因:
- DispatcherServlet的URL映射配置不正确
- 控制器方法映射路径与请求路径不匹配
- 视图文件位置不正确
解决方案:
- 检查
web.xml中<url-pattern>的配置 - 确保控制器方法的
@GetMapping路径与请求路径一致 - 确认JSP文件位于视图解析器配置的路径下
7.2 500服务器错误
问题描述:服务器返回500错误。
可能原因:
- 缺少必要的依赖
- JSP页面使用了未定义的变量
- 配置文件中存在错误
解决方案:
- 检查Maven依赖是否完整
- 确保JSP中所有EL表达式对应的属性都已添加到Model中
- 检查Spring配置文件是否有语法错误
7.3 中文乱码问题
问题描述:页面上显示的中文变成乱码。
解决方案:
- 确保所有JSP文件都设置了
<%@ page contentType="text/html;charset=UTF-8" %> - 在
web.xml中添加字符编码过滤器:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>8. 项目优化建议
8.1 使用Java配置替代XML
现代Spring项目更推荐使用Java配置。我们可以创建一个配置类来替代springmvc.xml:
@Configuration @EnableWebMvc @ComponentScan("com.example.controller") public class WebConfig implements WebMvcConfigurer { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/pages/"); resolver.setSuffix(".jsp"); return resolver; } }然后在web.xml中修改DispatcherServlet的配置:
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextClass</param-name> <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </init-param> <init-param> <param-name>contextConfigLocation</param-name> <param-value>com.example.config.WebConfig</param-value> </init-param> </servlet>8.2 添加静态资源处理
默认情况下,DispatcherServlet会拦截所有请求,包括对静态资源(如CSS、JS文件)的请求。我们需要在配置中添加静态资源处理:
在XML配置中:
<mvc:resources mapping="/resources/**" location="/resources/"/>或者在Java配置中:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/resources/"); }8.3 使用Thymeleaf替代JSP
现代Spring项目更推荐使用Thymeleaf作为模板引擎。要使用Thymeleaf,首先添加依赖:
<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.15.RELEASE</version> </dependency>然后配置Thymeleaf视图解析器:
@Bean public SpringResourceTemplateResolver templateResolver() { SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".html"); resolver.setTemplateMode("HTML"); return resolver; } @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine engine = new SpringTemplateEngine(); engine.setTemplateResolver(templateResolver()); return engine; } @Bean public ThymeleafViewResolver viewResolver() { ThymeleafViewResolver resolver = new ThymeleafViewResolver(); resolver.setTemplateEngine(templateEngine()); return resolver; }9. 深入理解请求处理流程
为了更好地掌握Spring MVC,我们需要理解一个请求从发起到响应的完整流程:
- 请求到达:用户发起HTTP请求,被DispatcherServlet捕获
- 确定处理器:HandlerMapping根据请求URL找到对应的Controller方法
- 执行拦截器:如果有配置拦截器,会按顺序执行preHandle方法
- 调用处理器:HandlerAdapter调用实际的Controller方法
- 处理返回值:HandlerAdapter处理方法的返回值(可能是ModelAndView、String或ResponseEntity等)
- 渲染视图:ViewResolver解析视图名,View渲染模型数据
- 后置处理:拦截器的postHandle方法被执行
- 完成请求:最终响应发送给客户端
理解这个流程对于调试和扩展Spring MVC应用非常重要。当遇到问题时,你可以按照这个流程逐步排查,看看是在哪个环节出现了问题。
10. 实际开发中的经验分享
在实际项目中使用Spring MVC多年,我总结了一些有价值的经验:
控制器设计原则:
- 保持控制器精简,只处理HTTP相关的逻辑
- 业务逻辑应该放在Service层
- 一个控制器最好只负责一个资源或功能领域
异常处理:
- 使用
@ControllerAdvice全局处理异常 - 为不同的异常类型提供友好的错误页面
- 记录详细的错误日志
- 使用
测试建议:
- 使用Spring的MockMvc测试控制器
- 编写集成测试验证完整的请求处理流程
- 测试各种边界情况和错误场景
性能优化:
- 合理使用缓存(页面缓存、数据缓存)
- 启用GZIP压缩
- 优化视图渲染性能
安全考虑:
- 防止XSS攻击(对输出进行编码)
- 防止CSRF攻击(使用Spring Security的CSRF保护)
- 验证所有用户输入
这个简单的"打招呼"项目虽然功能简单,但它展示了Spring MVC的核心概念和工作原理。通过这个基础,你可以继续探索更复杂的特性,如数据绑定、表单处理、文件上传、RESTful服务等。