SpringMVC学习笔记一: SpringMVC原理及实例解析

在Java Web开发领域,SpringMVC(Spring Web MVC)作为Spring框架的核心模块之一,是构建灵活、高效的Web应用程序的主流选择。它基于MVC(Model-View-Controller)设计模式,通过分离关注点(数据、展示、控制逻辑),简化了Web应用的开发流程,提升了代码的可维护性和扩展性。

本文作为SpringMVC学习笔记的第一篇,将从核心原理实战案例两方面展开,帮助读者深入理解SpringMVC的工作机制,并通过一个完整的示例掌握其基本使用方法。无论你是Java Web初学者,还是希望系统梳理SpringMVC知识的开发者,本文都能为你提供清晰的学习路径。

目录#

  1. 什么是SpringMVC?
  2. MVC设计模式回顾
  3. SpringMVC核心组件解析
  4. SpringMVC请求处理流程
  5. 实战案例:从零搭建SpringMVC应用
  6. 常见实践与最佳实践
  7. 总结
  8. 参考资料

1. 什么是SpringMVC?#

SpringMVC是Spring框架提供的Web层解决方案,它基于Servlet API实现,用于处理HTTP请求并构建Web应用。其核心目标是通过MVC模式将业务逻辑、数据展示和用户交互分离,降低代码耦合度。

核心特性:#

  • 松耦合设计:通过依赖注入(DI)和控制反转(IoC)管理组件,减少硬编码依赖。
  • 灵活的URL映射:支持注解式请求映射,简化URL与控制器方法的绑定。
  • 强大的数据绑定:自动将请求参数绑定到Java对象,支持类型转换。
  • 内置视图解析:支持JSP、Thymeleaf、FreeMarker等多种视图技术。
  • 可扩展的拦截器:通过拦截器实现权限控制、日志记录等横切功能。
  • 与Spring生态无缝集成:可直接使用Spring的事务管理、AOP等功能。

2. MVC设计模式回顾#

在深入SpringMVC之前,先回顾MVC设计模式的核心思想:将应用分为三个核心模块,各司其职。

  • Model(模型):封装应用数据和业务逻辑,通常对应JavaBean或领域模型。
  • View(视图):负责数据展示,如JSP、HTML页面,不包含业务逻辑。
  • Controller(控制器):接收用户请求,调用模型处理业务,返回结果给视图。

MVC的优势在于职责分离:模型专注于数据和业务,视图专注于展示,控制器专注于流程控制,避免代码混杂。

3. SpringMVC核心组件解析#

SpringMVC的核心是通过一系列组件协同工作,完成请求处理和响应。以下是关键组件及其作用:

3.1 DispatcherServlet(前端控制器)#

  • 作用:整个SpringMVC的"中央调度器",接收所有HTTP请求,协调其他组件工作。
  • 地位:相当于MVC中的"Controller"角色,但实际职责是分发请求,而非处理业务逻辑。

3.2 HandlerMapping(处理器映射器)#

  • 作用:根据请求URL查找对应的Handler(处理器,即Controller中的方法)
  • 常见实现RequestMappingHandlerMapping(基于注解@RequestMapping映射)。

3.3 HandlerAdapter(处理器适配器)#

  • 作用:根据Handler的类型(如注解式、XML配置式),调用对应的Handler方法。
  • 常见实现RequestMappingHandlerAdapter(适配注解式Controller)。

3.4 Handler(处理器)#

  • 作用:即业务控制器(Controller类中的方法),负责处理具体业务逻辑,返回ModelAndView(模型数据+视图名)。

3.5 ModelAndView#

  • 作用:封装处理结果,包含两部分:
    • Model:键值对形式的业务数据(如查询结果)。
    • View:逻辑视图名(如"index"),需通过ViewResolver解析为物理视图。

3.6 ViewResolver(视图解析器)#

  • 作用:将逻辑视图名解析为物理视图对象(如JSP路径)。
  • 示例InternalResourceViewResolver(解析JSP视图,配置前缀/WEB-INF/views/和后缀.jsp)。

3.7 Interceptor(拦截器)#

  • 作用:在请求处理的不同阶段(如请求前、请求后、视图渲染后)执行自定义逻辑,如登录验证、日志记录。

4. SpringMVC请求处理流程#

