十七:Spring Boot依赖 (2)-- spring-boot-starter-web 依赖详解

目录

[1. spring-boot-starter-web 简介](#1. spring-boot-starter-web 简介)

[1.1 作用与功能:](#1.1 作用与功能:)

[1.2 引入方式:](#1.2 引入方式:)

[1.3 包含的核心依赖:](#1.3 包含的核心依赖:)

[2. 自动配置原理](#2. 自动配置原理)

[3. 内嵌 Servlet 容器](#3. 内嵌 Servlet 容器)

[3.1 默认 Tomcat 配置:](#3.1 默认 Tomcat 配置:)

[3.2 替换容器(Jetty 或 Undertow):](#3.2 替换容器(Jetty 或 Undertow):)

[4. 构建 RESTful Web 服务:](#4. 构建 RESTful Web 服务:)

[4.1?什么是 RESTful Web 服务](#4.1?什么是 RESTful Web 服务)

[4.2 创建 REST 控制器](#4.2 创建 REST 控制器)

[5. 自动处理 JSON:](#5. 自动处理 JSON:)

[6. 静态资源支持](#6. 静态资源支持)

[7. Web 配置定制(通过 WebMvcConfigurer)](#7. Web 配置定制(通过 WebMvcConfigurer))

[7.1 注册拦截器(Interceptor)](#7.1 注册拦截器(Interceptor))

[7.2 配置静态资源处理](#7.2 配置静态资源处理)

[7.2.1 addResourceHandlers(ResourceHandlerRegistry registry) 方法](#7.2.1 addResourceHandlers(ResourceHandlerRegistry registry) 方法)

[7.2.2 registry.addResourceHandler("/assets/**")](#7.2.2 registry.addResourceHandler(“/assets/**”))

[7.2.3 addResourceLocations("classpath:/static/assets/")](#7.2.3 addResourceLocations(“classpath:/static/assets/”))

[7.3 配置视图解析器(ViewResolver)](#7.3 配置视图解析器(ViewResolver))

[7.3.1 pom.xml 加两个引用 支持jsp 的](#7.3.1 pom.xml 加两个引用 支持jsp 的)

[7.3.2 配置视图解析器](#7.3.2 配置视图解析器)

[7.3.3 创建jsp页面](#7.3.3 创建jsp页面)

[7.3.4 写controller 一定用@Controller](#7.3.4 写controller 一定用@Controller)

[7.3.4 浏览器访问 乱码 无所谓 只要能请求到 就没大问题](#7.3.4 浏览器访问 乱码 无所谓 只要能请求到 就没大问题)

[7.3.5 工作原理](#7.3.5 工作原理)

[7.4 CORS 配置(跨域资源共享)](#7.4 CORS 配置(跨域资源共享))

[7.4.1 什么是跨域?](#7.4.1 什么是跨域?)

[7.4.2 为什么会有跨域问题?](#7.4.2 为什么会有跨域问题?)

[7.4.3 同源策略(Same-Origin Policy)](#7.4.3 同源策略(Same-Origin Policy))

[7.4.4 跨域的场景???](#7.4.4 跨域的场景???)

[7.4.5 浏览器的跨域限制](#7.4.5 浏览器的跨域限制)

[7.4.6 跨域的解决方案](#7.4.6 跨域的解决方案)

[???7.4.6.1 CORS(跨域资源共享)](#???7.4.6.1 CORS(跨域资源共享))

[7.4.6.2 JSONP(仅限 GET 请求)](#7.4.6.2 JSONP(仅限 GET 请求))

[7.4.6.3 服务器端代理(推荐)](#7.4.6.3 服务器端代理(推荐))

[7.5 消息转换器(Message Converters)](#7.5 消息转换器(Message Converters))

[7.8 定制异常处理(@ExceptionHandler)(不推荐)](#7.8 定制异常处理(@ExceptionHandler)(不推荐))

[8. 支持文件上传与下载](#8. 支持文件上传与下载)

???8.1?文件上传

[8.1.1 配置文件上传的基本设置](#8.1.1 配置文件上传的基本设置)

[8.1.2 实现文件上传接口](#8.1.2 实现文件上传接口)

[8.1.3 上传目录配置](#8.1.3 上传目录配置)

[8.1.4 上传多个文件](#8.1.4 上传多个文件)

[8.2 文件下载](#8.2 文件下载)

[8.2.1 实现文件下载接口](#8.2.1 实现文件下载接口)

[8.2.2 设置响应头部以下载文件](#8.2.2 设置响应头部以下载文件)


1. spring-boot-starter-web 简介

复制代码
#### **1.1 作用与功能**:

* `spring-boot-starter-web` 是 Spring Boot 的一个启动器(starter),用于构建 Web 应用,它自动配置了多种常见的 Web 组件,尤其适合构建 RESTful Web 服务。
复制代码
#### **1.2 引入方式**:

* Maven:在 `pom.xml` 中添加:

  *

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-web</artifactId>
          </dependency>

* **Gradle** :在 `build.gradle` 中添加:

  *

          implementation 'org.springframework.boot:spring-boot-starter-web'
复制代码
#### **1.3 包含的核心依赖**:

* **Spring MVC**:构建 Web 应用的基础框架,提供了控制器、视图解析等功能。

* **内嵌 Servlet 容器(Tomcat)**:提供一个内嵌的默认 Servlet 容器,简化部署。

* **Jackson**:用于 JSON 数据的序列化和反序列化。

* **Spring Boot 自动配置** :自动配置 `DispatcherServlet`,自动配置 Spring MVC 相关的功能。

2. 自动配置原理

  • DispatcherServlet 自动配置

    • Spring Boot 会自动配置 DispatcherServlet,它是 Spring MVC 的核心,用于路由请求到适当的控制器方法。
  • Spring MVC 相关的自动配置
    spring-boot-starter-web 自动配置了 Spring MVC 所需的 MessageConverter、视图解析器等,简化了手动配置。

  • Tomcat 自动配置

    默认情况下,spring-boot-starter-web 使用 Tomcat 作为嵌入式容器,你可以通过配置改变容器(如使用 Jetty 或 Undertow)。

3. 内嵌 Servlet 容器

复制代码
#### **3.1 默认 Tomcat 配置**:

* 默认内嵌容器是 **Tomcat** ,并且默认端口是 `8080`。

* 可以通过 `application.properties` 或 `application.yml` 修改端口:

  *

          server.port=8081
复制代码
#### **3.2 替换容器(Jetty 或 Undertow)**:

* 如果你不想使用 Tomcat,可以排除它并使用 Jetty 或 Undertow:

* 排除 Tomcat:

  *

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-web</artifactId>
              <scope>provided</scope>
          </dependency>

* 添加 Jetty 或 Undertow:

  *

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-jetty</artifactId>
          </dependency>

4. 构建 RESTful Web 服务:

复制代码
#### **4.1**什么是 RESTful Web 服务

* REST(Representational State Transfer)是一种通过 HTTP 协议与 Web 服务交互的架构风格。RESTful Web 服务遵循一系列约定,通常使用 HTTP 方法(如 GET、POST、PUT、DELETE)来进行资源的创建、查询、更新和删除操作。每个资源通常由一个 URL 唯一标识,且资源的数据通常以 JSON 返回。
复制代码
#### 4.2 创建 REST 控制器

* 在 Spring Boot 中,构建 RESTful 服务的核心是 `@RestController` 注解。`@RestController` 是一个结合了 `@Controller` 和 `@ResponseBody` 注解的注解,表示该类是一个控制器,且返回的内容会自动以 JSON 或 XML 格式返回(根据客户端请求的 `Accept` 头)。

*

        package com.example.demo.controller;
        
        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.RestController;
        
        @RestController
        @RequestMapping("/api")
        public class HelloController {
        
            @GetMapping("/hello")
            public String hello() {
                return "Hello, World!";
            }
        }

* **`@RestController`**:表示该类是一个 REST 控制器,返回数据会被自动序列化为 JSON 格式。

* **`@RequestMapping("/api")`** :为所有请求添加一个基础路径 `/api`。

* **`@GetMapping("/hello")`** :处理 GET 请求,当客户端访问 `/api/hello` 时,返回 `"Hello, World!"`。

* **`@PostMapping`**:处理 HTTP POST 请求,用于创建新用户。

* **`@PutMapping`**:处理 HTTP PUT 请求,用于更新用户信息。

* **`@DeleteMapping`**:处理 HTTP DELETE 请求,用于删除用户。

5. 自动处理 JSON:

  • spring-boot-starter-web 默认集成了 Jackson 序列化和反序列化,自动将 Java 对象与 JSON 数据进行转换。

  • 你可以使用 @RequestBody 注解接收请求体中的 JSON 数据,使用 @ResponseBody 返回 JSON 数据。

6. 静态资源支持

  • 默认情况下,Spring Boot 会从 /static/public/resources/META-INF/resources 目录提供静态资源。

  • 可以将静态文件(如 HTML、CSS、JavaScript、图片等)放入这些目录中,Spring Boot 会自动提供访问。

  • 自定义静态资源路径

    • 可以通过配置文件修改静态资源的根目录

    复制代码
        spring.resources.static-locations=classpath:/custom-static/

7. Web 配置定制(通过 WebMvcConfigurer

  • 在开发 Spring Web 应用时,WebMvcConfigurer 是一个非常常用的接口,它提供了一种灵活的方式来定制 Spring MVC 的行为。

复制代码
#### 7.1 注册拦截器(Interceptor)

*

        package com.lirui.springbootmoduledemo.config;
        
        
        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 WebConfig  implements WebMvcConfigurer {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                // 注册一个拦截器
                registry.addInterceptor(new WebInterceptor())
                        // 设置拦截路径
                        .addPathPatterns("/api/**")
                        // 排除不需要拦截的路径
                        .excludePathPatterns("/api/login", "/api/register");
            }
        }
        

        package com.lirui.springbootmoduledemo.config;
        
        import org.springframework.web.servlet.HandlerInterceptor;
        import org.springframework.web.servlet.ModelAndView;
        
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        
        public class WebInterceptor  implements HandlerInterceptor {
        
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                // 这里可以做一些拦截前的校验或操作
                System.out.println("preHandle: 请求即将到达Controller");
        
                // 返回true表示继续处理请求,false表示请求被拦截,不会继续执行
                return true; // 如果返回false,请求会被拦截,后续不会执行
            }
        
            @Override
            public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
                // 请求处理之后,视图渲染之前调用
                System.out.println("postHandle: 请求已处理,视图渲染之前");
            }
        
            @Override
            public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
                // 请求处理完后,视图渲染完毕后调用(通常用于清理资源)
                System.out.println("afterCompletion: 请求完成后,视图渲染之后");
            }
        }

  ![](https://i-blog.csdnimg.cn/direct/a3deca2d5d374e81b3b80dc9ede7f06a.png)
复制代码
#### 7.2 配置静态资源处理

*

        package com.lirui.springbootmoduledemo.config;
        
        
        import org.springframework.context.annotation.Configuration;
        import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
        import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
        import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
        
        @Configuration
        public class WebConfig  implements WebMvcConfigurer {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                // 注册一个拦截器
                registry.addInterceptor(new WebInterceptor())
                        // 设置拦截路径
                        .addPathPatterns("/api/**")
                        // 排除不需要拦截的路径
                        .excludePathPatterns("/api/login", "/api/register");
            }
        
            @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry) {
                // 配置 /assets/** 请求,映射到 classpath:/static/assets/ 文件夹
                registry.addResourceHandler("/assets/**")
                        .addResourceLocations("classpath:/static/assets/");
        
                // 配置 /images/** 请求,映射到 classpath:/static/images/ 文件夹
                registry.addResourceHandler("/images/**")
                        .addResourceLocations("classpath:/static/images/");
            }
        
        }

  ![](https://i-blog.csdnimg.cn/direct/d087c7590ce2442e9129b00f003dda4b.png)
* ![](https://i-blog.csdnimg.cn/direct/dceba04be2d84500a4f2dce1f77e0e21.png)

*

  ##### `7.2.1 addResourceHandlers(ResourceHandlerRegistry registry)` 方法

  * `addResourceHandlers` 是 Spring MVC 提供的一个方法,用于配置静态资源的处理方式。`ResourceHandlerRegistry` 用来注册静态资源的访问路径和实际的资源位置。

  * `addResourceHandlers` 方法允许你定义一组 **资源处理器**(Resource Handlers),这些处理器负责处理静态资源请求并返回相应的资源。通过配置,Spring MVC 能够自动映射 URL 路径到实际的文件存放位置,从而提供静态文件的访问功能。

*

  ##### 7.2.2 registry.addResourceHandler("/assets/\*\*")

  * `registry.addResourceHandler("/assets/**")`

  * `addResourceHandler("/assets/**")` 指定了一个 **资源请求的映射路径** ,即用户访问 `/assets/` 路径下的任何 URL(匹配 `/assets/**`)时,都会交给 Spring MVC 来处理。

    * `**` 是一种通配符,表示匹配 `/assets/` 后面所有的路径(包括子目录)。

    * 例如,访问 `http://localhost:8080/assets/img/logo.png` 或者 `http://localhost:8080/assets/css/style.css` 都会被映射到对应的静态资源文件。

*

  ##### 7.2.3 addResourceLocations("classpath:/static/assets/")

  * `addResourceLocations("classpath:/static/assets/")` 指定了 **静态资源文件的实际存储路径** 。`classpath:/static/assets/` 是资源文件所在的路径。

  * `classpath:` 表示资源位置在类路径中。Spring Boot 默认会将静态资源放在 `src/main/resources/static` 目录下。所以如果你的静态文件在 `src/main/resources/static/assets/` 目录下,路径应该设置为 `classpath:/static/assets/`。

  * 这样,当用户请求 `/assets/**` 路径时,Spring 会在 `classpath:/static/assets/` 目录中查找对应的文件。
复制代码
#### 7.3 配置视图解析器(ViewResolver)

* 感觉很少会用到来

*

  ##### 7.3.1 pom.xml 加两个引用 支持jsp 的

  *

                  <dependency>
                      <groupId>org.apache.tomcat.embed</groupId>
                      <artifactId>tomcat-embed-jasper</artifactId>
                  </dependency>
                  <dependency>
                      <groupId>javax.servlet</groupId>
                      <artifactId>javax.servlet-api</artifactId>
                      <scope>provided</scope>
                  </dependency>

*

  ##### 7.3.2 配置视图解析器

  *

          package com.lirui.springbootmoduledemo.config;
          
          
          import org.springframework.context.annotation.Configuration;
          import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
          import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
          import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
          import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
          
          @Configuration
          public class WebConfig implements WebMvcConfigurer {
              @Override
              public void addInterceptors(InterceptorRegistry registry) {
                  // 注册一个拦截器
                  registry.addInterceptor(new WebInterceptor())
                          // 设置拦截路径
                          .addPathPatterns("/api/**")
                          // 排除不需要拦截的路径
                          .excludePathPatterns("/api/login", "/api/register");
              }
          
              @Override
              public void addResourceHandlers(ResourceHandlerRegistry registry) {
                  // 配置 /assets/** 请求,映射到 classpath:/static/assets/ 文件夹
                  registry.addResourceHandler("/assets/**")
                          .addResourceLocations("classpath:/static/assets/");
          
                  // 配置 /images/** 请求,映射到 classpath:/static/images/ 文件夹
                  registry.addResourceHandler("/images/**")
                          .addResourceLocations("classpath:/static/images/");
              }
          
              @Override
              public void configureViewResolvers(ViewResolverRegistry registry) {
                  // 配置 JSP 视图解析器
                  registry.jsp().prefix("/WEB-INF/views1/").suffix(".jsp");
              }
          
          }

*

  ##### 7.3.3 创建jsp页面

  * ![](https://i-blog.csdnimg.cn/direct/69c22319fddb4691a4e8670a221d2e04.png)
    *

            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>hello</title>
            </head>
            <body>
            <h1>欢迎</h1>
            <h1>欢迎</h1>
            <h1>欢迎</h1>
            <h1>欢迎</h1>
            </body>
            </html>

*

  ##### 7.3.4 写controller 一定用@Controller

  *

          package com.lirui.springbootmoduledemo.controller;
          
          import org.springframework.stereotype.Controller;
          import org.springframework.web.bind.annotation.GetMapping;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RestController;
          
          @Controller
          @RequestMapping("/api")
          public class HelloController {
          
              @GetMapping("/hello")
              public String hello() {
                  return "Hello, World!";
              }
          
              @GetMapping("/helloJSP")
              public String home() {
                  // 返回 index.jsp 视图
                  return "hello";
              }
          
          }

*

  ##### 7.3.4 浏览器访问 乱码 无所谓 只要能请求到 就没大问题

  * ![](https://i-blog.csdnimg.cn/direct/5778f1d06f4447ef93bae47a870c8b23.png)
*

  ##### 7.3.5 工作原理

  * 当 Spring MVC 中的控制器(Controller)返回一个视图名称时(比如 `"`hello`"`),视图解析器会根据配置的 `prefix` 和 `suffix` 来构造最终的 JSP 文件路径。

    * 控制器返回视图名称:hello
    * 视图解析器会去 `WEB-INF/views/` 目录下查找名为hello.jsp的文件。
    * 如果文件存在,Spring 会将该 JSP 文件渲染到响应中,返回给客户端。
复制代码
#### 7.4 CORS 配置(跨域资源共享)

*

  ##### 7.4.1 什么是跨域?

  * \*\*跨域(Cross-Origin)\*\*是指浏览器在不同的域、协议、端口之间进行资源请求的行为。简单来说,当一个网页试图从不同的域名、端口号或协议(如 `http://example.com` 和 `https://example.com`)加载资源时,就涉及到"跨域"问题。
*

  ##### 7.4.2 为什么会有跨域问题?

  * 浏览器出于安全考虑,采用了 **同源策略(Same-Origin Policy)**,即一个网页只能访问同一来源(同协议、同域名、同端口)的资源。这是为了防止恶意网站通过脚本获取用户的敏感数据或做其他恶意操作。
*

  ##### **7.4.3 同源策略(Same-Origin Policy)**

  * **协议** :`http`、`https`。
  * **域名** :如 `example.com`。
  * **端口** :如 `8080`。
  * 同源策略要求这三者必须完全相同才能进行资源的访问和交互。例如,`https://example.com` 和 `http://example.com` 是不同的源,因为协议不同;`http://example.com:8080` 和 `http://example.com:9090` 是不同的源,因为端口不同。
*

  ##### 7.4.4 跨域的场景

  * **不同的域**:

    * 网站 A(`https://site-a.com`)想要访问网站 B(`https://site-b.com`)的资源。
  * **不同的协议**:

    * 网站 A(`http://site.com`)想要访问网站 B(`https://site.com`)的资源,协议不同。
  * **不同的端口**:

    * 网站 A(`http://site.com:8080`)想要访问网站 B(`http://site.com:9090`)的资源,端口不同。
*

  ##### 7.4.5 浏览器的跨域限制

  * 浏览器出于安全原因,限制了网页脚本对跨域资源的访问。比如,如果你的网页在 `http://localhost:3000` 上,试图去请求 `http://api.example.com` 上的资源,浏览器会默认阻止这种请求,称为 **跨域请求(Cross-Origin Request)**。

    跨域请求的类型

    跨域请求可以分为两种类型:
    * **简单请求(Simple Request)**:

      * 请求方法是 `GET`、`POST` 或 `HEAD`。

      * 请求头只包括浏览器内置的标准头部(如 `Content-Type` 设置为 `application/x-www-form-urlencoded`、`multipart/form-data` 或 `text/plain`)。

    * **复杂请求(Preflighted Request)**:

      * 请求方法是 `PUT`、`DELETE` 或自定义的方法,或者请求头包含了非标准的自定义头部(例如 `Authorization`,`X-Custom-Header` 等)。

      * 在这种情况下,浏览器会先发送一个 **预检请求(Preflight Request)**,以确认服务器是否允许实际的请求。

*

  ##### 7.4.6 跨域的解决方案

  *

    ###### 7.4.6.1 CORS(跨域资源共享)

    * **CORS(Cross-Origin Resource Sharing)** 是一种浏览器和服务器之间的协议,它允许服务器声明哪些源(域、协议、端口)可以访问其资源。

    * 当浏览器发起跨域请求时,浏览器会自动添加一些 CORS 相关的头部信息:

      * **`Origin`**:表示请求发起的源(域、协议、端口)。

      * **`Access-Control-Allow-Origin`**:服务器响应的头部,表示允许哪些源可以访问资源。

    * **CORS 预检请求** : 当浏览器发起一个复杂的跨域请求时(例如,方法是 `PUT`、`DELETE` 或请求头包含自定义头),浏览器会先发起一个 **OPTIONS** 请求,即 **预检请求(Preflight Request)**,询问服务器是否允许跨域请求。如果服务器返回适当的响应头,则允许实际请求的发送。

    * **CORS 响应头**:

      * **`Access-Control-Allow-Origin`** :允许访问的源,`*` 表示所有域都可以访问,或者可以指定特定的域(如 `http://example.com`)。

      * **`Access-Control-Allow-Methods`** :允许的 HTTP 方法(如 `GET`, `POST`, `PUT`, `DELETE`)。

      * **`Access-Control-Allow-Headers`**:允许的请求头。

      * **`Access-Control-Allow-Credentials`**:是否允许带上身份凭证(如 Cookies)。

      * **`Access-Control-Max-Age`**:预检请求的有效时间,表示浏览器在多长时间内不需要再次发送预检请求。

    *

               @Override
                public void addCorsMappings(CorsRegistry registry) {
                    // 配置全局跨域
                    registry.addMapping("/**")
                            .allowedOrigins("http://example.com") // 允许来自 example.com 的跨域请求
                            .allowedMethods("GET", "POST") // 允许的请求方法
                            .allowedHeaders("*"); // 允许所有请求头
                }

  *

    ###### 7.4.6.2 JSONP(仅限 GET 请求)

    * 在早期,浏览器没有支持 CORS 机制时,开发者常用 **JSONP** 来绕过跨域限制。JSONP 是通过 `<script>` 标签的跨域特性来发送请求的,但它只支持 `GET` 请求,不支持发送其他类型的请求,如 `POST`。
  *

    ###### 7.4.6.3 服务器端代理(推荐)

    * 一种常见的解决跨域问题的方式是通过设置 **代理服务器**。前端应用发送请求到同源的代理服务器,由代理服务器转发请求到实际的跨域资源服务器。代理服务器和跨域服务器之间的请求不受浏览器的同源策略限制。
复制代码
#### 7.5 消息转换器(Message Converters)

* Spring MVC 使用 `HttpMessageConverter` 来将请求和响应的主体内容转换成 Java 对象或从 Java 对象转换为响应的格式(如 JSON、XML)。你可以定制消息转换器来支持自定义的序列化方式。

*

        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            // 创建 Jackson 转换器
            MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
            
            // 创建 ObjectMapper 并进行配置
            ObjectMapper objectMapper = new ObjectMapper();
            
            // 排除 null 字段
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            
            // 设置日期格式
            objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            
            // 可以通过 Jackson 的 MixIn 来定制序列化规则
            objectMapper.addMixIn(SomeClass.class, SomeClassMixIn.class);
        
            // 设置 ObjectMapper 到 Jackson 转换器
            jacksonConverter.setObjectMapper(objectMapper);
            
            // 添加到转换器列表
            converters.add(jacksonConverter);
        }
复制代码
#### 7.8 定制异常处理(@ExceptionHandler)(不推荐)

*

        @Configuration
        public class WebConfig implements WebMvcConfigurer {
            @Override
            public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
                // 定制异常处理
                resolvers.add(new MyCustomExceptionResolver());
            }
        }

8. 支持文件上传与下载

复制代码
#### **8.1**文件上传

*

  ##### 8.1.1 配置文件上传的基本设置

  * 在 Spring Boot 中,文件上传的功能默认已经启用。但是,你可以在 `application.properties` 或 `application.yml` 中配置一些上传限制(如文件大小)。
  *

          # 最大上传文件大小
          spring.servlet.multipart.max-file-size=10MB
          # 最大请求数据大小
          spring.servlet.multipart.max-request-size=10MB

*

  ##### 8.1.2 实现文件上传接口

  *

          @RestController
          @RequestMapping("/api/files")
          public class FileUploadController {
          
              @Value("${file.upload-dir}")
              private String uploadDir;  // 用于存储文件的目录
          
              // 文件上传接口
              @PostMapping("/upload")
              public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
                  try {
                      // 获取文件名
                      String fileName = file.getOriginalFilename();
                      // 将文件存储到指定目录
                      Path path = Paths.get(uploadDir, fileName);
                      Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
                      return ResponseEntity.ok("文件上传成功:" + fileName);
                  } catch (IOException e) {
                      e.printStackTrace();
                      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                              .body("文件上传失败:" + e.getMessage());
                  }
              }
          }

*

  ##### 8.1.3 上传目录配置

  * 你可以在 `application.properties` 文件中指定文件上传的目录。例如:
  *

          # 文件存储路径
          file.upload-dir=./uploads

*

  ##### 8.1.4 上传多个文件

  *

          @PostMapping("/uploadMultiple")
          public ResponseEntity<String> uploadMultipleFiles(@RequestParam("files") List<MultipartFile> files) {
              for (MultipartFile file : files) {
                  // 保存每个文件
                  try {
                      String fileName = file.getOriginalFilename();
                      Path path = Paths.get(uploadDir, fileName);
                      Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
                  } catch (IOException e) {
                      e.printStackTrace();
                      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                              .body("部分文件上传失败:" + e.getMessage());
                  }
              }
              return ResponseEntity.ok("所有文件上传成功");
          }
复制代码
#### 8.2 文件下载

*

  ##### 8.2.1 实现文件下载接口

  * 下载文件的实现比较简单,通常使用 `HttpServletResponse` 来将文件内容写入响应流中,浏览器会自动处理并触发文件下载。

  *

          @RestController
          @RequestMapping("/api/files")
          public class FileDownloadController {
          
              @Value("${file.upload-dir}")
              private String uploadDir;  // 文件存储目录
          
              // 文件下载接口
              @GetMapping("/download/{fileName}")
              public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) {
                  try {
                      // 获取文件路径
                      Path filePath = Paths.get(uploadDir).resolve(fileName).normalize();
                      // 如果文件不存在,抛出异常
                      Resource resource = new FileSystemResource(filePath);
                      if (!resource.exists()) {
                          throw new FileNotFoundException("文件未找到:" + fileName);
                      }
                      // 返回文件资源并设置下载的 Content-Disposition
                      return ResponseEntity.ok()
                              .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + resource.getFilename() + """)
                              .body(resource);
                  } catch (Exception e) {
                      e.printStackTrace();
                      return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
                  }
              }
          }

*

  ##### 8.2.2 设置响应头部以下载文件

  * 通过 `Content-Disposition` 响应头可以让浏览器以下载的形式处理文件而不是直接显示内容。上述代码中已经设置了这个头部:

  *

          .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + resource.getFilename() + """)
相关推荐
咖啡の猫2 小时前
Shell脚本-for循环应用案例
前端·chrome
uzong3 小时前
面试官:Redis中的 16 库同时发送命令,服务端是串行执行还是并行执行
后端·面试·架构
百万蹄蹄向前冲4 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
追逐时光者5 小时前
.NET 使用 MethodTimer 进行运行耗时统计提升代码的整洁性与可维护性!
后端·.net
朝阳5815 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路5 小时前
GeoTools 读取影像元数据
前端
练习时长一年5 小时前
AopAutoConfiguration源码阅读
java·spring boot·intellij-idea
ssshooter5 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友6 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry6 小时前
Jetpack Compose 中的状态
前端