【JAVA 进阶】SpringMVC全面解析:从入门到实战的核心知识点梳理

文章目录

  • 前言
  • 一、SpringMVC概述
    • [1.1 MVC设计模式简介](#1.1 MVC设计模式简介)
    • [1.2 SpringMVC的定义与核心优势](#1.2 SpringMVC的定义与核心优势)
    • [1.3 SpringMVC的应用场景](#1.3 SpringMVC的应用场景)
  • 二、SpringMVC核心原理与执行流程
    • [2.1 SpringMVC核心组件](#2.1 SpringMVC核心组件)
      • [2.1.1 前端控制器(DispatcherServlet)](#2.1.1 前端控制器(DispatcherServlet))
      • [2.1.2 处理器映射器(HandlerMapping)](#2.1.2 处理器映射器(HandlerMapping))
      • [2.1.3 处理器适配器(HandlerAdapter)](#2.1.3 处理器适配器(HandlerAdapter))
      • [2.1.4 处理器(Handler)](#2.1.4 处理器(Handler))
      • [2.1.5 视图解析器(ViewResolver)](#2.1.5 视图解析器(ViewResolver))
      • [2.1.6 视图(View)](#2.1.6 视图(View))
      • [2.1.7 模型和视图(ModelAndView)](#2.1.7 模型和视图(ModelAndView))
    • [2.2 SpringMVC执行流程详解](#2.2 SpringMVC执行流程详解)
  • 三、SpringMVC入门实战
    • [3.1 环境搭建(基于Spring Boot)](#3.1 环境搭建(基于Spring Boot))
      • [3.1.1 创建Maven项目](#3.1.1 创建Maven项目)
      • [3.1.2 引入依赖](#3.1.2 引入依赖)
      • [3.1.3 编写主启动类](#3.1.3 编写主启动类)
    • [3.2 第一个SpringMVC程序:Hello World](#3.2 第一个SpringMVC程序:Hello World)
      • [3.2.1 创建Controller类](#3.2.1 创建Controller类)
      • [3.2.2 启动项目并测试](#3.2.2 启动项目并测试)
    • [3.3 请求参数绑定](#3.3 请求参数绑定)
      • [3.3.1 基本类型参数绑定](#3.3.1 基本类型参数绑定)
      • [3.3.2 引用类型参数绑定](#3.3.2 引用类型参数绑定)
      • [3.3.3 集合类型参数绑定](#3.3.3 集合类型参数绑定)
    • [3.4 视图解析与页面跳转](#3.4 视图解析与页面跳转)
      • [3.4.1 引入Thymeleaf依赖](#3.4.1 引入Thymeleaf依赖)
      • [3.4.2 配置视图解析器](#3.4.2 配置视图解析器)
      • [3.4.3 编写视图页面](#3.4.3 编写视图页面)
      • [3.4.3 编写Controller方法实现页面跳转](#3.4.3 编写Controller方法实现页面跳转)
  • 四、SpringMVC高级特性
    • [4.1 拦截器(Interceptor)](#4.1 拦截器(Interceptor))
      • [4.1.1 拦截器的工作原理](#4.1.1 拦截器的工作原理)
      • [4.1.2 自定义拦截器实现](#4.1.2 自定义拦截器实现)
      • [4.1.3 配置拦截器](#4.1.3 配置拦截器)
    • [4.2 异常处理](#4.2 异常处理)
      • [4.2.1 @ExceptionHandler注解(局部异常处理)](#4.2.1 @ExceptionHandler注解(局部异常处理))
      • [4.2.2 @ControllerAdvice + @ExceptionHandler(全局异常处理)](#4.2.2 @ControllerAdvice + @ExceptionHandler(全局异常处理))
    • [4.3 文件上传](#4.3 文件上传)
      • [4.3.1 引入文件上传依赖](#4.3.1 引入文件上传依赖)
      • [4.3.2 配置文件上传解析器](#4.3.2 配置文件上传解析器)
      • [4.3.3 实现文件上传功能](#4.3.3 实现文件上传功能)
      • [4.3.4 编写文件上传Controller方法](#4.3.4 编写文件上传Controller方法)
  • 五、SpringMVC与其他技术的集成
    • [5.1 SpringMVC与Spring的集成](#5.1 SpringMVC与Spring的集成)
    • [5.2 SpringMVC与MyBatis的集成](#5.2 SpringMVC与MyBatis的集成)
      • [5.2.1 引入依赖](#5.2.1 引入依赖)
      • [5.2.2 配置数据源和SqlSessionFactory](#5.2.2 配置数据源和SqlSessionFactory)
      • [5.2.3 编写Mapper接口和映射文件](#5.2.3 编写Mapper接口和映射文件)
      • [5.2.4 在Service中注入Mapper接口](#5.2.4 在Service中注入Mapper接口)
      • [5.2.5 在Controller中调用Service](#5.2.5 在Controller中调用Service)
  • 六、总结与扩展
    • [6.1 本文知识点总结](#6.1 本文知识点总结)
    • [6.2 知识点扩展](#6.2 知识点扩展)

前言

在Java EE企业级开发领域,SpringMVC作为轻量级的Web层开发框架,凭借其清晰的架构设计、灵活的配置方式以及与Spring生态的无缝集成,成为了当前主流的Web开发技术选型之一。它基于MVC(Model-View-Controller)设计模式,通过分离模型、视图和控制器的职责,有效降低了代码耦合度,提升了项目的可维护性和扩展性。本文将从SpringMVC的基础概念出发,逐步深入其核心原理、核心组件、实战应用、高级特性等关键知识点,结合理论讲解与代码示例,帮助读者系统掌握SpringMVC技术栈。最后将对全文知识点进行总结扩展,并推荐优质阅读资料,助力读者进一步深化学习。

一、SpringMVC概述

1.1 MVC设计模式简介

MVC(Model-View-Controller)是一种经典的软件架构设计模式,其核心思想是将应用程序的功能划分为三个独立的模块,通过明确的职责划分实现代码解耦。

  • Model(模型):负责封装应用程序的核心数据和业务逻辑,是应用程序的数据层和业务层的结合体。模型不依赖于视图和控制器,仅专注于数据的处理和业务规则的实现。常见的模型组件包括实体类(Entity)、服务类(Service)、数据访问类(DAO)等。

  • View(视图):负责向用户展示数据,是用户与应用程序交互的界面。视图仅负责数据的呈现,不涉及业务逻辑的处理。常见的视图技术包括JSP、Thymeleaf、Freemarker等。

  • Controller(控制器):负责接收用户的请求,协调模型和视图完成用户需求。控制器接收请求后,调用模型进行业务逻辑处理,获取处理结果后,选择合适的视图向用户展示数据。

MVC设计模式的优势在于实现了功能模块的分离,使得代码结构清晰,便于团队协作开发和后期维护。当需求发生变化时,只需修改对应的模块,不会影响其他模块的功能。

1.2 SpringMVC的定义与核心优势

SpringMVC是Spring框架的一个重要模块,是基于Java实现MVC设计模式的轻量级Web框架。它并非对MVC设计模式的全新实现,而是在Spring生态的基础上,对MVC架构进行了优化和封装,提供了一套简洁、高效的Web开发解决方案。

SpringMVC的核心优势主要体现在以下几个方面:

  • 与Spring无缝集成:SpringMVC是Spring框架的一部分,能够直接使用Spring的IOC容器、AOP等核心特性,无需额外的整合配置,降低了框架集成的复杂度。

  • 灵活的配置方式:支持XML配置和注解配置两种方式,注解配置简化了开发流程,提高了开发效率;XML配置则便于对全局配置进行统一管理,适用于复杂的项目场景。

  • 清晰的架构设计:基于MVC设计模式,职责划分明确,各组件之间耦合度低,便于代码的维护和扩展。

  • 强大的功能支持:提供了请求参数绑定、数据验证、视图解析、异常处理、文件上传等一系列完善的功能,满足企业级Web开发的各种需求。

  • 良好的扩展性:支持自定义拦截器、转换器、格式化器等组件,能够根据项目的特殊需求进行功能扩展。

1.3 SpringMVC的应用场景

SpringMVC适用于各种规模的Java Web项目开发,尤其是企业级应用项目。无论是中小型的管理系统、电商平台,还是大型的分布式Web应用,SpringMVC都能凭借其灵活的架构和强大的功能满足开发需求。此外,由于SpringMVC与Spring Boot、Spring Cloud等主流技术的无缝集成,它也成为了微服务架构中Web层开发的首选技术。

二、SpringMVC核心原理与执行流程

2.1 SpringMVC核心组件

SpringMVC的核心功能是通过一系列组件协同工作实现的,每个组件都有明确的职责。了解这些核心组件是掌握SpringMVC原理的关键。

2.1.1 前端控制器(DispatcherServlet)

DispatcherServlet是SpringMVC的核心控制器,负责接收所有用户的请求,并协调其他组件完成请求的处理。它是整个SpringMVC流程的入口,相当于一个"中央处理器"。DispatcherServlet的主要职责包括:

  • 接收HTTP请求,解析请求URL和请求参数;

  • 根据请求信息查找对应的处理器(Handler);

  • 调用处理器适配器(HandlerAdapter)执行处理器;

  • 接收处理器的处理结果(ModelAndView);

  • 调用视图解析器(ViewResolver)解析视图,渲染并返回响应结果。

2.1.2 处理器映射器(HandlerMapping)

HandlerMapping的职责是根据用户请求的URL,查找对应的处理器(Handler)和拦截器(Interceptor)。SpringMVC提供了多种HandlerMapping实现,例如:

  • RequestMappingHandlerMapping:支持@RequestMapping注解的处理器映射,是当前最常用的映射器;

  • BeanNameUrlHandlerMapping:根据Bean的名称作为URL进行映射;

  • SimpleUrlHandlerMapping:通过XML配置的方式,将URL与处理器进行直接映射。

当DispatcherServlet接收到请求后,会调用HandlerMapping获取对应的HandlerExecutionChain(包含处理器和拦截器)。

2.1.3 处理器适配器(HandlerAdapter)

HandlerAdapter的职责是适配不同类型的处理器,使得DispatcherServlet无需关心处理器的具体实现,能够统一调用处理器的处理方法。由于SpringMVC支持多种类型的处理器(如注解式处理器、控制器接口实现类等),不同处理器的调用方式不同,HandlerAdapter通过适配模式解决了这一问题。

常用的HandlerAdapter实现包括:

  • RequestMappingHandlerAdapter:适配使用@RequestMapping注解的处理器;

  • SimpleControllerHandlerAdapter:适配实现Controller接口的处理器;

  • SimpleServletHandlerAdapter:适配实现Servlet接口的处理器。

2.1.4 处理器(Handler)

Handler即业务处理器,是SpringMVC中处理具体业务逻辑的组件,相当于MVC架构中的Controller。处理器接收请求参数,调用业务层服务完成数据处理,最终返回处理结果(ModelAndView)。在实际开发中,处理器通常是一个使用@RequestMapping注解的Controller类中的方法。

2.1.5 视图解析器(ViewResolver)

ViewResolver的职责是根据处理器返回的ModelAndView中的视图名称,解析出具体的视图对象(View)。它将逻辑视图名转换为物理视图路径,例如将"index"解析为"/WEB-INF/views/index.jsp"。

常用的ViewResolver实现包括:

  • InternalResourceViewResolver:解析JSP视图,是最常用的视图解析器;

  • ThymeleafViewResolver:解析Thymeleaf视图;

  • FreeMarkerViewResolver:解析Freemarker视图。

2.1.6 视图(View)

View是视图组件,负责将处理器返回的数据(Model)渲染为用户可查看的界面。View接收Model中的数据,通过特定的视图技术(如JSP、Thymeleaf)将数据展示出来。不同的视图技术对应不同的View实现类。

2.1.7 模型和视图(ModelAndView)

ModelAndView是处理器返回的结果对象,包含了视图名称和需要展示的数据(Model)。其中,Model是一个键值对集合,用于存储需要传递给视图的数据;ViewName是逻辑视图名,用于视图解析器解析具体的视图。

2.2 SpringMVC执行流程详解

SpringMVC的请求处理流程是一个标准化的流程,各组件按照固定的顺序协同工作。以下是SpringMVC完整的执行流程,结合核心组件的交互进行说明:

  1. 用户发送HTTP请求:用户通过浏览器向服务器发送请求,请求URL例如"http://localhost:8080/springmvc/user/list"。

  2. 请求到达前端控制器(DispatcherServlet):服务器接收到请求后,根据Web.xml中的配置(或Spring Boot的自动配置),将请求转发给DispatcherServlet。DispatcherServlet是SpringMVC的入口,负责统一处理所有请求。

  3. DispatcherServlet调用处理器映射器(HandlerMapping):DispatcherServlet将请求URL传递给HandlerMapping,HandlerMapping根据URL查找对应的处理器(Handler)和拦截器(Interceptor),返回HandlerExecutionChain对象(包含处理器和拦截器列表)。

  4. DispatcherServlet调用处理器适配器(HandlerAdapter):DispatcherServlet根据HandlerMapping返回的处理器类型,选择对应的HandlerAdapter。HandlerAdapter负责适配处理器,调用处理器的处理方法(如Controller中的@RequestMapping注解方法)。

  5. 处理器执行业务逻辑并返回ModelAndView:处理器(Controller方法)接收请求参数,调用业务层(Service)的方法完成数据处理,将处理结果(数据)存入Model,设置逻辑视图名,最终返回ModelAndView对象。

  6. DispatcherServlet调用视图解析器(ViewResolver):DispatcherServlet将ModelAndView中的逻辑视图名传递给ViewResolver,ViewResolver解析出具体的物理视图路径(如"/WEB-INF/views/user/list.jsp"),返回View对象。

  7. 视图渲染数据:View对象接收Model中的数据,通过视图技术(如JSP)将数据渲染为HTML页面。

  8. 返回响应结果:渲染后的HTML页面通过HTTP响应返回给用户浏览器,用户看到最终的页面效果。

注意:在整个执行流程中,拦截器会在处理器执行前后进行拦截处理,实现权限控制、日志记录等功能。拦截器的执行顺序是:preHandle(处理器执行前)→ 处理器执行 → postHandle(处理器执行后,视图渲染前)→ afterCompletion(视图渲染后)。

三、SpringMVC入门实战

3.1 环境搭建(基于Spring Boot)

Spring Boot提供了自动配置功能,能够快速搭建SpringMVC项目,无需繁琐的XML配置。以下是基于Spring Boot的SpringMVC环境搭建步骤:

3.1.1 创建Maven项目

使用IDEA或Eclipse创建一个Maven项目,选择"Spring Initializr"模板(IDEA内置),填写项目基本信息(Group、Artifact、Version等)。

3.1.2 引入依赖

在pom.xml文件中引入Spring Boot Web依赖(包含SpringMVC核心依赖):

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring Boot Starter Web依赖会自动引入SpringMVC的核心组件(DispatcherServlet、HandlerMapping、ViewResolver等)以及Tomcat服务器依赖,实现开箱即用。

3.1.3 编写主启动类

创建Spring Boot主启动类,使用@SpringBootApplication注解标识:

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringMvcDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringMvcDemoApplication.class, args);
    }
}

@SpringBootApplication注解包含了@ComponentScan(组件扫描)、@EnableAutoConfiguration(自动配置)、@Configuration(配置类)三个核心注解,能够自动扫描当前包及其子包下的组件,并完成SpringMVC的自动配置。

3.2 第一个SpringMVC程序:Hello World

编写一个简单的Controller,实现"Hello World"功能,验证SpringMVC环境是否搭建成功。

3.2.1 创建Controller类

在com.example.springmvcdemo.controller包下创建HelloController类,使用@Controller注解标识控制器,使用@RequestMapping注解映射请求路径:

java 复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    // 映射请求路径:/hello
    @RequestMapping("/hello")
    @ResponseBody // 直接返回字符串,不进行视图渲染
    public String hello() {
        return "Hello SpringMVC!";
    }
}

说明:

  • @Controller:标识该类为SpringMVC的控制器组件,Spring会自动扫描并将其纳入IOC容器管理;

  • @RequestMapping("/hello"):映射HTTP请求路径"/hello"到该方法;

  • @ResponseBody:表示该方法的返回值直接作为HTTP响应体返回,不经过视图解析器解析视图。如果不使用该注解,SpringMVC会将返回值作为逻辑视图名进行解析。

3.2.2 启动项目并测试

运行主启动类SpringMvcDemoApplication,启动成功后,打开浏览器访问"http://localhost:8080/hello",浏览器会显示"Hello SpringMVC!",说明SpringMVC环境搭建成功,请求处理正常。

3.3 请求参数绑定

SpringMVC提供了强大的请求参数绑定功能,能够自动将HTTP请求参数绑定到Controller方法的参数上。常见的参数绑定场景包括基本类型参数、引用类型参数、集合类型参数等。

3.3.1 基本类型参数绑定

请求参数名与Controller方法参数名一致时,SpringMVC会自动完成参数绑定。例如:

java 复制代码
@RequestMapping("/user/find")
@ResponseBody
public String findUserById(Integer id, String name) {
    return "id: " + id + ", name: " + name;
}

访问URL:"http://localhost:8080/user/find?id=1\&name=zhangsan",响应结果:"id: 1, name: zhangsan"。

如果请求参数名与方法参数名不一致,可以使用@RequestParam注解指定请求参数名:

java 复制代码
@RequestMapping("/user/findByParam")
@ResponseBody
public String findByParam(@RequestParam("user_id") Integer id, @RequestParam("user_name") String name) {
    return "id: " + id + ", name: " + name;
}

访问URL:"http://localhost:8080/user/findByParam?user_id=2\&user_name=lisi",响应结果:"id: 2, name: lisi"。

3.3.2 引用类型参数绑定

当请求参数较多时,可以将参数封装为引用类型(如实体类),SpringMVC会自动将请求参数绑定到实体类的属性上(要求请求参数名与实体类属性名一致)。

第一步:创建User实体类:

java 复制代码
public class User {
    private Integer id;
    private String name;
    private Integer age;
    
    // 无参构造器、有参构造器、getter、setter方法
    public User() {}
    public User(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    // getter和setter方法省略
    @Override
    public String toString() {
        return "User{id=" + id + ", name='" + name + "', age=" + age + "}";
    }
}

第二步:编写Controller方法:

java 复制代码
@RequestMapping("/user/add")
@ResponseBody
public String addUser(User user) {
    return "添加用户:" + user.toString();
}

访问URL:"http://localhost:8080/user/add?id=3\&name=wangwu\&age=25",响应结果:"添加用户:User{id=3, name='wangwu', age=25}"。

3.3.3 集合类型参数绑定

当需要传递多个同类型参数时(如批量删除用户的ID列表),可以使用集合类型(List、Map)接收参数。此时需要将集合参数封装到一个VO(Value Object)类中,或者使用@RequestParam注解指定参数名。

示例1:使用List接收批量删除的ID:

java 复制代码
@RequestMapping("/user/deleteBatch")
@ResponseBody
public String deleteBatch(@RequestParam("ids") List<Integer> ids) {
    return "批量删除的ID:" + ids.toString();
}

访问URL:"http://localhost:8080/user/deleteBatch?ids=1\&ids=2\&ids=3",响应结果:"批量删除的ID:\[1, 2, 3]"。

示例2:使用VO类封装集合参数(适用于复杂场景):

java 复制代码
// 创建UserVO类
public class UserVO {
    private List<User> userList;
    // getter和setter方法
    public List<User> getUserList() {
        return userList;
    }
    public void setUserList(List<User> userList) {
        this.userList = userList;
    }
}

// Controller方法
@RequestMapping("/user/addBatch")
@ResponseBody
public String addBatch(UserVO userVO) {
    return "批量添加用户:" + userVO.getUserList().toString();
}

前端传递参数时,需要按照"userList[0].id=1&userList[0].name=zhangsan&userList[1].id=2&userList[1].name=lisi"的格式传递。

3.4 视图解析与页面跳转

在实际开发中,除了返回JSON数据(使用@ResponseBody),还经常需要返回页面视图。SpringMVC通过视图解析器(ViewResolver)完成逻辑视图名到物理视图路径的解析。以下是基于Thymeleaf视图技术的页面跳转示例(Thymeleaf是Spring Boot推荐的视图技术,比JSP更灵活、更强大)。

3.4.1 引入Thymeleaf依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

3.4.2 配置视图解析器

Spring Boot对Thymeleaf提供了自动配置,默认的视图解析规则如下:

  • 模板文件路径:classpath:/templates/

  • 模板文件后缀:.html

  • 逻辑视图名"index"会被解析为:classpath:/templates/index.html

如果需要自定义配置,可以在application.properties文件中添加以下配置:

properties 复制代码
#  thymeleaf模板前缀(默认classpath:/templates/)
spring.thymeleaf.prefix=classpath:/templates/pages/
#  thymeleaf模板后缀(默认.html)
spring.thymeleaf.suffix=.html
#  编码格式
spring.thymeleaf.encoding=UTF-8
#  模板模式
spring.thymeleaf.mode=HTML5

3.4.3 编写视图页面

在classpath:/templates/目录下创建index.html文件:

html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h1 th:text="${message}">欢迎访问首页</h1>
    <a th:href="@{/user/list}">查看用户列表</a>
</body>
</html>

在classpath:/templates/目录下创建user/list.html文件:

html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户列表</title>
</head>
<body>
    <h1>用户列表</h1>
    <table border="1">
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>年龄</th>
        </tr>
        <tr th:each="user : ${userList}">
            <td th:text="${user.id}"></td>
            <td th:text="${user.name}"></td>
            <td th:text="${user.age}"></td>
        </tr>
    </table>
</body>
</html>

3.4.3 编写Controller方法实现页面跳转

java 复制代码
@RequestMapping("/index")
public String toIndex(Model model) {
    // 向Model中存入数据,供视图页面使用
    model.addAttribute("message", "Hello SpringMVC + Thymeleaf!");
    // 返回逻辑视图名"index",视图解析器会解析为classpath:/templates/index.html
    return "index";
}

@RequestMapping("/user/list")
public String userList(Model model) {
    // 模拟从数据库查询用户列表
    List<User> userList = new ArrayList<>();
    userList.add(new User(1, "zhangsan", 22));
    userList.add(new User(2, "lisi", 23));
    userList.add(new User(3, "wangwu", 24));
    // 向Model中存入用户列表
    model.addAttribute("userList", userList);
    // 返回逻辑视图名"user/list",解析为classpath:/templates/user/list.html
    return "user/list";
}

测试:访问"http://localhost:8080/index",会跳转到index.html页面,显示"Hello SpringMVC + Thymeleaf!";点击"查看用户列表"链接,会跳转到user/list.html页面,显示用户列表数据。

四、SpringMVC高级特性

4.1 拦截器(Interceptor)

SpringMVC的拦截器类似于Servlet的过滤器(Filter),用于在请求处理的不同阶段对请求进行拦截和处理。拦截器可以实现权限控制、日志记录、参数校验、性能监控等功能。与Filter不同的是,拦截器是SpringMVC框架内部的组件,能够访问Spring的IOC容器,而Filter是Servlet规范的组件,作用范围更广。

4.1.1 拦截器的工作原理

拦截器通过实现HandlerInterceptor接口或继承HandlerInterceptorAdapter类(已过时,推荐实现接口)来定义。HandlerInterceptor接口提供了三个方法,对应拦截器的三个执行时机:

  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):在处理器(Handler)执行前执行。返回true表示放行,继续执行后续的拦截器和处理器;返回false表示拦截,不再执行后续操作。

  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):在处理器执行后、视图渲染前执行。可以通过ModelAndView对象对视图和数据进行修改。

  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):在视图渲染后、请求完成后执行。通常用于资源清理、日志记录等操作。

4.1.2 自定义拦截器实现

第一步:创建自定义拦截器类,实现HandlerInterceptor接口:

java 复制代码
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor implements HandlerInterceptor {
    // 处理器执行前拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 模拟登录验证:从Session中获取用户信息
        Object user = request.getSession().getAttribute("user");
        if (user == null) {
            // 未登录,重定向到登录页面
            response.sendRedirect(request.getContextPath() + "/login.html");
            return false;
        }
        // 已登录,放行
        return true;
    }

    // 处理器执行后、视图渲染前拦截
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 可以修改ModelAndView中的数据或视图
        if (modelAndView != null) {
            modelAndView.addObject("interceptorMsg", "来自LoginInterceptor的消息");
        }
    }

    // 视图渲染后、请求完成后拦截
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 资源清理、日志记录等操作
        System.out.println("请求处理完成,执行资源清理...");
    }
}

4.1.3 配置拦截器

在SpringMVC中,需要通过配置类(实现WebMvcConfigurer接口)来注册拦截器,并指定拦截的请求路径和排除的请求路径。

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册LoginInterceptor拦截器
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**") // 拦截所有请求
                .excludePathPatterns("/login.html", "/user/login"); // 排除登录页面和登录接口的请求
    }
}

说明:

  • addPathPatterns("/**"):表示拦截所有请求路径;

  • excludePathPatterns("/login.html", "/user/login"):表示排除对"/login.html"页面和"/user/login"接口的拦截,允许未登录用户访问这些资源。

4.2 异常处理

在Web应用开发中,异常处理是不可或缺的一部分。SpringMVC提供了多种异常处理方式,能够统一捕获和处理Controller层的异常,避免异常直接暴露给用户,提升用户体验。常用的异常处理方式包括:@ExceptionHandler注解、@ControllerAdvice注解、实现HandlerExceptionResolver接口等。

4.2.1 @ExceptionHandler注解(局部异常处理)

@ExceptionHandler注解用于在Controller内部定义异常处理方法,只能处理当前Controller中的异常,属于局部异常处理。

java 复制代码
@Controller
public class UserController {
    // 业务方法,可能抛出异常
    @RequestMapping("/user/get")
    @ResponseBody
    public String getUserById(Integer id) {
        if (id == null) {
            throw new NullPointerException("用户ID不能为空");
        }
        if (id <= 0) {
            throw new IllegalArgumentException("用户ID必须为正数");
        }
        return "用户ID:" + id;
    }

    // 处理当前Controller中的NullPointerException
    @ExceptionHandler(NullPointerException.class)
    @ResponseBody
    public String handleNullPointerException(NullPointerException e) {
        return "错误:" + e.getMessage();
    }

    // 处理当前Controller中的IllegalArgumentException
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public String handleIllegalArgumentException(IllegalArgumentException e) {
        return "错误:" + e.getMessage();
    }
}

4.2.2 @ControllerAdvice + @ExceptionHandler(全局异常处理)

@ControllerAdvice注解用于定义全局异常处理类,结合@ExceptionHandler注解可以捕获所有Controller中的异常,实现全局异常统一处理。

java 复制代码
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

// 全局异常处理类,捕获所有Controller的异常
@ControllerAdvice
public class GlobalExceptionHandler {
    // 处理NullPointerException
    @ExceptionHandler(NullPointerException.class)
    @ResponseBody
    public String handleNullPointerException(NullPointerException e) {
        return "全局错误:" + e.getMessage();
    }

    // 处理IllegalArgumentException
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public String handleIllegalArgumentException(IllegalArgumentException e) {
        return "全局错误:" + e.getMessage();
    }

    // 处理所有未捕获的异常(兜底处理)
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleException(Exception e) {
        return "系统异常:" + e.getMessage();
    }
}

使用全局异常处理后,所有Controller中抛出的异常都会被GlobalExceptionHandler中的对应方法捕获并处理,无需在每个Controller中单独定义异常处理方法。

4.3 文件上传

SpringMVC提供了便捷的文件上传功能,基于Apache Commons FileUpload组件实现(Spring Boot已自动整合相关依赖)。以下是文件上传的实现步骤:

4.3.1 引入文件上传依赖

Spring Boot的spring-boot-starter-web依赖已包含文件上传所需的依赖,无需额外引入。如果是传统SpringMVC项目,需要手动引入以下依赖:

xml 复制代码
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

4.3.2 配置文件上传解析器

Spring Boot会自动配置MultipartResolver(文件上传解析器),默认的最大上传文件大小为1MB。如果需要自定义配置,可以在application.properties文件中添加以下配置:

properties 复制代码
# 单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
# 单次请求最大上传大小(多文件上传时)
spring.servlet.multipart.max-request-size=50MB
# 文件上传临时目录(默认在系统临时目录)
spring.servlet.multipart.location=${java.io.tmpdir}

4.3.3 实现文件上传功能

第一步:编写文件上传页面(upload.html):

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>
    <form action="/file/upload" method="post" enctype="multipart/form-data">
        选择文件:<input type="file" name="file"><br>
        <input type="submit" value="上传">
    </form>
</body>
</html>

注意:form表单的enctype属性必须设置为"multipart/form-data",否则无法正确上传文件。

4.3.4 编写文件上传Controller方法

java 复制代码
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

@RestController
public class FileUploadController {
    // 文件上传路径(实际开发中建议配置在配置文件中)
    private static final String UPLOAD_PATH = "D:/upload/";

    @PostMapping("/file/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file) {
        // 检查文件是否为空
        if (file.isEmpty()) {
            return "文件不能为空";
        }

        // 获取文件名
        String originalFilename = file.getOriginalFilename();
        // 生成唯一文件名(避免文件名重复覆盖)
        String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
        // 创建上传目录(如果不存在)
        File uploadDir = new File(UPLOAD_PATH);
        if (!uploadDir.exists()) {
            uploadDir.mkdirs();
        }

        try {
            // 保存文件到指定路径
            file.transferTo(new File(UPLOAD_PATH + fileName));
            return "文件上传成功!文件名:" + fileName;
        } catch (IOException e) {
            e.printStackTrace();
            return "文件上传失败:" + e.getMessage();
        }
    }
}

测试:访问"http://localhost:8080/upload.html",选择文件并点击"上传"按钮,文件会被保存到"D:/upload/"目录下,并返回上传结果。

五、SpringMVC与其他技术的集成

5.1 SpringMVC与Spring的集成

SpringMVC本身就是Spring框架的一部分,因此与Spring的集成非常简单。在Spring Boot项目中,通过@SpringBootApplication注解的@ComponentScan功能,会自动扫描Controller、Service、Repository等组件,实现Spring IOC容器与SpringMVC的无缝集成。

在传统SpringMVC项目中,需要在Web.xml中配置Spring的ContextLoaderListener,加载Spring的配置文件,实现Spring IOC容器的初始化。配置示例如下:

xml 复制代码
<!-- 配置Spring的ContextLoaderListener,加载Spring配置文件 -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring.xml</param-value>
</context-param>

集成后,SpringMVC的Controller可以直接通过@Autowired注解注入Spring IOC容器中的Service、DAO等组件,实现业务逻辑的调用。

5.2 SpringMVC与MyBatis的集成

MyBatis是一款优秀的持久层框架,SpringMVC与MyBatis的集成是企业级开发的常见组合。集成步骤如下:

5.2.1 引入依赖

xml 复制代码
<!-- MyBatis核心依赖 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.9</version>
</dependency>
<!-- MyBatis与Spring集成依赖 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.7</version>
</dependency>
<!-- 数据库驱动依赖(MySQL) -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>
<!-- 数据源依赖(Druid) -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.11</version>
</dependency>

5.2.2 配置数据源和SqlSessionFactory

在Spring配置文件中配置数据源(Druid)、SqlSessionFactoryBean、MapperScannerConfigurer等组件:

xml 复制代码
<!-- 配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>

<!-- 配置SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- 配置MyBatis映射文件路径 -->
    <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    <!-- 配置MyBatis全局配置文件 -->
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>

<!-- 配置Mapper扫描器,自动扫描Mapper接口并创建代理对象 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.dao"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

5.2.3 编写Mapper接口和映射文件

创建UserMapper接口:

java 复制代码
public interface UserMapper {
    User selectUserById(Integer id);
}

创建UserMapper.xml映射文件:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.UserMapper">
    <select id="selectUserById" parameterType="java.lang.Integer" resultType="com.example.entity.User">
        select id, name, age from user where id = #{id}
    </select>
</mapper>

5.2.4 在Service中注入Mapper接口

java 复制代码
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User getUserById(Integer id) {
        return userMapper.selectUserById(id);
    }
}

5.2.5 在Controller中调用Service

java 复制代码
@Controller
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/user/get/{id}")
    @ResponseBody
    public User getUserById(@PathVariable("id") Integer id) {
        return userService.getUserById(id);
    }
}

集成完成后,通过访问"http://localhost:8080/user/get/1",即可调用MyBatis查询数据库中的用户数据并返回。

六、总结与扩展

6.1 本文知识点总结

本文围绕SpringMVC知识点展开,采用总分总的编写模式,从基础到进阶,系统讲解了SpringMVC的核心内容。首先介绍了MVC设计模式和SpringMVC的基本概念、核心优势及应用场景,帮助读者建立对SpringMVC的整体认知;其次深入剖析了SpringMVC的核心组件(DispatcherServlet、HandlerMapping、HandlerAdapter等)和执行流程,让读者理解SpringMVC的工作原理;然后通过基于Spring Boot的实战案例,讲解了SpringMVC的环境搭建、请求参数绑定、视图解析与页面跳转等基础应用;接着介绍了SpringMVC的高级特性,包括拦截器、异常处理、文件上传等,提升读者的实战能力;随后讲解了SpringMVC与Spring、MyBatis等技术的集成,满足企业级开发的需求;最后通过总结与扩展,梳理全文知识点,并提供进一步学习的阅读资料。

核心知识点梳理:

  • MVC设计模式:模型(Model)、视图(View)、控制器(Controller)的职责划分;

  • SpringMVC核心组件:DispatcherServlet(前端控制器)、HandlerMapping(处理器映射器)、HandlerAdapter(处理器适配器)等的作用;

  • SpringMVC执行流程:从接收请求到返回响应的完整步骤,各组件的协同工作机制;

  • 基础实战:环境搭建、请求参数绑定(基本类型、引用类型、集合类型)、视图解析与页面跳转;

  • 高级特性:拦截器(权限控制、日志记录)、异常处理(局部异常、全局异常)、文件上传;

  • 技术集成:与Spring的无缝集成、与MyBatis的持久层集成。

6.2 知识点扩展

除了本文讲解的核心知识点,SpringMVC还有一些进阶内容值得深入学习,以应对更复杂的开发场景:

  • RESTful风格API开发:RESTful是一种软件架构风格,通过HTTP方法(GET、POST、PUT、DELETE)对应CRUD操作,实现资源的统一管理。SpringMVC通过@RequestMapping、@GetMapping、@PostMapping、@PutMapping、@DeleteMapping等注解
相关推荐
2301_789015622 小时前
C++:二叉搜索树
c语言·开发语言·数据结构·c++·算法·排序算法
Lucky小小吴3 小时前
ClamAV扫描速度提升6.5倍:服务器杀毒配置优化实战指南
java·服务器·网络·clamav
帅那个帅3 小时前
PHP里面的抽象类和接口类
开发语言·php
handsome_sai8 小时前
【Java 线程池】记录
java
咖啡の猫9 小时前
Python字典推导式
开发语言·python
大学生资源网9 小时前
基于springboot的唐史文化管理系统的设计与实现源码(java毕业设计源码+文档)
java·spring boot·课程设计
leiming69 小时前
C++ vector容器
开发语言·c++·算法
guslegend9 小时前
SpringSecurity源码剖析
java
SystickInt9 小时前
C语言 strcpy和memcpy 异同/区别
c语言·开发语言