SpringMVC的请求处理流程可概括为以下步骤,结合组件协同工作:

  1. 用户发送请求:浏览器或客户端发送HTTP请求(如http://localhost:8080/hello)。
  2. DispatcherServlet接收请求:所有请求被DispatcherServlet拦截(通过web.xml配置映射)。
  3. HandlerMapping查找HandlerDispatcherServlet调用HandlerMapping,根据URL找到对应的Handler(Controller方法)。
  4. HandlerAdapter执行HandlerDispatcherServlet通过HandlerAdapter调用Handler方法,处理业务逻辑,返回ModelAndView
  5. ViewResolver解析视图DispatcherServletModelAndView中的逻辑视图名交给ViewResolver,解析为物理视图(如JSP路径)。
  6. 渲染视图并响应:视图对象(如JSP)结合Model数据渲染页面,生成HTML响应给客户端。

流程图示意

请求 → DispatcherServlet → HandlerMapping → Handler → HandlerAdapter → ModelAndView → ViewResolver → View → 响应

5. 实战案例:从零搭建SpringMVC应用#

下面通过一个"Hello World"示例,演示SpringMVC的基本使用。

5.1 环境准备#

  • 开发工具:IntelliJ IDEA
  • 构建工具:Maven
  • 服务器:Tomcat 9
  • 依赖:SpringMVC、Servlet API、JSTL

5.2 步骤1:创建Maven Web项目#

  1. 新建Maven项目,选择maven-archetype-webapp
  2. 配置pom.xml,添加核心依赖:
<dependencies>
    <!-- SpringMVC核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.20</version>
    </dependency>
    <!-- Servlet API -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <!-- JSTL(用于JSP页面) -->
    <dependency>
        <groupId>javax.servlet.jsp.jstl</groupId>
        <artifactId>jstl-api</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

5.3 步骤2:配置web.xml(注册DispatcherServlet)#

src/main/webapp/WEB-INF/web.xml中配置DispatcherServlet

<?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>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 加载SpringMVC配置文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!-- 启动时加载(优先级1) -->
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <!-- 映射所有请求(/表示除.jsp外的所有请求) -->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

5.4 步骤3:创建SpringMVC配置文件#

src/main/resources下创建springmvc-servlet.xml,配置组件扫描和视图解析器:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">
 
    <!-- 组件扫描:扫描Controller所在的包 -->
    <context:component-scan base-package="com.example.controller"/>
 
    <!-- 启用SpringMVC注解驱动(支持@RequestMapping等注解) -->
    <mvc:annotation-driven/>
 
    <!-- 视图解析器:解析JSP视图 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 前缀:JSP文件所在目录 -->
        <property name="prefix" value="/WEB-INF/views/"/>
        <!-- 后缀:JSP文件扩展名 -->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

5.5 步骤4:创建Controller#

com.example.controller包下创建HelloController

package com.example.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller // 标记为控制器组件
public class HelloController {
 
    // 映射请求URL:/hello
    @RequestMapping("/hello")
    public String hello(Model model) {
        // 向模型中添加数据(键值对)
        model.addAttribute("message", "Hello, SpringMVC!");
        // 返回逻辑视图名(由视图解析器解析为 /WEB-INF/views/hello.jsp)
        return "hello";
    }
}

5.6 步骤5:创建JSP视图#

src/main/webapp/WEB-INF/views目录下创建hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC Hello</title>
</head>
<body>
    <h1>${message}</h1> <!-- 从Model中获取数据 -->
</body>
</html>

5.7 步骤6:部署与测试#

  1. 配置Tomcat服务器,将项目部署到Tomcat。
  2. 启动Tomcat,访问http://localhost:8080/项目名/hello
  3. 页面显示Hello, SpringMVC!,表示成功。

6. 常见实践与最佳实践#

6.1 注解使用规范#

  • @Controller vs @RestController
    • @Controller:返回逻辑视图名,需配合视图解析器渲染页面。
    • @RestController:等价于@Controller + @ResponseBody,直接返回数据(JSON/XML),适用于RESTful API。
  • 请求映射注解:优先使用@GetMapping@PostMapping等细分注解(替代@RequestMapping(method = RequestMethod.GET)),语义更清晰。

6.2 控制器设计原则#

  • 保持控制器简洁:控制器仅负责接收请求、调用业务层、返回结果,不包含复杂业务逻辑(业务逻辑交给Service层)。
  • 参数绑定:使用@RequestParam接收URL参数,@PathVariable接收路径变量(如/user/{id}),@ModelAttribute绑定表单数据到JavaBean。

6.3 视图解析与静态资源处理#

  • 静态资源(CSS/JS/图片):默认DispatcherServlet会拦截所有请求,导致静态资源无法访问。需在Spring配置中添加:
    <mvc:default-servlet-handler/> <!-- 让默认Servlet处理静态资源 -->
  • 视图技术选择:JSP适用于简单页面,复杂场景推荐Thymeleaf(无依赖Servlet容器,支持HTML原型)。

6.4 异常处理#

  • 使用@ExceptionHandler注解在Controller中定义异常处理方法,或通过@ControllerAdvice全局捕获异常,避免页面直接显示错误堆栈。

6.5 输入验证#

  • 使用JSR-303注解(如@NotNull@Size)配合@Valid对请求参数进行校验,提升数据安全性。

7. 总结#

本文从SpringMVC的核心概念、工作原理出发,通过一个完整的"Hello World"示例,展示了SpringMVC的基本使用流程。关键要点包括:

  • SpringMVC基于MVC模式,通过DispatcherServlet协调各组件完成请求处理。
  • 核心组件包括HandlerMapping、HandlerAdapter、ViewResolver等,需理解其协同流程。
  • 实战中需注意配置文件(web.xml、Spring配置)、控制器注解、视图解析等细节。

后续学习可深入SpringMVC的高级特性,如拦截器、数据绑定、RESTful API设计等。

8. 参考资料#

  1. Spring官方文档 - Spring Web MVC
  2. 《Spring实战(第5版)》- Craig Walls
  3. SpringMVC教程 - Runoob
  4. IntelliJ IDEA + Maven + Tomcat搭建SpringMVC项目