【Java 高阶】一文精通 Spring MVC - 基础概念(一)

👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主

⛪️ 个人社区:个人社区

💞 个人主页:个人主页

🙉 专栏地址: ✅ Java 高阶

🙉八股文专题:剑指大厂,手撕 Java 八股文

文章目录

      • [1. 什么是 Spring MVC](#1. 什么是 Spring MVC)
      • [2. Spring MVC 的优缺点](#2. Spring MVC 的优缺点)
      • [3. Spring MVC 的应用场景](#3. Spring MVC 的应用场景)
      • [4. Spring MVC 的实现原理](#4. Spring MVC 的实现原理)
      • [5. Spring MVC 的五大组件](#5. Spring MVC 的五大组件)
      • [6. 基于注解的 Hello World](#6. 基于注解的 Hello World)
      • [7. 请求参数处理](#7. 请求参数处理)
        • [7.1. @RequestParam](#7.1. @RequestParam)
        • [7.2. @RequestHeader](#7.2. @RequestHeader)
        • [7.3. @CookieValue](#7.3. @CookieValue)
      • [8. 复杂数据类型处理](#8. 复杂数据类型处理)
        • [8.1. JavaBean 数据绑定](#8.1. JavaBean 数据绑定)
        • [8.2. 嵌套对象数据绑定](#8.2. 嵌套对象数据绑定)
        • 8.3.数组、集合绑定

1. 什么是 Spring MVC

Spring MVC 是一个基于 Java 的开源框架,用于构建 Web 应用程序。它是 Spring 框架的一部分,提供了一种模型-视图-控制器(Model-View-Controller,MVC)的架构模式,用于开发灵活、可扩展和高性能的 Web 应用程序。

Spring MVC 的工作原理如下:

  1. 请求到达前端控制器(DispatcherServlet)。
  2. 前端控制器根据请求的 URL 找到对应的处理器映射器(HandlerMapper),它将请求映射到相应的处理器(Controller)。
  3. 处理器执行请求,并返回一个模型(Model)和逻辑视图名(View Name)。
  4. 前端控制器将模型和视图名传递给视图解析器(ViewResolver),它根据视图名解析出实际的视图对象(View)。
  5. 前端控制器将模型传递给视图,并由视图负责渲染响应内容。
  6. 最终,前端控制器将响应发送给客户端。

Spring MVC 提供了许多功能和特性,包括请求映射、数据绑定、表单处理、验证、拦截器、国际化支持等。它与其他 Spring 框架(如 Spring Boot)以及许多视图技术(如 JSP、Thymeleaf、Freemarker 等)集成良好,使开发人员能够轻松构建各种类型的 Web 应用程序。

Spring MVC 是一个成熟且广泛应用的框架,被许多企业和开发者用于构建 Web 应用程序,并且具有强大的社区支持和丰富的文档资源。

2. Spring MVC 的优缺点

Spring MVC 作为一个成熟的Web框架,具有以下优点:

  1. 松耦合:Spring MVC采用了MVC设计模式,将应用程序的不同层分离,使得开发更加模块化和可维护。这种松耦合的设计使得开发人员能够更好地管理和测试各个组件。
  2. 高度可定制:Spring MVC提供了许多可扩展的接口和抽象类,允许开发人员根据自己的需求进行定制。可以选择使用不同的视图技术、处理器映射器、视图解析器等,以满足特定的业务需求。
  3. 强大的集成能力:Spring MVC与其他Spring框架和第三方库的集成非常友好。它可以与Spring Boot、Spring Security、Hibernate、JPA等无缝集成,提供全面的解决方案。
  4. 易于测试:Spring MVC的松耦合设计使得单元测试和集成测试更加容易。可以针对控制器、服务类和数据访问层编写独立的单元测试,并模拟HTTP请求和响应进行集成测试。
  5. 大量的文档和社区支持:Spring MVC拥有庞大的用户社区和活跃的开发者社区,提供了丰富的文档和教程资源。可以轻松找到解决方案、参与讨论并获取帮助。

然而,Spring MVC 也存在一些缺点

  1. 学习曲线较陡:尽管Spring MVC提供了很多功能和灵活性,但对于初学者来说,学习和理解其概念和配置可能需要一些时间和精力。
  2. 配置复杂:Spring MVC的配置通常需要编写大量的XML或注解,特别是在较复杂的应用程序中。这可能会导致配置文件变得复杂和冗长。
  3. 代码冗余:在一些简单的场景中,为了实现某些功能,Spring MVC可能需要编写大量的重复代码,这可能增加开发的复杂性和维护成本。

3. Spring MVC 的应用场景

Spring MVC 的应用场景广泛,适用于各种类型的 Web 应用程序开发。以下是一些常见的应用场景:

  1. 企业级 Web 应用程序:Spring MVC 提供了一种模块化和可扩展的架构,使开发人员能够构建复杂的企业级 Web 应用程序。它可以与其他 Spring 框架(如 Spring Boot、Spring Security)和持久化框架(如 Hibernate、JPA)无缝集成,提供全面的解决方案。
  2. RESTful API:Spring MVC 提供了良好的支持,可以轻松构建和管理 RESTful API。它可以通过注解方式定义 RESTful 资源,支持请求和响应的数据绑定、验证和转换。同时,Spring MVC 还提供了丰富的拦截器和过滤器,用于处理身份验证、授权和日志记录等功能。
  3. 单页应用程序(SPA):Spring MVC 可以与前端框架(如 Angular、React、Vue.js)结合使用,构建响应式的单页应用程序。它可以作为后端服务,提供数据接口和业务逻辑处理,同时与前端框架进行无缝集成。
  4. 微服务架构:Spring MVC 可以作为微服务架构中的一部分,用于构建和管理微服务。它可以通过 Spring Cloud 提供的组件(如服务注册与发现、负载均衡、断路器)实现微服务的治理和协调。
  5. 敏捷开发:Spring MVC 提供了快速开发和迭代的能力,通过使用注解和约定优于配置的方式,减少了开发人员的工作量。同时,它还提供了丰富的测试支持,使得开发人员能够快速编写单元测试和集成测试。

4. Spring MVC 的实现原理

Spring MVC 的实现原理主要涉及以下几个核心组件和流程:

  1. 前端控制器(DispatcherServlet):前端控制器是整个 Spring MVC 的核心组件,它作为应用程序的入口点,接收所有的请求并进行处理。它负责将请求分发给相应的处理器(Controller)进行处理。
  2. 处理器映射器(HandlerMapper):处理器映射器负责将请求映射到相应的处理器。它根据请求的 URL 和其他条件,确定使用哪个处理器来处理请求。
  3. 处理器适配器(HandlerAdapter):处理器适配器负责将请求分发给相应的处理器进行处理。它根据处理器的类型,调用相应的方法来处理请求,并将处理结果返回给前端控制器。
  4. 视图解析器(ViewResolver):视图解析器负责将逻辑视图名解析为实际的视图对象。它根据配置的视图解析规则,将逻辑视图名解析为具体的视图对象,以便渲染响应内容。
  5. 视图(View):视图负责渲染响应内容,并将其返回给客户端。它可以是 JSP、Thymeleaf、Freemarker 等模板引擎,也可以是 JSON、XML 等其他格式的视图。
  6. 拦截器(Interceptor):拦截器可以在请求处理的不同阶段进行拦截,添加额外的逻辑。它可以在请求前、请求后或视图渲染前后执行一些操作,如身份验证、日志记录等。
  7. 数据绑定和验证:Spring MVC 提供了数据绑定和验证的支持,可以将请求参数绑定到方法参数上,并进行数据验证和转换。
  8. 异常处理:Spring MVC 提供了异常处理机制,可以捕获和处理请求处理过程中产生的异常,并根据配置的异常处理器进行相应的处理。
  9. 核心流程:当请求到达前端控制器时,它会通过处理器映射器找到对应的处理器,并通过处理器适配器调用处理器的方法进行处理。处理器处理完请求后,将模型和逻辑视图名返回给前端控制器。前端控制器将逻辑视图名传递给视图解析器,解析为实际的视图对象,并将模型传递给视图进行渲染。最终,视图将渲染后的响应内容返回给客户端。

5. Spring MVC 的五大组件

Spring MVC 的五大组件包括:

  1. 前端控制器(DispatcherServlet):前端控制器是整个 Spring MVC 的核心组件,它作为应用程序的入口点,接收所有的请求并进行处理。它负责将请求分发给相应的处理器进行处理。
    2. 处理器映射器(HandlerMapper):处理器映射器负责将请求映射到相应的处理器。它根据请求的 URL 和其他条件,确定使用哪个处理器来处理请求。
  2. 处理器适配器(HandlerAdapter):处理器适配器负责将请求分发给相应的处理器进行处理。它根据处理器的类型,调用相应的方法来处理请求,并将处理结果返回给前端控制器。
  3. 视图解析器(ViewResolver):视图解析器负责将逻辑视图名解析为实际的视图对象。它根据配置的视图解析规则,将逻辑视图名解析为具体的视图对象,以便渲染响应内容。
  4. 视图(View):视图负责渲染响应内容,并将其返回给客户端。它可以是 JSP、Thymeleaf、Freemarker 等模板引擎,也可以是 JSON、XML 等其他格式的视图。

6. 基于注解的 Hello World

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

@RestController
public class HelloWorldController {
    
    @GetMapping("/hello")
    public String helloWorld() {
        return "Hello, World!";
    }
}

7. 请求参数处理

在 Spring MVC 中,可以使用多种方式处理请求参数。以下是几种常见的处理方式:

  1. 使用@RequestParam注解:可以通过@RequestParam注解将请求参数绑定到方法的参数上。例如:
java 复制代码
@GetMapping("/hello")
public String hello(@RequestParam("name") String name) {
    // 处理name参数
    return "hello";
}

在上述示例中,请求参数中的"name"将会绑定到方法参数name上。

  1. 使用@PathVariable注解:可以通过@PathVariable注解将路径变量绑定到方法的参数上。例如:
java 复制代码
@GetMapping("/hello/{name}")
public String hello(@PathVariable("name") String name) {
    // 处理路径中的name变量
    return "hello";
}

在上述示例中,路径中的"name"部分将会绑定到方法参数name上。

  1. 使用@RequestBody注解:可以通过@RequestBody注解将请求体中的数据绑定到方法的参数上。例如:
java 复制代码
@PostMapping("/hello")
public String hello(@RequestBody User user) {
    // 处理请求体中的User对象
    return "hello";
}

在上述示例中,请求体中的JSON数据将会被转换成User对象,并绑定到方法参数user上。

4. 使用@RequestParamMap或@PathVariableMap注解:可以使用@RequestParamMap或@PathVariableMap注解将所有的请求参数或路径变量绑定到一个Map对象上。例如:

java 复制代码
@GetMapping("/hello")
public String hello(@RequestParamMap Map<String, String> params) {
    // 处理所有的请求参数
    return "hello";
}

@GetMapping("/hello/{name}")
public String hello(@PathVariableMap Map<String, String> pathVars) {
    // 处理所有的路径变量
    return "hello";
}

在上述示例中,所有的请求参数或路径变量将会被绑定到一个Map对象上,可以通过Map对象进行进一步的处理。

7.1. @RequestParam

@RequestParam 是 Spring MVC 中用于绑定请求参数的注解。它可以用于将请求中的参数值绑定到方法的参数上。

@RequestParam 注解有以下常用属性:

  • value 或 name:用于指定请求参数的名称。例如,@RequestParam("name") 表示将请求参数中的 "name" 绑定到方法参数上。
  • required:指定该参数是否为必需的,默认为 true。如果设置为 true,但请求中没有该参数,将会抛出异常;如果设置为 false,但请求中没有该参数,方法参数将被设置为 null。
  • defaultValue:指定参数的默认值。如果请求中没有该参数,将使用 defaultValue 指定的值作为参数的默认值。

下面是一个使用 @RequestParam 的示例:

java 复制代码
@GetMapping("/hello")
public String hello(@RequestParam("name") String name) {
    // 处理 name 参数
    return "hello";
}

在上述示例中,请求中的 "name" 参数将会绑定到方法参数 name 上。

@RequestParam 注解可以用于处理 GET、POST 等请求的参数。它支持基本类型(如 String、int、boolean 等)、对象类型和数组类型的参数绑定。

需要注意的是,如果请求参数名称与方法参数名称一致,可以省略 @RequestParam 注解。例如:

java 复制代码
@GetMapping("/hello")
public String hello(String name) {
    // 处理 name 参数
    return "hello";
}

在上述示例中,请求中的 "name" 参数将会直接绑定到方法参数 name 上。

7.2. @RequestHeader

@RequestHeader 是 Spring MVC 中用于获取请求头信息的注解。它可以用于将特定的请求头值绑定到方法的参数上。

@RequestHeader 注解有以下常用属性:

  • value 或 name:用于指定请求头的名称。例如,@RequestHeader("User-Agent") 表示将请求头中的 "User-Agent" 值绑定到方法参数上。
  • required:指定该请求头是否为必需的,默认为 true。如果设置为 true,但请求中没有该请求头,将会抛出异常;如果设置为 false,但请求中没有该请求头,方法参数将被设置为 null。
  • defaultValue:指定请求头的默认值。如果请求中没有该请求头,将使用 defaultValue 指定的值作为参数的默认值。
    下面是一个使用 @RequestHeader 的示例:
java 复制代码
@GetMapping("/hello")
public String hello(@RequestHeader("User-Agent") String userAgent) {
    // 处理 User-Agent 请求头
    return "hello";
}

在上述示例中,请求头中的 "User-Agent" 值将会绑定到方法参数 userAgent 上。

@RequestHeader 注解可以用于获取任意请求头的值,常用的请求头包括 User-Agent、Content-Type、Authorization 等。它可以与其他注解组合使用,如 @GetMapping、@PostMapping 等,来处理特定的请求。

需要注意的是,如果请求头名称与方法参数名称一致,可以省略 @RequestHeader 注解。例如:

java 复制代码
@GetMapping("/hello")
public String hello(String userAgent) {
    // 处理 User-Agent 请求头
    return "hello";
}

在上述示例中,请求头中的 "User-Agent" 值将会直接绑定到方法参数 userAgent 上。

7.3. @CookieValue

@CookieValue 是 Spring MVC 中用于获取请求中的 Cookie 值的注解。它可以用于将特定的 Cookie 值绑定到方法的参数上。

@CookieValue 注解有以下常用属性:

  • value 或 name:用于指定 Cookie 的名称。例如,@CookieValue("sessionId") 表示将名为 "sessionId" 的 Cookie 值绑定到方法参数上。
  • required:指定该 Cookie 是否为必需的,默认为 true。如果设置为 true,但请求中没有该 Cookie,将会抛出异常;如果设置为 false,但请求中没有该 Cookie,方法参数将被设置为 null。
  • defaultValue:指定 Cookie 的默认值。如果请求中没有该 Cookie,将使用 defaultValue 指定的值作为参数的默认值。
    下面是一个使用 @CookieValue 的示例:
java 复制代码
@GetMapping("/hello")
public String hello(@CookieValue("sessionId") String sessionId) {
    // 处理 sessionId Cookie 值
    return "hello";
}

在上述示例中,名为 "sessionId" 的 Cookie 值将会绑定到方法参数 sessionId 上。

@CookieValue 注解可以用于获取任意 Cookie 的值。它可以与其他注解组合使用,如 @GetMapping、@PostMapping 等,来处理特定的请求。

需要注意的是,如果 Cookie 名称与方法参数名称一致,可以省略 @CookieValue 注解。例如:

java 复制代码
@GetMapping("/hello")
public String hello(String sessionId) {
    // 处理 sessionId Cookie 值
    return "hello";
}

在上述示例中,名为 "sessionId" 的 Cookie 值将会直接绑定到方法参数 sessionId 上。

8. 复杂数据类型处理

在 Spring MVC 中,处理复杂数据类型(如对象、集合、数组等)的方式有多种。以下是几种常见的复杂数据类型处理方式:

  1. 使用表单参数绑定:可以通过将复杂数据类型的属性作为表单参数进行绑定。在表单中,使用属性名作为参数名,可以通过表单提交将数据绑定到方法的参数上。例如:
java 复制代码
@PostMapping("/save")
public String saveUser(User user) {
    // 处理User对象
    return "success";
}

在上述示例中,User 对象的属性可以通过表单参数进行绑定,前提是表单中的参数名与 User 对象的属性名相匹配。

  1. 使用 @ModelAttribute 注解:可以使用 @ModelAttribute 注解将复杂数据类型绑定到方法的参数上。@ModelAttribute 注解可以用于方法参数或方法上,用于指定要绑定的数据来源。例如:
java 复制代码
@PostMapping("/save")
public String saveUser(@ModelAttribute("user") User user) {
    // 处理User对象
    return "success";
}

在上述示例中,@ModelAttribute 注解指定了要绑定的数据来源为 "user",并将其绑定到方法参数 User 上。

  1. 使用 @RequestBody 注解:可以使用 @RequestBody 注解将请求体中的数据绑定到复杂数据类型的参数上。例如:
java 复制代码
@PostMapping("/save")
public String saveUser(@RequestBody User user) {
    // 处理User对象
    return "success";
}

在上述示例中,请求体中的 JSON 数据将会被转换成 User 对象,并绑定到方法参数 user 上。

  1. 使用 @RequestParamMap 或 @PathVariableMap 注解:可以使用 @RequestParamMap 或 @PathVariableMap 注解将所有的请求参数或路径变量绑定到一个 Map 对象上。例如:
java 复制代码
@PostMapping("/save")
public String saveUser(@RequestParamMap Map<String, String> params) {
    // 处理所有的请求参数
    return "success";
}

在上述示例中,所有的请求参数将会被绑定到一个 Map 对象上,可以通过 Map 对象进行进一步的处理。

8.1. JavaBean 数据绑定

在 Spring MVC 中,JavaBean 数据绑定是指将请求参数绑定到 JavaBean 对象的属性上。通过 JavaBean 数据绑定,可以将请求中的数据自动转换为 JavaBean 对象,并进行验证和处理。

JavaBean 数据绑定的实现依赖于数据绑定器(DataBinder)。Spring MVC 提供了一个称为 WebDataBinder 的数据绑定器,用于处理 JavaBean 数据绑定。

要使用 JavaBean 数据绑定,需要按照以下步骤进行配置和使用:

  1. 创建一个 JavaBean 类,该类包含要绑定的属性和相应的 getter 和 setter 方法。
java 复制代码
public class User {
    private String name;
    private int age;
     // getter 和 setter 方法
}
  1. 在控制器方法中,使用 @ModelAttribute 注解将 JavaBean 对象绑定到方法参数上。
java 复制代码
@PostMapping("/save")
public String saveUser(@ModelAttribute("user") User user) {
    // 处理 User 对象
    return "success";
}

在上述示例中,@ModelAttribute("user") 将会将请求参数绑定到名为 "user" 的 JavaBean 对象上。

  1. 在表单中,使用属性名作为参数名,以便将数据绑定到 JavaBean 对象的属性上。
html 复制代码
<form action="/save" method="post">
    <input type="text" name="name" />
    <input type="text" name="age" />
    <button type="submit">保存</button>
</form>

在上述示例中,表单中的 name 和 age 参数将会自动绑定到 User 对象的相应属性上。

8.2. 嵌套对象数据绑定

在 Spring MVC 中,可以使用嵌套对象数据绑定来处理复杂的数据结构,其中包含了嵌套的对象或集合。通过嵌套对象数据绑定,可以将请求中的数据自动转换为嵌套对象,并进行验证和处理。

要使用嵌套对象数据绑定,需要按照以下步骤进行配置和使用:

  1. 创建嵌套对象的 JavaBean 类,该类包含要绑定的属性和相应的 getter 和 setter 方法。
java 复制代码
public class Address {
    private String city;
    private String street;
    // getter 和 setter 方法
}

public class User {
    private String name;
    private int age;
    private Address address;
    // getter 和 setter 方法
}
  1. 在控制器方法中,使用 @ModelAttribute 注解将嵌套对象绑定到方法参数上。
java 复制代码
@PostMapping("/save")
public String saveUser(@ModelAttribute("user") User user) {
    // 处理 User 对象及其嵌套对象
    return "success";
}

在上述示例中,@ModelAttribute("user") 将会将请求参数绑定到名为 "user" 的 User 对象上,包括嵌套的 Address 对象。

  1. 在表单中,使用属性名作为参数名,并使用点号(.)表示嵌套对象的属性,以便将数据绑定到嵌套对象的属性上。
html 复制代码
<form action="/save" method="post">
    <input type="text" name="name" />
    <input type="text" name="age" />
    <input type="text" name="address.city" />
    <input type="text" name="address.street" />
    <button type="submit">保存</button>
</form>

在上述示例中,表单中的 name、age、address.city 和 address.street 参数将会自动绑定到 User 对象及其嵌套的 Address 对象的相应属性上。

8.3.数组、集合绑定

在 Spring MVC 中,可以使用数组和集合绑定来处理请求参数中的数组和集合数据。通过数组和集合绑定,可以将请求中的数据自动转换为数组或集合,并进行验证和处理。

要使用数组和集合绑定,需要按照以下步骤进行配置和使用:

  1. 在控制器方法中,将数组或集合作为方法参数进行声明。
java 复制代码
@PostMapping("/save")
public String saveData(@RequestParam("names") String[] names, 
                       @RequestParam("ids") List<Integer> ids) {
    // 处理数组和集合数据
    return "success";
}

在上述示例中, names 参数将会绑定为一个字符串数组, ids 参数将会绑定为一个整数列表。

  1. 在表单中,使用相同的参数名多次提交数据,或者使用索引号作为参数名来提交数组或集合数据。
html 复制代码
<form action="/save" method="post">
    <input type="text" name="names" value="Alice" />
    <input type="text" name="names" value="Bob" />
    <input type="text" name="ids[0]" value="1" />
    <input type="text" name="ids[1]" value="2" />
    <button type="submit">保存</button>
</form>

在上述示例中, names 参数使用相同的参数名多次提交数据, ids 参数使用索引号作为参数名来提交数据。

精彩专栏推荐订阅:在下方专栏👇🏻
2023年华为OD机试真题(A卷&B卷)+ 面试指导
精选100套 Java 项目案例
面试需要避开的坑(活动)
你找不到的核心代码
带你手撕 Spring
Java 初阶

相关推荐
熊大如如5 小时前
Java 反射
java·开发语言
猿来入此小猿6 小时前
基于SSM实现的健身房系统功能实现十六
java·毕业设计·ssm·毕业源码·免费学习·猿来入此·健身平台
goTsHgo6 小时前
Spring Boot 自动装配原理详解
java·spring boot
卑微的Coder6 小时前
JMeter同步定时器 模拟多用户并发访问场景
java·jmeter·压力测试
pjx9877 小时前
微服务的“导航系统”:使用Spring Cloud Eureka实现服务注册与发现
java·spring cloud·微服务·eureka
多多*7 小时前
算法竞赛相关 Java 二分模版
java·开发语言·数据结构·数据库·sql·算法·oracle
爱喝酸奶的桃酥7 小时前
MYSQL数据库集群高可用和数据监控平台
java·数据库·mysql
唐僧洗头爱飘柔95278 小时前
【SSM-SSM整合】将Spring、SpringMVC、Mybatis三者进行整合;本文阐述了几个核心原理知识点,附带对应的源码以及描述解析
java·spring·mybatis·springmvc·动态代理·ioc容器·视图控制器
骑牛小道士8 小时前
Java基础 集合框架 Collection接口和抽象类AbstractCollection
java
alden_ygq9 小时前
当java进程内存使用超过jvm设置大小会发生什么?
java·开发语言·jvm