目录
[1. WebJars 资源访问](#1. WebJars 资源访问)
[2. 静态资源访问](#2. 静态资源访问)
[3. 欢迎页配置](#3. 欢迎页配置)
[Spring MVC组件的自动配置](#Spring MVC组件的自动配置)
FileUploadController.java(/upload)
经过前面对SpringBoot第一课的学习,大致也总结出对springboot的使用流程:
②少量配置即可运行 :Spring Boot 具有自动配置的特性,默认将很多常见的开发场景(如 Web 开发的服务器配置、数据库连接的基础配置等)都配置好了。开发者不需要进行大量复杂的配置工作,只需要在配置文件(如 application.properties 或 application.yml)中指定少量必要的配置信息,就能够让应用程序运行起来。
③编写业务代码:当 Spring Boot 应用创建好并且基本配置完成后,开发者就可以专注于编写具体的业务逻辑代码了。例如,实现用户登录、数据处理、业务规则判断等功能,来满足实际项目的需求。
本文章就解读**"少量配置"** 和**"编写业务代码"**两方面进行讲解。
在开始讲解之前,先来说一说Spring Boot 框架中的两个核心概念:自动配置(AutoConfiguration)和属性配置(Properties)
-
xxxxAutoConfiguration(给容器中自动配置组件):指的是自动配置类,这些类帮助我们在 Spring Boot 应用中自动配置各种组件。Spring Boot 通过这些自动配置类,根据类路径中的 jar 包依赖和配置文件中的设置,自动配置应用的各个部分,从而简化了配置过程。
-
xxxxProperties(配置类来封装配置文件中的内容) :指的是配置属性类,这些类用于封装外部配置文件(如
application.properties
或application.yml
)中的内容。通过将配置文件中的属性映射到这些类中的字段,Spring Boot 能够将配置值注入到应用的各个组件中,实现配置的集中管理和使用。
所以向查看这两个方面的源码,可以参见类名带这两个后缀的类。
一、SpringBoot对静态资源的映射规则
在 Spring Boot 2.4 之前,静态资源的配置属性主要由 ResourceProperties
类来管理,它位于 org.springframework.boot.autoconfigure.web
包下,相关配置项以 spring.resources
作为前缀;
但是在从 Spring Boot 2.4 开始,静态资源的配置属性被整合到了 WebProperties
类中,该类位于 org.springframework.boot.autoconfigure.web
包下。其中,静态资源相关的配置被封装在 WebProperties.Resources
这个内部类里(WebProperties的前缀是spring.web,而ResourceProperties
作为内部封装类,它的前缀依旧是 spring.resources
,所以2.4后想在配置文件更改它的信息前缀就变成了spring.web.resources
)。
可以在External Libraries里查看(由于我用的是2.7.0版本,所以在这里我就展示WebProperties类,代码功能都是一样的
):
External Libraries目录下
就在这个包里面,顺着org.springframework.boot.autoconfigure.web查看
:
顺着路径向下找
可以点开查看这个封装类的源码:
就是这一个(2.4后封装位置)
可以看见内部:
WebProperties源码
1. WebJars 资源访问
WebJars 是一种将前端库(如 jQuery、Bootstrap 等)打包成 Java 可识别的 JAR 文件的方式。这样做的好处是可以利用 Maven 或 Gradle 等构建工具来管理这些库的依赖,同时保持项目的依赖关系清晰。
在 Spring Boot 项目中,所有以 /webjars/**
开头的请求都会被映射到 classpath:/META-INF/resources/webjars/
目录下寻找资源。这意味着,如果在项目中引入了 WebJars 资源,你可以通过 /webjars/
路径前缀来访问这些资源。
【注:所有以
/webjars/**
开头的请求通常是指那些通过<groupId>org.webjars</groupId>
引入的依赖】
例如,如果在 pom.xml
文件中添加了以下依赖:
XML
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
那么就可以通过访问 http://localhost:8080/webjars/jquery/3.3.1/jquery.js
来获取 jQuery 库的 JavaScript 文件。
也可以在External Libraries这里查看:
查看External Libraries里的jQuery
2. 静态资源访问
在 Spring Boot 项目中,可以通过多种路径前缀来访问静态资源。这些路径前缀包括(优先级也是下面这个顺序从高到低):
-
classpath:/META-INF/resources/
-
classpath:/resources/
-
classpath:/static/
-
classpath:/public/
在 Maven 项目中,这些目录可能位于:
src/main/resources/META-INF/resources/
src/main/resources/resources/
src/main/resources/static/
src/main/resources/public/
这些路径通常对应于项目中的目录结构,例如 Maven 项目中的 src/main/resources
目录。通过这些路径,可以访问存放在这些目录下的静态资源,如 HTML、CSS、JavaScript 文件等。
例如,如果在 src/main/resources/static
目录下有一个名为 abc
的文件,可以通过访问 http://localhost:8080/abc
来获取这个文件。
3. 欢迎页配置
在 Spring Boot 项目中,可以通过配置来设置欢迎页。当用户访问应用的根路径(如 http://localhost:8080/
)时,Spring Boot 会尝试在静态资源文件夹下查找 index.html
文件作为欢迎页。
如果在静态资源文件夹下存在多个 index.html
文件,Spring Boot 会按照一定的规则选择一个作为欢迎页。通常,它会查找第一个找到的 index.html
文件。
这种方式使得配置欢迎页变得非常简单,只需要在静态资源文件夹下放置一个 index.html
文件即可。
Springboot自动指定resources下的index.html
二、S pringBoot 整合springmvc
springboot整合mvc本质来说就是对它的组件实现了自动装配:
中央转发器(DispatcherServlet)
控制器
视图解析器
静态资源访问
消息转换器
格式化
静态资源管理
这些组件在springmvc中的运作流程和功能详见下面这篇博客:
概述
Spring Boot对Spring MVC进行了自动配置,简化了Spring MVC的使用。它通过自动配置类(如WebMvcAutoConfiguration
)和注解扫描,使得开发者无需手动配置大量的Spring MVC相关组件,如DispatcherServlet
、视图解析器、消息转换器等。同时,Spring Boot还提供了扩展机制,允许开发者根据业务需求进行自定义配置。
Spring MVC组件的自动配置
中央转发器(DispatcherServlet)
-
自动配置 :Spring Boot自动接管了
DispatcherServlet
的配置,无需在web.xml
中手动配置。DispatcherServlet
的配置由**DispatcherServletAutoConfiguration
**类完成。 -
默认配置 :默认情况下,
DispatcherServlet
拦截/
路径下的所有请求(包括静态资源,但不包括JSP请求)。可以通过**server.servletPath
**属性修改其拦截路径。
控制器(Controller)
-
自动管理 :在Spring Boot的注解扫描范围内,使用
@Controller
或@RestController
注解的类会被自动识别并管理为Spring MVC的控制器。 -
注解扫描 :Spring Boot默认会扫描与主应用类同级或子级的包中的注解类。如果需要扫描其他包,可以通过
@ComponentScan
注解指定。
视图解析器
-
自动配置 :Spring Boot自动配置了视图解析器,包括
InternalResourceViewResolver
和ContentNegotiatingViewResolver
等。 -
默认配置 :默认的视图解析器前缀为
classpath:/templates/
,后缀为.html
(如果使用Thymeleaf模板引擎的话-引入了Thymeleaf的依赖)。可以通过application.properties
文件中的**spring.mvc.view.prefix
和spring.mvc.view.suffix
**属性进行自定义(这个出自于WebMvcProperties封装类)。
实现springmvc的文件上传
当我们做文件上传的时候我们也会发现multipartResolver是自动被配置好的,它被封装在MultipartAutoConfiguration类中,处 org.springframework.boot.autoconfigure.web.servlet
包下。
注意看这个类的前缀
可以通过配置文件配置如下属性:
python
# 是否启用文件上传支持,默认为 true
spring.servlet.multipart.enabled=true
# 上传文件的临时存储目录
spring.servlet.multipart.location=
# 单个文件的最大大小,默认为 1MB
spring.servlet.multipart.max-file-size=1MB
# 整个请求的最大大小,默认为 10MB
spring.servlet.multipart.max-request-size=10MB
# 文件写入磁盘的阈值,默认值为 0
spring.servlet.multipart.file-size-threshold=0
# 是否延迟解析多部分请求,默认为 false
spring.servlet.multipart.resolve-lazily=false
在讲解示例之前,照例展示我用的pom.xml文件:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qcby</groupId>
<artifactId>springboot2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot2</name>
<description>springboot2</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!--thymeleaf模块支撑-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--消息转换扩展-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
顺带附赠演示项目的目录结构
upload.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>File Upload</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input name="pic" type="file">
<input type="submit">
</form>
</body>
</html>
<!--
action 属性:指定表单数据提交的目标 URL。在这段代码中,action="/upload" 表示表单数据将被发送到服务器的 /upload 路径进行处理。
method 属性:规定表单数据的提交方式,常见的有 GET 和 POST。这里使用 method="post",意味着表单数据会以 HTTP POST 请求的方式发送到服务器,适合用于提交包含敏感信息或大量数据的表单,如文件上传。
enctype 属性:指定表单数据在发送到服务器之前的编码方式。对于文件上传,必须使用 enctype="multipart/form-data",这种编码方式允许表单数据以多部分的形式进行传输,能够处理二进制文件数据。
-->
FileUploadController.java(/upload)
java
package com.qcby.springboot2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller //标记为一个控制器类
public class FileUploadController {
@ResponseBody
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(@RequestParam("pic") MultipartFile file, HttpServletRequest request) {
//@RequestParam("pic") MultipartFile file:从请求中获取名为 pic 的文件参数(在html表单中设置了),MultipartFile 是 Spring 框架提供的用于处理文件上传的接口。
String contentType = file.getContentType();
String fileName = file.getOriginalFilename();
String filePath = "D:\\001_Myclass001\\javava\\TestAll"; // 修改路径
try {
this.uploadFile(file.getBytes(), filePath, fileName);
} catch (Exception e) {
// TODO: handle exception
return "upload error";
}
return "upload"; //上传成功后在前端返回字符串
}
public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {
File targetFile = new File(filePath);
if (!targetFile.exists()) {
targetFile.mkdirs();
}
FileOutputStream out = new FileOutputStream(filePath + File.separator + fileName); // 使用 File.separator
out.write(file);
out.flush();
out.close();
}
}
启动项目框架,输入"http://localhost:8080/upload"(因为我没有在配置文件中更改路径或端口号):
得到:
访问后得到
选择文件并提交后就可以得到:
提交成功后得到
消息转换和格式化
1.消息转换器
概念
消息转换器(Message Converters)是 Spring MVC 中的一个核心组件,**用于在 HTTP 请求和响应中进行数据的序列化和反序列化,这是前后端交互(交互产生的信息都是消息)**过程中不可或缺的一部分。当客户端发送请求时,消息转换器会将请求体中的数据转换为 Java 对象;当服务器返回响应时,消息转换器会将 Java 对象转换为合适的响应体格式(如 JSON、XML 等)。
Springboot自动配置了消息转换器(HttpMessageConvertersAutoConfiguration类中)
2.格式化
格式化通常指的是将数据转换成特定格式的过程,以便它可以用于显示、存储或传输(封装在)。
实现格式化功能可以通过实现WebMvcConfigurer
接口和在配置文件中编写配置这两种方式来实现。
以时间格式化为例:
①实现WebMvcConfigurer
接口

②配置文件编写

实现
WebMvcConfigurer
接口和在配置文件中编写配置这两种有什么区别呢?最大的区别就是通过实现接口的方式配置功能更加自由。
如下是配置文件的几种选项
但是通过实现接口的方式进行配置可以有更多选择。
三、Springboot扩展springmvc
在实际开发中springboot并非完全自动化,很多跟业务相关我们需要自己扩展,springboot给我提供了接口,我们可以来通过实现WebMvcConfigurer接口来扩展。
瞅一眼项目封装的WebMvcConfigurer接口
我为这个源码加上了注释,标明每个方法是可以拓展什么:
java
package org.springframework.web.servlet.config.annotation;
import java.util.List;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
public interface WebMvcConfigurer {
// 配置路径匹配的选项
default void configurePathMatch(PathMatchConfigurer configurer) {
}
// 配置内容协商选项(例如,基于请求头的内容类型和接受类型来选择响应的媒体类型)
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
// 配置异步请求处理(例如,使用DeferredResult或Callable来处理长时间运行的任务)
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
// 配置默认的Servlet处理(例如,映射到dispatcherServlet的URL路径)
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
// 添加自定义格式化器到FormatterRegistry,用于数据绑定时的格式化和解析
default void addFormatters(FormatterRegistry registry) {
}
// 添加拦截器到拦截器注册表,用于拦截和处理请求
default void addInterceptors(InterceptorRegistry registry) {
}
// 添加资源处理器到资源处理器注册表,用于处理静态资源请求
default void addResourceHandlers(ResourceHandlerRegistry registry) {
}
// 添加跨域资源共享(CORS)映射到CORS注册表
default void addCorsMappings(CorsRegistry registry) {
}
// 添加视图控制器到视图控制器注册表,用于处理特定的URL路径
default void addViewControllers(ViewControllerRegistry registry) {
}
// 配置视图解析器选项
default void configureViewResolvers(ViewResolverRegistry registry) {
}
// 添加自定义参数解析器到参数解析器列表,用于解析控制器方法的参数
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
}
// 添加自定义返回值处理器到返回值处理器列表,用于处理控制器方法的返回值
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
}
// 配置消息转换器列表,用于处理HTTP请求和响应的序列化和反序列化
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
// 扩展消息转换器列表,可以添加或修改现有的消息转换器
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
// 配置异常解析器列表,用于解析和处理异常
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
// 扩展异常解析器列表,可以添加或修改现有的异常解析器
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
// 提供一个自定义的验证器(Validator)实例,用于数据验证
@Nullable
default Validator getValidator() {
return null;
}
// 提供一个自定义的消息代码解析器(MessageCodesResolver)实例,用于解析验证错误消息的代码
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
下面就来简单用一下实现接口配置来实现业务:
1.在 容器中 注册视图 控制器 ( 请求转发 )
java
@Controller
public class MyMVCCofnig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/tx").setViewName("success");
//将 /tx 路径映射到 success 视图下(前端页面)
}
2.拦截器设置
拦截类:
java
package com.qcby.springboot2;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器
*/
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前置拦截");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("后置拦截");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("最终拦截");
}
}
实现WebMvcConfigurer类的Java:
java
package com.qcby.springboot2;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
@Controller
public class MyMVCCofnig implements WebMvcConfigurer {
/**
* 重写拦截器
*
* 配置一个名为MyInterceptor的拦截器,使其应用于所有请求路径,除了/hello2(拦截所有请求,除了hello2)
*可以得到结果,在访问hello2时,并不会在控制台打印拦截,但是当访问hello1时(对比),就会打印三条拦截消息
* */
@Autowired
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/hello2");
}
}
再来一个controller类:
java
package com.qcby.springboot2;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController1 {
@GetMapping("/hello1")
public String hello() {
return "Hello, World 1!";
}
@GetMapping("/hello2")
public String hello2() {
return "Hello, World 2!";
}
}
可以得到:
访问hello1
由于除了hello2请求,其他的都会受到拦截,所以这里的hello1请求就会收到后台的拦截类提醒(准确来说访问除hello2外的所有请求都会收到拦截通知):

现在清空后台再来访问一下hello2试验一下:
访问hello2
后台空空
补充(配置类的加载顺序)
可以注意到在上面展示的那些源码中,经常会有
@AutoConfigureOrder
和@Order这两个注解:
首先@AutoConfigureOrder
和@Order
注解是用于控制Spring Boot配置类的加载顺序的。
@Order 是通用的,适用于所有Spring管理的Bean,控制加载或执行顺序。
@AutoConfigureOrder 是专门用于Spring Boot自动配置类的,确保自动配置类的加载顺序。
序列规则 :两者都遵循"值越小,优先级越高"的规则,但默认值不同(
@Order
默认为Integer.MAX_VALUE
,@AutoConfigureOrder
默认为0
)。