狂神说笔记——SpringBoot开发单体应用21

Spring Boot 开发单体应用(1)

1.SpringBoot Web开发

使用SpringBoot的步骤

  1. 创建一个SpringBoot应用,选择我们需要的模块,SpringBoot就会默认将我们的需要的模块自动配置好;
  2. 手动在配置文件中配置部分配置项目就可以运行起来了。
  3. 专注编写业务代码,不需要考虑以前那样一大堆的配置了。

自动装配

  • spring boot到底帮我们配置了什么?我们能不能进行修改?能修改哪些东西?能不能扩展?
  • xxxxAutoConfiguraion… 向容器中自动配置组件;
  • xxxxProperties:自动配置类,装配配置文件中自定义的一些内容!

2.静态资源处理

静态资源映射规则

  • 搭建一个普通的SpringBoot项目。
  • 写请求非常简单,那我们要引入我们前端资源,我们项目中有许多的静态资源,比如css,js等文件,这 个SpringBoot怎么处理呢?
  • 如果我们是一个web应用,我们的main下会有一个webapp,我们以前都是将所有的页面导在这里面 的,对吧!但是我们现在的pom呢,打包方式是为jar的方式,那么这种方式SpringBoot能不能来给我们 写页面呢?当然是可以的,但是SpringBoot对于静态资源放置的位置,是有规定的!
  • SpringBoot中,SpringMVC的web配置都在 WebMvcAutoConfiguration 这个配置类里面;有一个方法: addResourceHandlers 添加资源处理。
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!this.resourceProperties.isAddMappings()) {

        logger.debug("Default resource handling disabled");
    } else {

        Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
        CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();

        if (!registry.hasMappingForPattern("/webjars/**")) {
            this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
        }

        String staticPathPattern = this.mvcProperties.getStaticPathPattern();
        if (!registry.hasMappingForPattern(staticPathPattern)) {
            this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
        }

    }
}
  • 读一下源代码:比如所有的 /webjars/** , 都需要去 classpath:/META-INF/resources/webjars/ 找对应的资源。

那什么是webjars呢?

  • Webjars本质就是以jar包的方式引入我们的静态资源 , 我们以前要导入一个静态资源文件,直接导入即 可。
  • 使用SpringBoot需要使用Webjars,我们可以去搜索一下:
  • 网站:https://www.webjars.org 【网站带看,并引入jQuery测试】
  • 要使用jQuery,我们只要要引入jQuery对应版本的pom依赖即可!
<dependency>
    <groupId>org.webjarsgroupId>
    <artifactId>jqueryartifactId>
    <version>3.4.1version>
dependency>
  • 导入完毕,查看webjars目录结构,并访问Jquery.js文件!

狂神说笔记——SpringBoot开发单体应用21
  • 访问:只要是静态资源,SpringBoot就会去对应的路径寻找资源,这里访问 : http://localhost:8080/webjars/jquery/3.4.1/jquery.js

狂神说笔记——SpringBoot开发单体应用21

第二种静态资源映射规则

  • 当项目中要是使用自己的静态资源该怎么导入呢?看下一行代码;
  • 去找staticPathPattern发现第二种映射规则:/**, 访问当前的项目任意资源,它会去找 resourceProperties 这个类,我们可以点进去看一下分析:
public class ResourceProperties {

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
    private String[] staticLocations;
    private boolean addMappings;
    private final ResourceProperties.Chain chain;
    private final ResourceProperties.Cache cache;

    public ResourceProperties() {

        this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
        this.addMappings = true;
        this.chain = new ResourceProperties.Chain();
        this.cache = new ResourceProperties.Cache();
    }

    public String[] getStaticLocations() {
        return this.staticLocations;
    }

    ......

}
  • ResourceProperties 可以设置和我们静态资源有关的参数;这里面指向了它会去寻找资源的文件夹,即上面数组的内容。 所以得出结论,以下四个目录存放的静态资源可以被我们识别:
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"
  • 在resources根目录下新建对应的文件夹,都可以存放我们的静态文件; 比如我们访问 http://localhost:8080/1.js , 他就会去这些文件夹中寻找对应的静态资源文件;

狂神说笔记——SpringBoot开发单体应用21

狂神说笔记——SpringBoot开发单体应用21

自定义静态资源路径

  • 也可以自己通过配置文件来指定一下,哪些文件夹是需要我们放静态资源文件的,在 application.properties中配置;
spring.web.resources.static-locations=classpath:/coding/,classpath:/github/
  • 一旦自己定义了静态文件夹的路径,原来的自动配置就都会失效了!

狂神说笔记——SpringBoot开发单体应用21

3.首页和图标定制

  • 继续向下看源码!可以看到一个欢迎页的映射,就是我们的首页!
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {

    WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
    welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
    welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
    return welcomePageHandlerMapping;
}
  • 点击去继续
private Optional<Resource> getWelcomePage() {
    String[] locations = WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations());

    return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}

private Resource getIndexHtml(String location) {
    return this.resourceLoader.getResource(location + "index.html");
}
  • 欢迎页,静态资源文件夹下的所有 index.html 页面;被 /** 映射。
  • 比如我访问 http://localhost:8080/ ,就会找静态资源文件夹下的 index.html 【可以测试一下】
  • 新建一个 index.html ,在我们上面的3个目录中任意一个;然后访问测试 http://localhost:8080/ 看结果!
  • 注意:此功能需要取消自定义静态资源路径。

狂神说笔记——SpringBoot开发单体应用21

狂神说笔记——SpringBoot开发单体应用21

关于网站图标说明:

  • 2.2版本之后已删除!!!

狂神说笔记——SpringBoot开发单体应用21
  • 与其他静态资源一样,Spring Boot在配置的静态内容位置中查找 favicon.ico。如果存在这样的文件,它将自动用作应用程序的favicon。

  • 关闭SpringBoot默认图标!

关闭默认图标
spring.mvc.favicon.enabled=false
  1. 自己放一个图标在静态资源目录下,我放在 resources目录下, &#x56FE;&#x6807;&#x7684;&#x547D;&#x540D;&#x5FC5;&#x987B;&#x662F;favicon.ico
  2. 清除浏览器缓存!刷新网页,发现图标已经变成自己的了!

狂神说笔记——SpringBoot开发单体应用21

4.Thymeleaf模板引擎及语法

模板引擎

  • 前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等。
  • jsp支持非常强大的功能,包括能写Java代码,但是呢,我们现在的这种情况,SpringBoot这个项目首先是以jar的方式,不是war,像第二,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp 的。
  • 那不支持jsp,如果我们直接用纯静态页面的方式,那给我们开发会带来非常大的麻烦,那怎么办呢?
  • SpringBoot推荐你可以来使用模板引擎:
  • 模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有以用的比较多的freemarker,包括 SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想都是一样 的,什么样一个思想呢我们来看一下这张图:

狂神说笔记——SpringBoot开发单体应用21
  • 模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些 值,从哪来呢,就是我们在后台封装一些数据。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们 想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。只 不过呢,就是说不同模板引擎之间,他们可能这个语法有点不一样。其他的我就不介绍了,我主要来介 绍一下SpringBoot给我们推荐的Thymeleaf模板引擎,这模板引擎呢,是一个高级语言的模板引擎,他 的这个语法更简单。而且呢,功能更强大。
  • 首先,我们来看SpringBoot里边怎么用。

引入Thymeleaf

  • 怎么引入呢,对于springboot来说,什么事情不都是一个start的事情嘛,我们去在项目中引入一下。给如下三个网址:
  • Thymeleaf 官网:https://www.thymeleaf.org/
  • Thymeleaf 在Github 的主页:https://github.com/thymeleaf/thymeleaf
  • Spring官方文档: 找到我们对应的版本,Spring Boot Reference Documentation
  • 找到对应的pom依赖:可以适当点进源码看下本来的包!

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
  • Maven会自动下载jar包,我们可以去看下下载的东西;

狂神说笔记——SpringBoot开发单体应用21

thymeleaf 分析

  • 前面已经引入了Thymeleaf,那这个要怎么使用呢?
  • 我们首先得按照SpringBoot的自动配置原理看一下我们这个Thymeleaf的自动配置规则,在按照那个规则,我们进行使用。
  • 先去找一下Thymeleaf的自动配置类:ThymeleafProperties
@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    private Charset encoding;
    private boolean cache;
    private Integer templateResolverOrder;
    private String[] viewNames;
    private String[] excludedViewNames;
    private boolean enableSpringElCompiler;
    private boolean renderHiddenMarkersBeforeCheckboxes;
    private boolean enabled;
    private final ThymeleafProperties.Servlet servlet;
    private final ThymeleafProperties.Reactive reactive;
}
  • 可以在其中看到默认的前缀和后缀!
  • 我们只需要把我们的html页面放在类路径下的templates下,thymeleaf就可以帮我们自动渲染了。
  • 使用thymeleaf什么都不需要配置,只需要将他放在指定的文件夹下即可!

测试

  1. 编写一个TestController
@Controller
public class TestController {
    @RequestMapping("/t1")
    public String test(){

        return "test";
    }
}
  1. 编写一个测试页面 test.html 放在 templates 目录下
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试title>
head>
<body>

  <h1>测试页h1>
body>
html>
  1. 启动项目请求测试

狂神说笔记——SpringBoot开发单体应用21

Thymeleaf语法学习

  • 语法学习,参考官网:Thymeleaf
  • 做个最简单的练习:我们需要查出一些数据,在页面中展示。

  • 修改测试请求,增加数据传输;

@Controller
public class TestController {
    @RequestMapping("/t1")
    public String test(Model model){

        model.addAttribute("msg","hello,Thymeleaf");

        return "test";
    }
}
  1. 要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。可以去官方文档的#3中看一下命名空间拿来过来:
<html xmlns:th="http://www.thymeleaf.org">
  1. 编写前端页面
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>测试title>
head>
<body>

  <h1>测试页h1>

  <div th:text="${msg}">div>

body>
html>

狂神说笔记——SpringBoot开发单体应用21
  • OK,入门搞定,我们来认真研习一下Thymeleaf的使用语法!

  • 可以使用任意的 th:attr 来替换Html中原生属性的值!参考官网文档#10; th语法

狂神说笔记——SpringBoot开发单体应用21
  1. 具体能写那些表达式呢?可以参考官方文档 #4
Simple expressions:(表达式语法)
Variable Expressions: ${...}:获取变量值;OGNL;
  1)、获取对象的属性、调用方法
  2)、使用内置的基本对象: #18
      #ctx : the context object.

      #vars: the context variables.

      #locale : the context locale.

      #request : (only in Web Contexts) the HttpServletRequest object.

      #response : (only in Web Contexts) the HttpServletResponse object.

      #session : (only in Web Contexts) the HttpSession object.

      #servletContext : (only in Web Contexts) the ServletContext object.

  3)、内置的一些工具对象:
      #execInfo : information about the template being processed.

      #uris : methods for escaping parts of URLs/URIs
      #conversions : methods for executing the configured conversion
  service (if any).

      #dates : methods for java.util.Date objects: formatting, component
  extraction, etc.

      #calendars : analogous to #dates , but for java.util.Calendar
  objects.

      #numbers : methods for formatting numeric objects.

      #strings : methods for String objects: contains, startsWith,
  prepending/appending, etc.

      #objects : methods for objects in general.

      #bools : methods for boolean evaluation.

      #arrays : methods for arrays.

      #lists : methods for lists.

      #sets : methods for sets.

      #maps : methods for maps.

      #aggregates : methods for creating aggregates on arrays or
  collections.

  ============================================================================
  ======

      Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;
      Message Expressions: #{...}:获取国际化内容
      Link URL Expressions: @{...}:定义URL;
      Fragment Expressions: ~{...}:片段引用表达式
  Literals(字面量)
      Text literals: 'one text' , 'Another one!' ,...

      Number literals: 0 , 34 , 3.0 , 12.3 ,...

      Boolean literals: true , false
      Null literal: null
      Literal tokens: one , sometext , main ,...

  Text operations:(文本操作)
      String concatenation: +
      Literal substitutions: |The name is ${name}|
  Arithmetic operations:(数学运算)
      Binary operators: + , - , * , / , %
      Minus sign (unary operator): -
  Boolean operations:(布尔运算)
      Binary operators: and , or
      Boolean negation (unary operator): ! , not
  Comparisons and equality:(比较运算)
      Comparators: > , < , >= ,  ( gt , lt , ge , le )
      Equality operators: == , != ( eq , ne )
  Conditional operators:条件运算(三元运算符)
      If-then: (if) ? (then)
      If-then-else: (if) ? (then) : (else)
      Default: (value) ?: (defaultvalue)
  Special tokens:
      No-Operation: _

练习测试

  1. 编写一个Controller,放一些数据。
@RequestMapping("/t2")
public String test2(Map<String, Object> map) {

    map.put("msg","MSD");
    map.put("users", Arrays.asList("subei","github"));
    return "test";
}
  1. 编写前端页面
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>测试title>
head>
<body>

  <h1>测试页h1>

  <div th:text="${msg}">div>

  <div th:utext="${msg}">div>

<h3 th:each="user :${users}" th:text="${user}">h3>

body>
html>
  1. 启动测试!

狂神说笔记——SpringBoot开发单体应用21

根据官方文档来查询,才是最重要的,要熟练使用官方文档!

5.Spring MVC 配置原理

阅读官网

在进行项目编写前,还需要知道一个东西,就是SpringBoot对我们的SpringMVC还做了哪些配置,包括如何扩展,如何定制。

只有把这些都搞清楚了,在之后的使用才会更加得心应手。

Spring MVC Auto-configuration

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.

The auto-configuration adds the following features on top of Spring's defaults:

Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.

Support for serving static resources, including support for WebJars

Automatic registration of Converter, GenericConverter, and Formatter beans.

Support for HttpMessageConverters (covered later in this document).

Automatic registration of MessageCodesResolver (covered later in this document).

Static index.html support.

Custom Favicon support (covered later in this document).

Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration
(interceptors, formatters, view controllers, and other features), you can add your own
@Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide
custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or
ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

  • 仔细对照,看一下它怎么实现的,它告诉我们SpringBoot已经帮我们自动配置好了SpringMVC,然后自动配置了哪些东西呢?

ContentNegotiatingViewResolver 内容协商视图解析器

自动配置了ViewResolver,就是之前学习的SpringMVC的视图解析器;

即根据方法的返回值取得视图对象(View),然后由视图对象决定如何渲染(转发,重定向)。

  • 去看看这里的源码:我们找到 WebMvcAutoConfiguration , 然后搜索ContentNegotiatingViewResolver。找到如下方法!
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
    ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
    resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));

    resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return resolver;
}
  • 点进这类看看!找到对应的解析视图的代码;
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
    RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
    Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
    List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
    if (requestedMediaTypes != null) {

        List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);

        View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
        if (bestView != null) {
            return bestView;
        }
    }

    String mediaTypeInfo = this.logger.isDebugEnabled() && requestedMediaTypes != null ? " given " + requestedMediaTypes.toString() : "";
    if (this.useNotAcceptableStatusCode) {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo);
        }

        return NOT_ACCEPTABLE_VIEW;
    } else {
        this.logger.debug("View remains unresolved" + mediaTypeInfo);
        return null;
    }
}
  • 继续点进去看,他是怎么获得候选的视图的呢?
  • getCandidateViews中看到他是把所有的视图解析器拿来,进行while循环,挨个解析!
Iterator var5 = this.viewResolvers.iterator();
  • 所以得出结论: ContentNegotiatingViewResolver 这个视图解析器就是用来组合所有的视图解析器的
  • 再去研究下他的组合逻辑,看到有个属性viewResolvers,看看它是在哪里进行赋值的!
protected void initServletContext(ServletContext servletContext) {

    Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
    ViewResolver viewResolver;
    if (this.viewResolvers == null) {
        this.viewResolvers = new ArrayList(matchingBeans.size());
    }

}
  • 既然它是在容器中去找视图解析器,是否可以猜想,可以去实现一个视图解析器了呢?
  • 可以自己给容器中去添加一个视图解析器;这个类就会帮我们自动的将它组合进来;

  • 在主程序中去写一个视图解析器来试试;

@Bean
public ViewResolver myViewResolver(){
    return new MyViewResolver();
}

private static class MyViewResolver implements ViewResolver{
    @Override
    public View resolveViewName(String s, Locale locale) throws Exception {
        return null;
    }
}
  1. 看我们自己写的视图解析器有没有起作用呢? 我们给 DispatcherServlet 中的doDispatch方法加个断点进行调试一下,因为所有的请求都会走到这个方法中。

狂神说笔记——SpringBoot开发单体应用21
  1. 启动我们的项目,然后 &#x5728;&#x6D4F;&#x89C8;&#x5668;&#x968F;&#x4FBF;&#x8BBF;&#x95EE;&#x4E00;&#x4E2A;&#x9875;&#x9762;,看一下Debug信息;

狂神说笔记——SpringBoot开发单体应用21
  • 找到视图解析器,看到我们自己定义的就在这里了;

狂神说笔记——SpringBoot开发单体应用21
  • 所以说,如果想要使用自己定制化的东西,只需要给容器中添加这个组件就好了!剩下的事情SpringBoot就会帮我们做了!

转换器和格式化器

  • 找到格式化转换器:
@Bean
public FormattingConversionService mvcConversionService() {

    WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat());
    this.addFormatters(conversionService);
    return conversionService;
}
  • 点进去:
public String getDateFormat() {
    return this.dateFormat;
}

public void setDateFormat(String dateFormat) {
    this.dateFormat = dateFormat;
}

private String dateFormat;
  • 可以看到在Properties文件中,我们可以进行自动配置它!

狂神说笔记——SpringBoot开发单体应用21

修改SpringBoot的默认配置

这么多的自动配置,原理都是一样的,通过这个WebMVC的自动配置原理分析,我们要学会一种学习方式,通过源码探究,得出结论;这个结论一定是属于自己的,而且一通百通。

SpringBoot的底层,大量用到了这些设计细节思想,所以,没事需要多阅读源码!得出结论;

SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(如果用户自己配置@bean),如果有就用用户配置的,如果没有就用自动配置的;

如果有些组件可以存在多个,比如我们的视图解析器,就将用户配置的和自己默认的组合起来!

扩展使用SpringMVC 官方文档如下:

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

  • 要做的就是编写一个@Configuration注解类,并且类型要为WebMvcConfigurer,还不能标注@EnableWebMvc注解;我们去自己写一个;我们新建一个包叫config,写一个类MyMvcConfig;

@Configuration
public class MyMVCConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry){

        registry.addViewController("/test").setViewName("test");
    }
}

狂神说笔记——SpringBoot开发单体应用21

确实也跳转过来了!所以说,要扩展SpringMVC,官方推荐我们这么去使用,既保留SpringBoot 所有的自动配置,也能用我们扩展的配置!

  • 具体可以去分析一下原理:
  • WebMvcAutoConfiguration 是 SpringMVC的自动配置类,里面有一个类 WebMvcAutoConfigurationAdapter
  • 这个类上有一个注解,在做其他自动配置时会导入: @Import(EnableWebMvcConfiguration.class)
  • 当点进EnableWebMvcConfiguration这个类看一下,它继承了一个父类: DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();

    public DelegatingWebMvcConfiguration() {
    }

    @Autowired(
        required = false
    )
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }

    }
}
  1. 可以在这个类中去寻找一个上面刚才设置的viewController当做参考,发现它调用了一个。
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
    if (!CollectionUtils.isEmpty(configurers)) {
        this.delegates.addAll(configurers);
    }

}
  1. 点进去:
public void addFormatters(FormatterRegistry registry) {
    Iterator var2 = this.delegates.iterator();

    while(var2.hasNext()) {

        WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
        delegate.addFormatters(registry);
    }

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

全面接管SpringMVC

  • 官方文档:
If you want to take complete control of Spring MVC
you can add your own @Configuration annotated with @EnableWebMvc.

  • 全面接管即:SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己去配置!
  • 只需在我们的配置类中要加一个@EnableWebMvc。
  • 看下如果我们全面接管了SpringMVC了,我们之前SpringBoot给我们配置的静态资源映射一定会无效,我们可以去测试一下;
  • 不加注解之前,访问首页:

狂神说笔记——SpringBoot开发单体应用21
  • 给配置类加上注解: @EnableWebMvc

狂神说笔记——SpringBoot开发单体应用21
  • 发现所有的SpringMVC自动配置都失效了!回归到了最初的样子;
  • 所以,开发中不推荐使用全面接管SpringMVC。

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

  1. 可以发现它是导入了一个类,可以继续进去看:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}
  1. 它继承了一个父类 WebMvcConfigurationSupport
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
.......

}
  1. 来回顾一下Webmvc自动配置类:
@Configuration
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})

@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
    public static final String DEFAULT_PREFIX = "";
    public static final String DEFAULT_SUFFIX = "";
    private static final String[] SERVLET_LOCATIONS = new String[]{"/"};

    public WebMvcAutoConfiguration() {
    }
    ......

}
  • 总结一句话:@EnableWebMvc将WebMvcConfigurationSupport组件导入进来了;而导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能!
  • 这就是在SpringMVC上加了一层封装!

Original: https://www.cnblogs.com/gh110/p/15869244.html
Author: subeiLY
Title: 狂神说笔记——SpringBoot开发单体应用21

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/541888/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Jenkins 强制停止 job 执行

    0.背景 某天,Jenkins 运维支持群里,有同学反馈说,点击 job 页面的取消执行按钮不生效,job 执行停不下来。 收到这个反馈后,我自己也试了下,发现确实点页面取消按钮不…

    Java 2023年6月9日
    098
  • 程序人生|从网瘾少年到微软、BAT、字节offer收割机逆袭之路

    有情怀,有干货,微信搜索【 三太子敖丙】关注这个不一样的程序员。本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点、资料…

    Java 2023年6月9日
    087
  • 并发Map类删除数据的问题java.lang.UnsupportedOperationException: null

    笔者最近在开发Websocket相关的消息推送服务,使用了JSR356规范,由于需要维持会话。于是分别使用了以下类 笔者在维护失效的代码写了以下代码 最终在调用clients.re…

    Java 2023年5月29日
    070
  • springboot聚合项目搭建

    springboot聚合项目搭建 1、简介 1.1、什么是聚合项目? 一个项目中包含多个子项目的项目。 结构: `txt|- 父模块 Original: https://www.c…

    Java 2023年6月5日
    060
  • 枚举.Java学习

    今天复习一下Java里面的 枚举 。 枚举简介 使用enum关键字开发一个枚举类的时候,这个类会默认继承Enum系统类。而且是一个final类。 当多个枚举存在时候。需要逗号分隔,…

    Java 2023年6月9日
    052
  • MySQL基础(2)

    MySQL服务器支持SQL,因此,如何通过SQL告知MySQL服务器如何完成各种数据管理操作,就是重中之重。要想和服务器做好交流,则必须熟练掌握它。当使用某个程序(如mysql客户…

    Java 2023年6月5日
    073
  • 一次XGBoost性能优化-超线程影响运算速度

    一、问题背景 一个朋友在使用 XGBoost 框架进行机器学习编码,他们的一个demo, 在笔记本的虚拟机(4核)运行的时候,只要8s, 但是在一个64核128G 的物理机上面的虚…

    Java 2023年5月30日
    073
  • spring中的事件发布与监听

    点赞再看,养成习惯,微信搜索「 小大白日志」关注这个搬砖人。 文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。 spring事件发布与监听的应用场景 当处理完一段…

    Java 2023年6月8日
    055
  • 【万字图文-原创】 | 学会Java中的线程池,这一篇也许就够了!

    碎碎念 关于JDK源码相关的文章这已经是第四篇了,原创不易,粉丝从几十人到昨天的 666人,真的很感谢之前帮我转发文章的一些朋友们。 从16年开始写技术文章,到现在博客园已经发表了…

    Java 2023年5月29日
    085
  • Idea的Debug

    来自CSDN:https://blog.csdn.net/yxl_1207/article/details/80973622 Original: https://www.cnblo…

    Java 2023年6月8日
    058
  • quartz框架(七)-JobStore

    在之前的博文中,博主已经写了关于Job的相关内容。本篇博文,博主将介绍JobStore相关的内容。 JobStore是存放Job和Trigger的地方。当我们调用Scheduler…

    Java 2023年6月7日
    065
  • 分布式任务调度平台XXL-JOB安装及使用

    一、为什么需要任务调度平台 在Java中,传统的定时任务实现方案,比如Timer,Quartz等都或多或少存在一些问题: 不支持集群、不支持统计、没有管理平台、没有失败报警、没有监…

    Java 2023年6月5日
    075
  • 想入门数据结构,却总是拜倒在链表的石榴裙下?

    大家好,我是melo,一名大二上软件工程在读生,经历了一年的摸滚,现在已经在工作室里边准备开发后台项目啦不过这篇文章呢,还是想跟大家聊一聊数据结构与算法,学校也是大二上才开设了数据…

    Java 2023年6月5日
    087
  • 新蜂商城增强版来了,完善秒杀功能,添加秒杀单超期未支付任务,支持万人秒杀

    本项目是在newbee-mall项目的基础上改造而来,将orm层由mybatis替换为mybatis-plus,添加了秒杀功能、优惠劵功能以及后台搜索功能,喜欢的话麻烦给我个sta…

    Java 2023年6月14日
    081
  • [转]Spring源码解析之@Configuration

    Spring源码解析之@Configuration Original: https://www.cnblogs.com/gotodsp/p/15613221.htmlAuthor:…

    Java 2023年5月29日
    057
  • Oracle:10g(10.2.0.5):纯控制台console版本的dbca:不要java!

    不解释! 一切都在批处理代码中! 关键,挺简单的。 1 @echo off 2 3 %~d0 4 cd "%~dp0" 5 title "%~n0&q…

    Java 2023年5月29日
    075
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球