Spring MVC 零基础入门指南:从概念到实战
欢迎来到 Spring MVC 的世界!如果你是一个对 Java Web 开发充满兴趣的初学者,或者正在寻找一个强大、灵活且易于使用的 Web 框架,那么 Spring MVC 绝对值得你深入了解。本文将从最基础的概念出发,一步步带你搭建一个简单的 Spring MVC 应用,让你亲手体验这个框架的魅力。
本文假设你已经具备基本的 Java 编程知识,对 Web 开发(如 HTTP 请求、响应)有初步了解,并且安装了 Java 开发环境 (JDK)、Maven 或 Gradle 构建工具以及一个集成开发环境 (IDE),如 Eclipse、IntelliJ IDEA 或 VS Code。
第一章:初识 Spring MVC – 它是什么?为什么用它?
1.1 什么是 Spring MVC?
Spring MVC 是 Spring 框架中的一个模块,它是一个基于 Java 的 Web 框架,实现了模型-视图-控制器(Model-View-Controller,MVC)设计模式。它旨在简化 Web 应用程序的开发过程,提供了一种结构化的方式来处理 Web 请求、业务逻辑和页面展示。
简单来说,Spring MVC 就是 Spring 框架在处理 Web 请求方面的解决方案。它帮你组织代码,明确各个部分的职责,让 Web 应用更加清晰、易于维护和扩展。
1.2 为什么选择 Spring MVC?
Java Web 开发的框架有很多,比如传统的 Servlet/JSP、Struts、JSF 等等。Spring MVC 为什么如此流行?
- 基于 Spring 平台: 作为 Spring 家族的一员,Spring MVC 可以无缝地集成 Spring 的其他功能,如依赖注入 (DI)、面向切面编程 (AOP)、事务管理等。这意味着你可以利用 Spring 的强大功能来构建你的 Web 层。
- 遵循 MVC 模式: MVC 模式是一种经典的设计模式,它将应用程序分为三个相互独立的组件:
- Model (模型): 负责处理数据和业务逻辑。
- View (视图): 负责数据的展示(用户界面)。
- Controller (控制器): 负责接收用户输入,调用模型处理业务逻辑,并选择合适的视图展示结果。
MVC 模式提高了代码的可维护性、可测试性和模块化程度。
- 灵活性高: Spring MVC 的组件是高度解耦的,你可以选择不同的技术来实现各个部分,例如选择 JSP、Thymeleaf、FreeMarker 等作为视图技术,选择不同的 ORM 框架作为模型层的数据访问技术。
- 功能强大: 提供了丰富的功能,如请求参数绑定、表单处理、文件上传、国际化、输入校验、异常处理、RESTful 服务支持等等。
- 测试友好: 控制器和其他组件可以很容易地进行单元测试和集成测试。
- 活跃的社区和丰富的文档: 作为业界主流框架,Spring MVC 有庞大的用户群体和活跃的社区,遇到问题很容易找到解决方案。
总而言之,Spring MVC 提供了一个结构清晰、功能丰富、易于扩展和测试的 Web 开发框架,是构建企业级 Java Web 应用的优秀选择。
第二章:Spring MVC 核心组件与工作流程
理解 Spring MVC 的工作流程是入门的关键。虽然初次接触可能会觉得组件有点多,但它们各司其职,协同工作。
2.1 核心组件介绍
- DispatcherServlet (前端控制器): 这是 Spring MVC 的核心。所有请求都会先经过它。它负责接收请求,并将其分发给合适的处理程序(通常是 Controller)。它就像一个总调度员。
- Handler Mapping (处理器映射器): 负责根据请求的 URL 找到对应的 Controller 方法。Spring MVC 提供了多种 Handler Mapping,最常用的是基于注解的映射(如
@RequestMapping
)。 - Controller (控制器): 负责处理具体的业务逻辑。接收 DispatcherServlet 分发的请求,调用 Service/Model 层进行处理,然后决定返回哪个视图。通常使用
@Controller
注解标识。 - ModelAndView: Controller 方法通常返回 ModelAndView 对象或包含视图名称和模型数据的其他类型。ModelAndView 包含两部分信息:模型数据(需要展示给视图的数据)和视图名称(逻辑上的视图标识)。
- View Resolver (视图解析器): 负责将 Controller 返回的逻辑视图名称解析成实际的物理视图资源(如 JSP 文件路径)。例如,Controller 返回 “success”,View Resolver 可能将其解析为
/WEB-INF/views/success.jsp
。 - View (视图): 负责渲染模型数据,生成最终呈现给用户的响应(如 HTML 页面)。Spring MVC 支持多种视图技术。
- Handler Adapter (处理器适配器): DispatcherServlet 调用 Controller 方法时,需要通过 Handler Adapter 进行适配。不同的 Controller 实现方式(如基于注解、实现特定接口)需要不同的 Handler Adapter。基于注解的 Controller 主要依赖
RequestMappingHandlerAdapter
。
2.2 工作流程详解
一个典型的 Spring MVC 请求处理流程如下:
- 请求到达: 用户向服务器发送 HTTP 请求。
- DispatcherServlet 接收: 所有请求首先被配置在
web.xml
(或 Java Config)中的DispatcherServlet
捕获。 - Handler Mapping 查找:
DispatcherServlet
查询HandlerMapping
,根据请求的 URL 查找能处理该请求的 Handler(通常是一个 Controller 方法)。 - Handler Adapter 调用: 找到对应的 Handler 后,
DispatcherServlet
通过HandlerAdapter
调用 Handler 的方法。Handler Adapter 负责处理参数绑定、数据校验等。 - Controller 处理: Controller 方法开始执行。它通常会调用 Service 层或 Model 层进行业务逻辑处理和数据获取。
- 返回 ModelAndView: Controller 方法执行完毕后,返回一个
ModelAndView
对象(或视图名、Model 对象等)。ModelAndView
包含了逻辑视图名和需要在视图中显示的数据。 - View Resolver 解析:
DispatcherServlet
将逻辑视图名交给ViewResolver
。ViewResolver
根据配置查找对应的物理视图资源(如/WEB-INF/views/userList.jsp
)。 - View 渲染:
DispatcherServlet
调用View
的render()
方法。View
接收 Controller 传递过来的模型数据,结合视图模板(如 JSP 文件)生成最终的响应内容(如 HTML)。 - 响应返回:
DispatcherServlet
将生成的响应发送回给客户端(浏览器)。
理解这个流程图,有助于你在后续的配置和代码编写中知道每个文件和类是做什么的。
第三章:搭建第一个 Spring MVC 项目
现在,让我们动手创建一个简单的 Spring MVC 应用,实现一个接收请求并返回一个页面的功能。我们将使用 Maven 进行项目管理。
3.1 创建 Maven Web 项目
- 打开你的 IDE (如 IntelliJ IDEA 或 Eclipse)。
- 创建一个新的 Maven Project。
- 选择
maven-archetype-webapp
原型。这个原型会帮你生成一个基本的 Web 项目结构,包含src/main/webapp
目录和WEB-INF
目录,以及一个web.xml
文件。 - 填写 GroupId、ArtifactId 等信息,创建项目。
-
创建完成后,项目结构大致如下:
your-project-name
├── pom.xml
└── src
└── main
├── java (你需要手动创建这个目录来存放Java源代码)
├── resources (你需要手动创建这个目录来存放配置文件等)
└── webapp
├── WEB-INF
│ └── web.xml
└── index.jsp
请手动在src/main
下创建java
和resources
目录,并标记为 Source Root 和 Resources Root (在 IDE 中操作)。
3.2 添加 Spring MVC 依赖
打开项目的 pom.xml
文件,添加 Spring MVC 相关的依赖。
“`xml
<!-- Servlet API (provided by web server) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version> <!-- 根据你的服务器支持的版本选择 -->
<scope>provided</scope>
</dependency>
<!-- JSP API (provided by web server) -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version> <!-- 根据你的服务器支持的版本选择 -->
<scope>provided</scope>
</dependency>
<!-- JSTL (JSP Standard Tag Library) - Optional but useful for views -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Logging (slf4j & logback example) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>runtime</scope>
</dependency>
<!-- Test dependency (optional for now) -->
<!--
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
-->
``
**注意:**、
javax.servlet-api和
javax.servlet.jsp-api的版本可能需要根据你的环境和偏好进行调整。
provided` scope 表示这些依赖由运行时的 Web 服务器(如 Tomcat)提供,不会打包进你的 WAR 文件。
保存 pom.xml
,Maven 会自动下载这些依赖。
3.3 配置 web.xml (或使用 Java Config – 后续介绍)
web.xml
是 Web 应用的部署描述符。我们需要在这里配置 DispatcherServlet
,告诉服务器将哪些请求交给 Spring MVC 处理。
打开 src/main/webapp/WEB-INF/web.xml
,修改其内容如下:
“`xml
“`
这段配置做了两件事:
1. 定义了一个名为 springmvc
的 Servlet,其实现类是 org.springframework.web.servlet.DispatcherServlet
。
2. 通过 contextConfigLocation
参数指定了 Spring MVC 的配置文件位置为 classpath:springmvc-config.xml
。这意味着我们需要在 src/main/resources
目录下创建这个文件。
3. load-on-startup
设置为 1,表示服务器启动时就加载并初始化这个 Servlet。
4. 通过 <servlet-mapping>
将所有请求路径 (/
) 都交给名为 springmvc
的 DispatcherServlet
处理。
3.4 创建 Spring MVC 配置文件
在 src/main/resources
目录下创建 springmvc-config.xml
文件。这个文件是 Spring MVC 的核心配置,用来配置扫描哪些包、视图解析器等等。
“`xml
<!-- 启用注解驱动的Spring MVC功能 -->
<!-- 包含了处理器映射器、处理器适配器等配置 -->
<mvc:annotation-driven/>
<!-- 配置组件扫描,告诉Spring在哪里查找Controller等注解组件 -->
<!-- 扫描 com.example.controller 包及其子包 -->
<context:component-scan base-package="com.example.controller"/> <!-- 将这里的包名替换为你创建Controller的实际包名 -->
<!-- 配置视图解析器 InternalResourceViewResolver -->
<!-- 它会解析Controller返回的逻辑视图名 -->
<!-- 例如,返回 "hello",前缀是 "/WEB-INF/views/",后缀是 ".jsp" -->
<!-- 最终会解析到 /WEB-INF/views/hello.jsp -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/> <!-- 视图文件存放的目录 -->
<property name="suffix" value=".jsp"/> <!-- 视图文件的后缀 -->
</bean>
<!-- 配置静态资源处理,例如 js, css, images 等 -->
<!-- /statics/** 表示所有 /statics/ 开头的请求 -->
<!-- location="/statics/" 表示静态资源在Web应用根目录下的 /statics/ 目录 -->
<!-- 如果没有这个配置,DispatcherServlet会拦截所有请求,包括静态资源,导致访问不到 -->
<mvc:resources mapping="/statics/**" location="/statics/"/>
<!-- 你也可以配置多个静态资源目录 -->
<!-- <mvc:resources mapping="/css/**" location="/css/"/> -->
<!-- <mvc:resources mapping="/js/**" location="/js/"/> -->
“`
这个配置文件是 Spring MVC 配置的核心:
1. <mvc:annotation-driven/>
: 启用了 @Controller
、@RequestMapping
等注解的支持,这是使用注解驱动开发的关键。
2. <context:component-scan base-package="...">
: 配置 Spring 扫描指定的包及其子包,查找带有 @Controller
、@Service
、@Repository
等注解的类,并将它们注册为 Spring Bean。确保 base-package
指向你存放 Controller 类的包。
3. <bean id="viewResolver" ...>
: 配置了一个 InternalResourceViewResolver
视图解析器。它告诉 Spring,如果一个 Controller 方法返回了一个字符串(如 “hello”),就去 /WEB-INF/views/
目录下查找名为 hello.jsp
的文件作为视图。
4. <mvc:resources ...>
: 配置了静态资源的处理。通常我们不希望 Spring MVC 的 DispatcherServlet
处理静态资源(如 CSS、JavaScript、图片),因为这效率较低。这个配置告诉 Spring,对于符合指定 mapping 模式的请求,直接去 location 指定的目录查找资源并返回,跳过 Controller 处理流程。
3.5 创建 Controller
现在,我们在 src/main/java
目录下创建 Controller 类。根据 springmvc-config.xml
中的 component-scan
配置,你应该在 com.example.controller
包下创建。
创建一个名为 HomeController.java
的类:
“`java
package com.example.controller; // 确保包名与springmvc-config.xml中的base-package匹配
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
// 使用 @Controller 注解标识这是一个控制器类
@Controller
public class HomeController {
// 使用 @RequestMapping 注解将请求路径映射到这个方法
// method = RequestMethod.GET 表示只处理GET请求
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model) {
// Controller 方法可以接收一个 Model 参数
// Model 对象用于向视图传递数据
model.addAttribute("message", "Hello, Spring MVC!");
// 方法返回一个字符串,这个字符串就是逻辑视图名
// 根据springmvc-config.xml中的ViewResolver配置,
// "index" 会被解析为 "/WEB-INF/views/index.jsp"
return "index";
}
// 你可以创建更多的方法来处理不同的请求
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String sayHello(Model model) {
model.addAttribute("name", "User"); // 添加数据
return "hello"; // 返回逻辑视图名 "hello"
}
}
“`
这个 Controller 类:
1. 使用 @Controller
注解,Spring 会扫描到它并将其作为控制器进行管理。
2. home()
方法使用 @RequestMapping(value = "/", method = RequestMethod.GET)
注解,表示它将处理根路径 (/
) 的 GET 请求。
3. 方法接收一个 Model
参数,用于携带数据到视图。
4. model.addAttribute("message", "Hello, Spring MVC!")
将一个键值对添加到 Model 中,视图可以通过键名获取到值。
5. 方法返回字符串 "index"
。这就是逻辑视图名。
3.6 创建视图 (JSP)
根据 springmvc-config.xml
中的 View Resolver 配置,逻辑视图名 "index"
对应的是 /WEB-INF/views/index.jsp
。
在 src/main/webapp/WEB-INF/views
目录下(如果 views 目录不存在,请手动创建)创建一个 index.jsp
文件。
“`jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>
Welcome to Spring MVC!
${message}
“`
同样,创建 /WEB-INF/views/hello.jsp
文件:
“`jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>
Hello Page
Hello, ${name}!
“`
这些 JSP 文件是简单的 HTML 页面,其中 ${message}
和 ${name}
使用了 EL 表达式来显示 Controller 通过 Model 传递过来的数据。
3.7 部署和运行
- 将你的项目部署到一个支持 Servlet 3.0 或更高版本的 Web 服务器(如 Tomcat 8+,Jetty 等)。大多数 IDE 都有直接部署到内置或配置的服务器的功能。例如,在 IntelliJ IDEA 中,你可以添加一个 Tomcat Run Configuration,然后部署你的项目。
- 启动服务器。
- 打开浏览器,访问你的应用。如果你的应用部署在 Tomcat 的 root 路径下,并且端口是 8080,你可以访问
http://localhost:8080/
。如果部署在特定上下文路径下(例如/my-app
),则访问http://localhost:8080/my-app/
。
你应该能看到 index.jsp
页面的内容,其中显示了 Controller 传递的 “Hello, Spring MVC!” 消息。点击 “Say Hello” 链接,你应该能跳转到 /hello
路径,看到 hello.jsp
页面显示 “Hello, User!”。
恭喜!你已经成功搭建并运行了第一个 Spring MVC 应用。
第四章:更进一步 – 请求参数与表单处理
前面的例子只是简单的页面跳转和数据传递。实际应用中,我们需要处理用户提交的数据,比如查询参数或表单数据。
4.1 处理请求参数
使用 @RequestParam
注解可以轻松获取请求中的参数。
修改 HomeController.java
,添加一个方法来接收一个名字参数:
“`java
// … (imports and class definition)
@RequestMapping(value = "/greet", method = RequestMethod.GET)
// @RequestParam("name") String name: 从请求参数中获取名为"name"的值,绑定到name变量
// required = false 表示这个参数不是必须的
// defaultValue = "Guest" 表示如果参数不存在,就使用"Guest"作为默认值
public String greet(@RequestParam(value = "name", required = false, defaultValue = "Guest") String name, Model model) {
model.addAttribute("greeting", "Hello, " + name + "!");
return "greet"; // 逻辑视图名
}
// … (other methods)
“`
创建 /WEB-INF/views/greet.jsp
:
“`jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>
Greeting
${greeting}
“`
现在你可以访问 http://localhost:8080/my-app/greet?name=World
,页面将显示 “Hello, World!”。如果只访问 http://localhost:8080/my-app/greet
,页面将显示 “Hello, Guest!”。
4.2 处理表单提交
处理 HTML 表单提交是 Web 应用的常见需求。Spring MVC 使用 @ModelAttribute
注解来绑定表单数据到一个 Java 对象(通常称为 Command Object 或 Form Object)。
首先,创建一个简单的 Java 类来表示表单数据,例如 UserForm.java
(在 com.example.model
包或其他合适的包下创建):
“`java
package com.example.model; // 创建一个新的包来存放模型类
public class UserForm {
private String username;
private int age;
// 需要有无参构造函数
public UserForm() {
}
// 需要有getter和setter方法,Spring MVC通过它们进行数据绑定
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "UserForm{" +
"username='" + username + '\'' +
", age=" + age +
'}';
}
}
“`
修改 HomeController.java
,添加处理表单的方法:
“`java
// … (imports)
import com.example.model.UserForm;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; // 用于处理POST请求的快捷方式
@Controller
public class HomeController {
// ... (home, sayHello, greet methods)
// 显示提交表单的页面
@GetMapping("/user/register") // 使用 @GetMapping 简化GET请求映射
public String showRegistrationForm(Model model) {
// 向模型中添加一个空的 UserForm 对象,供表单使用
// <form:form modelAttribute="userForm"> 会查找这个对象
model.addAttribute("userForm", new UserForm());
return "registrationForm"; // 返回表单页面的逻辑视图名
}
// 处理表单提交
@PostMapping("/user/register") // 使用 @PostMapping 简化POST请求映射
// @ModelAttribute("userForm") UserForm userForm: 将表单数据绑定到 userForm 对象
// BindingResult result: 包含绑定和验证的结果(用于数据校验,后面可以学)
public String processRegistration(@ModelAttribute("userForm") UserForm userForm, Model model) {
// 在这里处理 userForm 对象,比如保存到数据库等
System.out.println("Received registration data: " + userForm); // 打印到控制台查看
// 将userForm对象添加到模型中,以便在结果页面显示
model.addAttribute("submittedUser", userForm);
// 返回处理结果页面的逻辑视图名
return "registrationSuccess";
}
}
``
showRegistrationForm
**注意:**方法使用了
@GetMapping,它是
@RequestMapping(method = RequestMethod.GET)的快捷方式。同理,
processRegistration方法使用了
@PostMapping`。这些是 Spring 4.3+ 引入的便捷注解。
创建 /WEB-INF/views/registrationForm.jsp
(为了方便,我们直接用HTML表单):
“`jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>
Register New User
“`
创建 /WEB-INF/views/registrationSuccess.jsp
:
“`jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>
Registration Successful!
Submitted Username: ${submittedUser.username}
Submitted Age: ${submittedUser.age}
“`
现在重新部署并运行应用。访问 http://localhost:8080/my-app/user/register
,填写表单并提交,你应该能看到提交成功页面,并显示你输入的信息。Spring MVC 自动将表单字段的数据绑定到了 UserForm
对象的相应属性上。
第五章:进阶之路与后续学习
通过上面的步骤,你已经掌握了 Spring MVC 的基本概念、工作流程以及如何搭建一个简单的应用并处理请求参数和表单。但这只是 Spring MVC 的冰山一角。
为了更好地掌握 Spring MVC 并构建更复杂的应用,你可以继续学习以下主题:
- 数据校验 (Validation): 使用 JSR 303 (Bean Validation) 和 Spring 的校验支持来验证用户输入数据的合法性。
- 异常处理 (Exception Handling): graceful 地处理应用运行时的各种异常。
- 文件上传 (File Upload): 处理用户上传的文件。
- RESTful 服务开发: Spring MVC 是构建 RESTful API 的强大工具,学习
@RestController
、@RequestBody
、@ResponseBody
等注解。 - 拦截器 (Interceptors): 在请求处理的不同阶段(请求前、请求后、视图渲染后)执行自定义逻辑,常用于登录检查、权限控制、日志记录等。
- 国际化 (Internationalization – I18n): 支持多语言应用。
- 主题 (Themes): 支持应用的多套外观。
- Java Config 代替 XML 配置: 随着 Spring Boot 的流行,使用 Java 类和注解 (
@Configuration
,@EnableWebMvc
) 来配置 Spring MVC 越来越普遍,这比 XML 更简洁、类型安全。 - 集成其他技术: 如何集成 Spring Data (JPA/Hibernate), Spring Security, Thymeleaf/FreeMarker (替代 JSP) 等。
- 测试: 学习如何对 Controller 进行单元测试和集成测试。
总结
Spring MVC 是一个成熟、强大且灵活的 Java Web 框架。通过本文的学习,你应该对它的核心概念、工作流程有了清晰的认识,并且能够动手搭建和运行一个基本的 Spring MVC 应用。
从零开始学习一个新框架可能会有挑战,但请记住:实践是最好的老师。不断动手尝试、修改代码、查看文档、搜索遇到的问题,你的技能就会逐步提升。
希望这篇指南能为你开启 Spring MVC 的学习之旅提供一个坚实的基础。祝你学习愉快!