【SpringBoot学习笔记 八】SpringBoot定制整合SpringMVC

简介: 【SpringBoot学习笔记 八】SpringBoot定制整合SpringMVC

上篇Blog详细探讨了SpringBoot是如何整合数据源的,从JDBC层面、数据源连接池层面(Druid),再到MyBatis层面。我们分别使用了spring-boot-starter-data-jdbc、druid-spring-boot-starter、mybatis-spring-boot-starter这三个封装好的场景启动器,通过SpringBoot的自动配置机制我们只需要关心yml配置文件内容即可简单方便的使用SpringBoot操作数据库,可以说非常方便,至少比起Spring整合MyBatis节省了不少代码和配置。同样SpringBoot整合SpringMVC也非常方便,通过spring-boot-starter-web场景启动器即可。

spring-boot-starter-web场景启动器

spring-boot-starter-web 为我们提供了嵌入的 Servlet 容器以及 SpringMVC 的依赖,并为 Spring MVC 提供了大量自动配置,可以适用于大多数 Web 开发场景。Spring Boot 为 Spring MVC 提供了自动配置,并在 Spring MVC 默认功能的基础上添加了以下特性:

  • 引入了 ContentNegotiatingViewResolver 和 BeanNameViewResolver(视图解析器)
  • 对包括 WebJars 在内的静态资源的支持,支持对静态首页(index.html)的访问
  • 自动注册 Converter、GenericConverter 和 Formatter (转换器和格式化器)
  • 对 HttpMessageConverters 的支持(Spring MVC 中用于转换 HTTP 请求和响应的消息转换器)
  • 自动注册 MessageCodesResolver(用于定义错误代码生成规则)
  • 自动使用 ConfigurableWebBindingInitializer

只要我们在 Spring Boot 项目中的 pom.xml 中引入了 spring-boot-starter-web ,即使不进行任何配置,也可以直接使用 Spring MVC 进行 Web 开发,如果大家有没有印象可以看下我的第一篇SpringBoot的Blog【SpringBoot学习笔记 一】SpringBoot基本概念和项目初始化,当时第一次引入web模块的时候其实已经自动引入了SpringMVC。对比之前的Spring整合SpringMVC,以下步骤都省略了:

我们专注于自己的逻辑即可,SpringBoot的自动配置都替我们做好了。

SpringMVC自动配置原理

Spring Boot 抛弃了传统 xml 配置文件,通过配置类(标注 @Configuration 的类,相当于一个 xml 配置文件)以 JavaBean 形式进行相关配置。Spring Boot 对 Spring MVC 的自动配置可以满足我们的大部分需求,但是我们也可以通过自定义配置类(标注 @Configuration 的类)并实现 WebMvcConfigurer 接口来定制 Spring MVC 配置,例如拦截器、格式化程序、视图控制器等

WebMvcAutoConfiguration自动配置类

在自动配置原理SpringBoot学习笔记 四】SpringBoot自动配置原理这篇Blog中提到,在 spring-boot-autoconfigure-xxx.jar 类路径下的 META-INF/spring.factories 中设置了一些自动配置类,就包括WebMvcAutoConfiguration

它可以帮我们完成SpringMVC的自动整合和定制。

格式化举例说明

我们举个例子,找到格式化转换器,代码如下:

@Bean
        public FormattingConversionService mvcConversionService() {
            WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
            this.addFormatters(conversionService);
            return conversionService;
        }

跟进去可以看到:

public String getDateFormat() {
    return this.dateFormat;
}
/**
* Date format to use. For instance, `dd/MM/yyyy`. 默认的
 */
private String dateFormat;

可以看到在我们的Properties文件中,我们可以进行自动配置它,如果配置了自己的格式化方式,就会注册到Bean中生效,例如我们可以在配置文件中配置日期格式化的规则。

扩展SpringMVC功能

在 Spring Boot 项目中,我们可以通过以下 2 中形式定制 Spring MVC:扩展 Spring MVC,全面接管 Spring MVC

下面,我们分别对这两种定制 Spring MVC 的形式进行介绍

WebMvcConfigurer 是一个基于 Java 8 的接口,该接口定义了许多与 Spring MVC 相关的方法,其中大部分方法都是 default 类型的,且都是空实现。因此我们只需要定义一个配置类实现 WebMvcConfigurer 接口,并重写相应的方法便可以定制 Spring MVC 的配置

WebMvcConfigurer接口

如果 Spring Boot 对 Spring MVC 的自动配置不能满足我们的需要,我们还可以通过自定义一个 WebMvcConfigurer 类型(实现 WebMvcConfigurer 接口)的配置类(标注 @Configuration,但不标注 @EnableWebMvc 注解的类),来扩展 Spring MVC。这样不但能够保留 Spring Boot 对 Spring MVC 的自动配置,享受 Spring Boot 自动配置带来的便利,还能额外增加自定义的 Spring MVC 配置

定制修改SpringBoot的默认配置

我们可以修改SpringBoot的默认配置来自定义自己的实现,我们先来看下如果不开启拦截,首页请求会是什么样:

1 创建Controller

我们创建一个result的Controller跳转请求:

package com.example.springboot.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResultController {
    @GetMapping("/result")
    public String loginPage() {
        return "result";
    }
}

2 修改自定义配置

实现 WebMvcConfigurer 接口可以来扩展 SpringMVC 的功能

