栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【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;
}


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 修改自定义配置

修改自定义配置,让首页请求到来时,会被拦截然后转到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 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可以给我们省去很多麻烦。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/318068.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号