Spring MVC 零基础入门指南 – wiki基地


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 请求处理流程如下:

  1. 请求到达: 用户向服务器发送 HTTP 请求。
  2. DispatcherServlet 接收: 所有请求首先被配置在 web.xml(或 Java Config)中的 DispatcherServlet 捕获。
  3. Handler Mapping 查找: DispatcherServlet 查询 HandlerMapping,根据请求的 URL 查找能处理该请求的 Handler(通常是一个 Controller 方法)。
  4. Handler Adapter 调用: 找到对应的 Handler 后,DispatcherServlet 通过 HandlerAdapter 调用 Handler 的方法。Handler Adapter 负责处理参数绑定、数据校验等。
  5. Controller 处理: Controller 方法开始执行。它通常会调用 Service 层或 Model 层进行业务逻辑处理和数据获取。
  6. 返回 ModelAndView: Controller 方法执行完毕后,返回一个 ModelAndView 对象(或视图名、Model 对象等)。ModelAndView 包含了逻辑视图名和需要在视图中显示的数据。
  7. View Resolver 解析: DispatcherServlet 将逻辑视图名交给 ViewResolverViewResolver 根据配置查找对应的物理视图资源(如 /WEB-INF/views/userList.jsp)。
  8. View 渲染: DispatcherServlet 调用 Viewrender() 方法。View 接收 Controller 传递过来的模型数据,结合视图模板(如 JSP 文件)生成最终的响应内容(如 HTML)。
  9. 响应返回: DispatcherServlet 将生成的响应发送回给客户端(浏览器)。

理解这个流程图,有助于你在后续的配置和代码编写中知道每个文件和类是做什么的。

第三章:搭建第一个 Spring MVC 项目

现在,让我们动手创建一个简单的 Spring MVC 应用,实现一个接收请求并返回一个页面的功能。我们将使用 Maven 进行项目管理。

3.1 创建 Maven Web 项目

  1. 打开你的 IDE (如 IntelliJ IDEA 或 Eclipse)。
  2. 创建一个新的 Maven Project。
  3. 选择 maven-archetype-webapp 原型。这个原型会帮你生成一个基本的 Web 项目结构,包含 src/main/webapp 目录和 WEB-INF 目录,以及一个 web.xml 文件。
  4. 填写 GroupId、ArtifactId 等信息,创建项目。
  5. 创建完成后,项目结构大致如下:

    your-project-name
    ├── pom.xml
    └── src
    └── main
    ├── java (你需要手动创建这个目录来存放Java源代码)
    ├── resources (你需要手动创建这个目录来存放配置文件等)
    └── webapp
    ├── WEB-INF
    │ └── web.xml
    └── index.jsp

    请手动在 src/main 下创建 javaresources 目录,并标记为 Source Root 和 Resources Root (在 IDE 中操作)。

3.2 添加 Spring MVC 依赖

打开项目的 pom.xml 文件,添加 Spring MVC 相关的依赖。

“`xml
4.0.0
com.example
my-springmvc-app war 1.0-SNAPSHOT
http://maven.apache.org

5.3.20
1.8
1.8




org.springframework
spring-webmvc
${spring.version}

<!-- 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>
-->

org.apache.maven.plugins
maven-war-plugin
3.3.2
org.apache.maven.plugins
maven-compiler-plugin
3.10.1
${maven.compiler.source}
${maven.compiler.target}
``
**注意:**
javax.servlet-apijavax.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


Archetype Created Web Application


springmvc
org.springframework.web.servlet.DispatcherServlet



contextConfigLocation
classpath:springmvc-config.xml


1



springmvc
/


“`

这段配置做了两件事:
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> 将所有请求路径 (/) 都交给名为 springmvcDispatcherServlet 处理。

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″%>





Spring MVC Home

Welcome to Spring MVC!

${message}

Say Hello


“`

同样,创建 /WEB-INF/views/hello.jsp 文件:

“`jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>





Hello Page

Hello Page

Hello, ${name}!

Go Home


“`

这些 JSP 文件是简单的 HTML 页面,其中 ${message}${name} 使用了 EL 表达式来显示 Controller 通过 Model 传递过来的数据。

3.7 部署和运行

  1. 将你的项目部署到一个支持 Servlet 3.0 或更高版本的 Web 服务器(如 Tomcat 8+,Jetty 等)。大多数 IDE 都有直接部署到内置或配置的服务器的功能。例如,在 IntelliJ IDEA 中,你可以添加一个 Tomcat Run Configuration,然后部署你的项目。
  2. 启动服务器。
  3. 打开浏览器,访问你的应用。如果你的应用部署在 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 Page

Greeting

${greeting}

Go Home


“`

现在你可以访问 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″%>





User Registration

Register New User





Go Home


“`

创建 /WEB-INF/views/registrationSuccess.jsp:

“`jsp
<%@ page language=”java” contentType=”text/html; charset=UTF-8″ pageEncoding=”UTF-8″%>





Registration Success

Registration Successful!

Submitted Username: ${submittedUser.username}

Submitted Age: ${submittedUser.age}

Go Home


“`

现在重新部署并运行应用。访问 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 的学习之旅提供一个坚实的基础。祝你学习愉快!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部