package com.example.springboot.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
//实现 WebMvcConfigurer 接口可以来扩展 SpringMVC 的功能
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //当访问 “/” 或 “/index.html” 时,都直接跳转到登陆页面
        registry.addViewController("/").setViewName("result");
    }
}

修改自定义配置,让首页请求到来时,会被拦截然后转到result的请求上去

package com.example.springboot.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResultController {
    @GetMapping("/result")
    public String loginPage() {
        return "我不是你想看到的首页,我是一个跳转定制页面,一个登录页面";
    }
}

3 请求首页查看效果

我们配置了自定义设置后再次进行首页请求查看:

扩展SpringMVC原理

为什么定制扩展可以生效呢?我们通过源码追溯一下:

WebMvcAutoConfiguration

是 SpringMVC的自动配置类,里面有一个类

WebMvcAutoConfigurationAdapter

这个类上有一个注解,在做其他自动配置时会导入:@Import(EnableWebMvcConfiguration.class),我们点进EnableWebMvcConfiguration这个类看一下,它继承了一个父类:

DelegatingWebMvcConfiguration

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
  // 从容器中获取所有的webmvcConfigurer
    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }
}

我们可以在这个类中去寻找一个我们刚才设置的viewController当做参考,发现它调用了一个

protected void addViewControllers(ViewControllerRegistry registry) {
    this.configurers.addViewControllers(registry);
}

继续向下看:

public void addViewControllers(ViewControllerRegistry registry) {
        Iterator var2 = this.delegates.iterator();
        while(var2.hasNext()) {
            WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
            delegate.addViewControllers(registry);
        }
    }

所以得出结论:所有的WebMvcConfiguration都会被作用,不止Spring自己的配置类,我们自己的配置类当然也会被调用

全面接管SpringMVC

全面接管即SpringBoot对SpringMVC的自动配置不需要了,所有内容都是我们自己去配置,实现方式只需在我们的配置类中加一个@EnableWebMvc,当然我们开发中,不推荐使用全面接管SpringMVC。

开启全面接管效果

开启全面接管比较简单,我们只需要在原有的定制配置类开启注解即可:

package com.example.springboot.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
//实现 WebMvcConfigurer 接口可以来扩展 SpringMVC 的功能
@Configuration
@EnableWebMvc
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //当访问 “/” 或 “/index.html” 时,都直接跳转到登陆页面
        registry.addViewController("/").setViewName("result");
    }
}

全面接管后再次请求:

Spring Boot 能够访问首页静态资源是SpringBoot默认的SpringMVC配置,全面接管后该自动配置失效

全面接管的原理

为什么加了一个注解,自动配置就失效了?我们看下源码:

EnableWebMVC注解

@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

这里发现它是导入了一个类,我们可以继续进去看

WebMvcConfigurationSupport类

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
  // ......
}

它继承了一个父类 WebMvcConfigurationSupport,我们来回顾一下Webmvc自动配置类

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// 这个注解的意思就是:容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
    ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
}

因为有了这个注解@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),导致

WebMvcAutoConfiguration自动配置不会生效,而WebMvcConfigurationSupport只有SpringMVC的基本功能,所以我们编写起来难度太大,不方便操作。

总结一下

首先,不要用全面接管,不要用全面接管,不要用全面接管,重要的事情说三遍,这样啥活都干不了了。其次我们可以发现定制的SpringMVC配置有点像拦截器,就是我们可以在默认的基础上修改请求,常用的一些功能还是很有用的,所以只要了解定制扩展方式就可以了,当然为什么全面接管生效的原理也需要简单了解下,知其然知其所以然,最后我们最好用封装好的场景启动器,例如:spring-boot-starter-web可以给我们省去很多麻烦。

相关文章
|
7月前
|
JSON 前端开发 Java
SpringBoot:SpringMVC(上)
SpringBoot:SpringMVC(上)
59 3
|
7月前
|
SQL JavaScript Java
springboot+springm vc+mybatis实现增删改查案例!
springboot+springm vc+mybatis实现增删改查案例!
|
3月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
|
2月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
195 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
2月前
|
前端开发 Java
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
文章介绍了如何使用SpringBoot创建简单的后端服务器来处理HTTP请求,包括建立连接、编写Controller处理请求,并返回响应给前端或网址。
61 0
学习SpringMVC,建立连接,请求,响应 SpringBoot初学,如何前后端交互(后端版)?最简单的能通过网址访问的后端服务器代码举例
|
4月前
|
前端开发 Java Spring
Java 新手入门:Spring Boot 轻松整合 Spring 和 Spring MVC!
Java 新手入门:Spring Boot 轻松整合 Spring 和 Spring MVC!
76 0
|
6月前
|
安全 前端开发 Java
挑战5分钟内基于Springboot+SpringMVC+Mybatis-plus快速构建web后端三层架构
挑战5分钟内基于Springboot+SpringMVC+Mybatis-plus快速构建web后端三层架构
59 1
|
6月前
|
Java 程序员
浅浅纪念花一个月完成Springboot+Mybatis+Springmvc+Vue2+elementUI的前后端交互入门项目
浅浅纪念花一个月完成Springboot+Mybatis+Springmvc+Vue2+elementUI的前后端交互入门项目
55 1
|
6月前
|
前端开发 Dubbo Java
spring面试题_spring mvc面试题_springboot面试题库
spring面试题_spring mvc面试题_springboot面试题库
|
5月前
|
XML 前端开发 Java
Spring Boot与Spring MVC的区别和联系
Spring Boot与Spring MVC的区别和联系