SpringBoot对SpringMVC的整合

目录

1.中央转发器

2.控制器Controller

3.视图解析器自动管理

4.欢迎页面的自动配置


1.中央转发器

传统的mvc是通过在web.xml配置文件当中配置DispatcherServlet :

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
    <!-- 配置 DispatcherServlet -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 指定Spring MVC配置文件位置 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <!-- 配置Servlet映射 -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

在springboot项目当中,中央转发器被springboot自动接管,不再需要我们在web.xml中配置。

我们可以在源码当中看到配置:

在org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\当中:

我们能看到几个关键的方法:

java 复制代码
Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
	DispatcherServlet dispatcherServlet = new DispatcherServlet();
	dispatcherServlet.setDispatchOptionsRequest(
			this.webMvcProperties.isDispatchOptionsRequest());
	dispatcherServlet.setDispatchTraceRequest(
			this.webMvcProperties.isDispatchTraceRequest());
	dispatcherServlet.setThrowExceptionIfNoHandlerFound(
			this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
	return dispatcherServlet;
}

这个方法自动创建了DispatcherServlet,自动配置了各种属性。

java 复制代码
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public ServletRegistrationBean dispatcherServletRegistration(
		DispatcherServlet dispatcherServlet) {
	ServletRegistrationBean registration = new ServletRegistrationBean(
			dispatcherServlet, this.serverProperties.getServletMapping());
	registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
	registration.setLoadOnStartup(
			this.webMvcProperties.getServlet().getLoadOnStartup());
	if (this.multipartConfig != null) {
		registration.setMultipartConfig(this.multipartConfig);
	}
	return registration;
}

这个方法自动创建了servlet

2.控制器Controller

在Springboot的主启动类当中,有@SpringBootApplication注解,里面有@ComponentScan注解,在之前自动装配的时候说过:@ComponentScan 会扫描主启动类所在包及其子包,包括:@Controller,@Service,@Repository,@Component等其他Spring组件

3.视图解析器自动管理

视图解析器InternalResourceViewResolver在springmvc当中的xml配置:

XML 复制代码
<!-- 在 springmvc.xml 中配置MVC组件 -->
<beans>
    <!-- 组件扫描 -->
    <context:component-scan base-package="com.example.controller"/>
    
    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    
    <!-- MVC注解驱动 -->
    <mvc:annotation-driven/>
</beans>

Spring Boot 在 WebMvcAutoConfiguration 中自动配置视图解析器:

java 复制代码
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public class WebMvcAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean(InternalResourceViewResolver.class)
    @ConditionalOnProperty(prefix = "spring.mvc", name = "view.prefix")
    public InternalResourceViewResolver defaultViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix(this.mvcProperties.getView().getPrefix());
        resolver.setSuffix(this.mvcProperties.getView().getSuffix());
        return resolver;
    }
}

需要满足的条件:

java 复制代码
@ConditionalOnMissingBean(InternalResourceViewResolver.class)  // 用户没有自定义时才生效
@ConditionalOnProperty(prefix = "spring.mvc", name = "view.prefix")  // 配置了前缀时才生效

所以需要我们手动在application.yaml当中配置:

java 复制代码
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

4.消息转换和格式化

Springboot自动配置了消息转换器

我们在idea中Ctrl+N进入全局查找,输入HttpMessageConverter,找到接口:

点击之后可以查看其实现类:

格式化转换器的自动注册

我们在WebMvcAutoConfiguration类的addFormatters方法的第一行打断点,然后debug:

debug的信息可以看到它的主要功能:

类型转换:String ↔ 各种Java类型

数据格式化:日期、数字、货币等格式化

注解驱动:处理 @DateTimeFormat、@NumberFormat 等注解

我们仔细查看debug信息可以看到:

java 复制代码
// Long类型格式化
@DateTimeFormat java.lang.Long -> java.lang.String: 
    DateTimeFormatAnnotationFormatterFactory@d3e3085
@NumberFormat java.lang.Long -> java.lang.String: 
    NumberFormatAnnotationFormatterFactory@4b87074a

// Java 8 日期时间格式化
java.time.LocalDate -> java.lang.String: 
    Jsr310DateTimeFormatAnnotationFormatterFactory@73ca34e7
java.time.LocalDate -> java.lang.String: 
    TemporalAccessorPrinter@4d98e41b

java.time.LocalDateTime -> java.lang.String: 
    Jsr310DateTimeFormatAnnotationFormatterFactory@73ca34e7
java.time.LocalDateTime -> java.lang.String: 
    TemporalAccessorPrinter@4d98e41b

4.欢迎页面的自动配置

Springboot自动指定resources下的index.html

我们全局查找ResourceProperties这个类,在里面能看到getStaticWelcomePageLocations()方法:

java 复制代码
private String[] getStaticWelcomePageLocations() {
		String[] result = new String[this.staticLocations.length];
		for (int i = 0; i < result.length; i++) {
			String location = this.staticLocations[i];
			if (!location.endsWith("/")) {
				location = location + "/";
			}
			result[i] = location + "index.html";
		}
		return result;
	}

这个方法可以构建完整的欢迎页面路径,结合getWelcomePage()方法使用:

java 复制代码
	public Resource getWelcomePage() {
		for (String location : getStaticWelcomePageLocations()) {
			Resource resource = this.resourceLoader.getResource(location);
			try {
				if (resource.exists()) {
					resource.getURL();
					return resource;
				}
			}
			catch (Exception ex) {
				// Ignore
			}
		}
		return null;
	}

我们分别在static目录下创建index.html,然后在getWelcomePage()方法的第一行打断点:

如图:(注意不能在resource目录下创建,后续debug时会说)

我们查看debug信息:

可以看到springboot查找欢迎页面的默认位置:

java 复制代码
// Spring Boot 只在以下位置查找 index.html:
1. classpath:/META-INF/resources/index.html
2. classpath:/resources/index.html// 注意:这是 resources/resources/ 目录!
3. classpath:/static/index.html  
4. classpath:/public/index.html

然后在getWelcomePage()方法中,

Debug 时会按顺序检查:

classpath:/META-INF/resources/index.html → ❌ 不存在

classpath:/resources/index.html → 找到文件

classpath:/static/index.html → 不会执行到这里

classpath:/public/index.html → 不会执行到这里

如图:

相关推荐
珹洺2 小时前
Java-Spring入门指南(三十二)Android SQLite数据库实战
java·数据库·spring
刘一说2 小时前
深入理解 Spring Boot 高级特性:条件化 Bean 注册机制
java·spring boot·后端
用户69371750013842 小时前
Kotlin 函数详解:命名参数与默认参数值
android·后端·kotlin
启山智软2 小时前
使用 Spring Boot + Vue.js 组合开发多商户商城(B2B2C平台)是一种高效的全栈技术方案
vue.js·spring boot·后端
用户90555842148052 小时前
请求失败溯源Netty关闭连接源码流程
后端
Han.miracle2 小时前
JavaEE ——多线程的线程安全集合类
java·java-ee
踏浪无痕2 小时前
准备手写Simple Raft(一):想通Raft的核心问题
分布式·后端
00后程序员2 小时前
Charles抓包实战,开发者如何通过流量分析快速定位系统异常?
后端