SpringBoot配置

常见应用程序属性

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的。

文件名必须为application,才会被SpringBoot所识别。

配置文件后缀有两种方式:

  1. properties

    key=value

  2. yaml,yml(详见/Java/Additional/YAML)

    key: value

两个配置文件可以共存。

1. 将配置文件中的对象注入实体类中

1.1. yaml

  1. 准备工作

    添加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    

    修改依赖

    <project>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-configuration-processor</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    
  2. 编写实体类

    package org.gs.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author admin
     * @date 9/24/21 5:42 PM
     */
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    // 需要注册为组件
    @Component
    // 指定配置文件中的字段
    @ConfigurationProperties(prefix = "person")
    public class Person {
        private String name;
        private Integer age;
        private Boolean adult;
        private Date birth;
        private Map<String, Object> maps;
        private List<String> lists;
    
        @Autowired
        private Dog dog;
    }
    
    package org.gs.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.stereotype.Component;
    
    /**
     * @author admin
     * @date 9/24/21 5:44 PM
     */
    @Component
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    public class Dog {
        private String name;
        private Integer age;
    }
    
  3. 配置文件中对对象赋值

    Person:
        name: zhangsan
        age: 18
        adult: true
        birth: 1999/06/18
        maps:
            k1: v1
            k2: v2
            k3: v3
        lists:
            - l1
            - l2
            - l3
        dog:
            name: wangcai
            age: 1
    
  4. 测试

    package org.gs;
    
    import org.gs.pojo.Person;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class MyspringbootApplicationTests {
        @Autowired
        private Person person;
    
        @Test
        void contextLoads() {
            System.out.println(person);
        }
    
    }
    

1.2. Properties

  1. 配置文件

    # 只能单个赋值
    name=zhangsan
    age=19
    adult=true
    birth=1999/06/18
    
  2. 实体类

    package org.gs.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.stereotype.Component;
    
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author admin
     * @date 9/24/21 5:42 PM
     */
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    @Component
    // 加载指定的配置文件
    @PropertySource(value = "classpath:person.properties")
    // 如果在Springboot的配置文件中,可以用 @ConfigurationProperties 从全局配置文件中获取值
    public class Person {
        // 使用SpEL表达式对属性进行单个赋值
        @Value("${name}")
        private String name;
        @Value("${age}")
        private Integer age;
        @Value("${adult}")
        private Boolean adult;
        @Value("${birth}")
        private Date birth;
    }
    
  3. 测试

    package org.gs;
    
    import org.gs.pojo.Person;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    @SpringBootTest
    class MyspringbootApplicationTests {
        @Autowired
        private Person person;
    
        @Test
        void contextLoads() {
            System.out.println(person);
        }
    
    }
    

YAML比较简单,开发中较常使用,也是SpringBoot官方推荐的。

2. SpringBoot中YAML和Properties对比

@ConfigurationProperties(YAML) @Value(Properties)
功能 批量注入配置文件中的属性 一个个指定
松散绑定 支持 不支持
SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持

松散绑定:yml中写的last-name,这个和lastName是一样的。

JSR303数据校验:可以在字段是增加一层过滤器验证 , 可以保证数据的合法性。

复杂类型封装,yml中可以封装对象 , 使用value就不支持。

Properties的短处

Properties配置文件在写中文的时候,会有乱码, 我们需要去IDEA中设置编码格式为UTF-8;settings-->FileEncodings 中配置。

@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加。

3. 在SpringBoot中使用JSR303校验

JSR303详见Java--->Additional--->JSR303

  1. 导入依赖

    在SpirngBoot中导入这个依赖,会自动导入文章开头的依赖,不需要手动导入。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    
  2. 添加校验

    package org.gs.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    import org.springframework.validation.annotation.Validated;
    
    import javax.validation.constraints.Email;
    
    /**
     * @author admin
     * @date 9/24/21 5:42 PM
     */
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    @Component
    // 开启校验
    @Validated
    public class Person {
        // 指定元素必须为Email格式,否则出错
        @Email
        private String name;
    }
    

4. 多环境切换

profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境。

4.1. 多配置文件properties

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties, 用来指定多个环境版本。

例如:

application-test.properties 代表测试环境配置

application-dev.properties 代表开发环境配置

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件。

我们需要通过一个配置来选择需要激活的环境:

#比如在配置文件中指定使用dev环境
spring.profiles.active=dev

4.2. 多文档块yaml

和properties配置文件中一样,但是使用yml去实现不需要创建多个配置文件,更加方便了 !

server:
  port: 8081
#选择要激活那个环境块
spring:
  profiles:
    active: test

---
server:
  port: 8082
spring:
  profiles: dev #配置环境的名称


---

server:
  port: 8083
spring:
  profiles: test  #配置环境的名称

注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件。

4.3. 配置文件读取的优先级问题

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:

优先级1:项目路径下的config文件夹配置文件 file:./config
优先级2:项目路径下配置文件    file:./
优先级3:资源路径下的config文件夹配置文件    classpath:/config/
优先级4:资源路径下配置文件    classpath:/

优先级由高到底,高优先级的配置会覆盖低优先级的配置;

SpringBoot会从这四个位置全部加载主配置文件,互补配置。

5. 指定位置加载配置文件

我们还可以通过spring.config.location来改变默认的配置文件位置

项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;

这种情况,一般是后期运维做的多,相同配置,外部指定的配置文件优先级最高

java -jar spring-boot-config.jar --spring.config.location=/Users/admin/application.properties

6. 配置内容

#配置项目的访问路径
server.servlet.context-path=/hello

7. 静态资源导入探究

WebMvcAutoConfiguration.java中

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();
    // 配置webjars
    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).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
    }
        // 默认静态资源的路径
    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).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
    }
  }
}

从源码中可以读出的信息:

  1. 静态资源路径若被自定义,则默认的路径会失效

  2. webjars的路径为/webjars/**

    webjars官网

    像是jquery、bootstrap、npm等依赖这这里可以通过Maven坐标导入,导入后会有jar包,包内的classpath:/META-INF/resources/webjars/就是资源目录,会被映射到/webjars/**,方便使用。

  3. 默认路径(常用)

    默认的路径在staticPathPattern中

    进入staticPathPattern,发现private String staticPathPattern = "/**";

    即映射的url路径为/**

    进入@EnableConfigurationProperties下的WebProperties.class,发现

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
                    "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
    

    这四个就是默认的静态资源路径。

    即:默认静态资源的url映射路径为/**

    在"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"四种路径下的资源均能被映射到。

    经测试,当静态资源文件发生重名时,会有优先级的问题。

    优先级:resources > static > public.

8. 首页和图标

8.1. 首页

WebMvcAutoConfiguration.java

private Optional<Resource> getWelcomePage() {
   String[] locations = 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。位置就是上面提到的静态资源的四个位置。

8.2. 图标

favicon在线生成

Springboot 对 favicon 配置在 2.2.0以上 和 2.2.0 之前的版本是不一样的。

  1. 在2.2.0之前

    只需要在 application.properties (或者 application.yaml) 中配置

    spring.mvc.favicon.enabled=false
    
  2. 在2.2.0之后

    不需要在 applicaiton.properties 文件中配置了而是在 html 中配置

    <link rel="icon" th:href="@{/public/favicon.ico}" type="image/x-icon"/>
    <link rel="bookmark" th:href="@{/public/favicon.ico}" type="image/x-icon"/>
    

9. MVC自动配置原理

对应的官方文档

自动配置在Spring的默认值之外添加了以下功能:

  • 包含ContentNegotiatingViewResolverBeanNameViewResolver豆。
  • 支持提供静态资源,包括对WebJars的支持。
  • 自动注册ConverterGenericConverterFormatter豆。
  • 支持HttpMessageConverters。SpringMVC用来转换Http请求和响应的的,比如我们要把一个User对象转换为JSON字符串。
  • 自动注册MessageCodesResolver。定义错误代码生成规则的。
  • Static index.html支持。
  • 自动使用ConfigurableWebBindingInitializer豆子。

如果您想保留这些Spring Boot MVC自定义,并进行更多的MVC自定义(拦截器、格式化程序、视图控制器和其他功能),您可以添加自己的@Configuration类类型为WebMvcConfigurer但没有@EnableWebMvc

如果您想提供RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver的自定义实例,但仍然保留Spring Boot MVC自定义,您可以声明类型WebMvcRegistrations的bean,并使用它来提供这些组件的自定义实例。

如果您想完全控制Spring MVC,您可以添加自己的@Configuration注释为@EnableWebMvc,或者按照Javadoc of@EnableWebMvc所述添加您自己的@Configuration-annotated DelegatingWebMvcConfiguration

它告诉我们SpringBoot已经帮我们自动配置好了SpringMVC,然后自动配置了哪些东西呢?

9.1. ContentNegotiatingViewResolver

内容协商视图解析器

public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean

这个类继承了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));
  // ContentNegotiatingViewResolver使用所有其他视图解析器来定位视图,因此它应该具有较高的优先级
  resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
  return resolver;
}

进入ContentNegotiatingViewResolver,可以找到对应的解析视图的源码

@Override
@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 = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
  if (requestedMediaTypes != null) {
    // 获取候选的视图对象
    List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
    // 选择一个最适合的视图对象,然后把这个对象返回
    View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
    if (bestView != null) {
      return bestView;
    }
  }

  String mediaTypeInfo = logger.isDebugEnabled() && requestedMediaTypes != null ?
    " given " + requestedMediaTypes.toString() : "";

  if (this.useNotAcceptableStatusCode) {
    if (logger.isDebugEnabled()) {
      logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo);
    }
    return NOT_ACCEPTABLE_VIEW;
  }
  else {
    logger.debug("View remains unresolved" + mediaTypeInfo);
    return null;
  }
}

getCandidateViews获取候选视图,进入看方法

private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes)
  throws Exception {

  List<View> candidateViews = new ArrayList<>();
  if (this.viewResolvers != null) {
    Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
    for (ViewResolver viewResolver : this.viewResolvers) {
      View view = viewResolver.resolveViewName(viewName, locale);
      if (view != null) {
        candidateViews.add(view);
      }
      for (MediaType requestedMediaType : requestedMediaTypes) {
        List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
        for (String extension : extensions) {
          String viewNameWithExtension = viewName + '.' + extension;
          view = viewResolver.resolveViewName(viewNameWithExtension, locale);
          if (view != null) {
            candidateViews.add(view);
          }
        }
      }
    }
  }
  if (!CollectionUtils.isEmpty(this.defaultViews)) {
    candidateViews.addAll(this.defaultViews);
  }
  return candidateViews;
}

其中,for (ViewResolver viewResolver : this.viewResolvers)中可以得知,获取候选视图的方法就是进行挨个判断。

所以得出结论:ContentNegotiatingViewResolver 这个视图解析器就是用来组合所有的视图解析器的

溯源,看ViewResolver是哪里赋值的

@Override
protected void initServletContext(ServletContext servletContext) {
  Collection<ViewResolver> matchingBeans =
    // 这里它是从beanFactory工具中获取容器中的所有视图解析器
    // ViewRescolver.class 把所有的视图解析器来组合的    
    BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), ViewResolver.class).values();
  if (this.viewResolvers == null) {
    this.viewResolvers = new ArrayList<>(matchingBeans.size());
    for (ViewResolver viewResolver : matchingBeans) {
      if (this != viewResolver) {
        this.viewResolvers.add(viewResolver);
      }
    }
  }
  else {
    for (int i = 0; i < this.viewResolvers.size(); i++) {
      ViewResolver vr = this.viewResolvers.get(i);
      if (matchingBeans.contains(vr)) {
        continue;
      }
      String name = vr.getClass().getName() + i;
      obtainApplicationContext().getAutowireCapableBeanFactory().initializeBean(vr, name);
    }

  }
  AnnotationAwareOrderComparator.sort(this.viewResolvers);
  this.cnmFactoryBean.setServletContext(servletContext);
}

得出,它是在容器中去找视图解析器。所以,我们可以在容器中自定义视图解析器。

9.2. 自定义视图解析器

这里按照官方文档说明来定义,详见上面的MVC自动配置原理。

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    // WebMvcConfigurer是一个实现了ViewResolver视图解析器接口的类,所以实际上也是一个视图解析器

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

    // 自定义了一个自己的视图解析器
    public static class MyViewResolver implements ViewResolver {

        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {

            return null;
        }
    }
}

在DispatcherServlet 中的 doDispatch方法,加断点进行调试,就可以看到this-->viewReslovers中出现自定义的视图解析器。

所以说,我们如果想要使用自己定制化的东西,我们只需要给容器中添加这个组件就好了。

10. 转换器和格式化器

  • WebMvcAutoConfiguration中找到格式化转换器:

    @Bean
    @Override
    public FormattingConversionService mvcConversionService() {
      // 从配置文件中取出格式化的规则
      Format format = this.mvcProperties.getFormat();
      WebConversionService conversionService = new WebConversionService(new DateTimeFormatters().dateFormat(format.getDate()).timeFormat(format.getTime()).dateTimeFormat(format.getDateTime()));
      addFormatters(conversionService);
      return conversionService;
    }
    
  • 进入mvcProperties,找到配置的源码

    public static class Format {
    
      /**
             * Date format to use, for example `dd/MM/yyyy`.
             */
      private String date;
    
      /**
             * Time format to use, for example `HH:mm:ss`.
             */
      private String time;
    
      /**
             * Date-time format to use, for example `yyyy-MM-dd HH:mm:ss`.
             */
      private String dateTime;
    
      // ...
    }
    
    @Deprecated
    @DeprecatedConfigurationProperty(replacement = "spring.mvc.format.date")
    public String getDateFormat() {
      return this.format.getDate();
    }
    

如果配置了自己的格式化方式,就会注册到Bean中生效,可以在配置文件中配置日期格式化的规则:

  • 2.2.x版本之前的

    配置文件

    # 配置文件
    spring.mvc.date-format=
    
  • 2.2.x版本之后的

    配置文件

    spring.mvc.date=
    

11. 修改SpringBoot的默认配置

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

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

  • 这里按照官方文档说明来定义,详见上面的MVC自动配置原理。

    扩展SpringMVC的方法:编写一个@Configuration注解类,并且类型要为WebMvcConfigurer,不能标注@EnableWebMvc注解

    MyMvcConfig

    @Configuration
    public class MyMvcConfig implements WebMvcConfigurer {
    
      @Override
      public void addViewControllers(ViewControllerRegistry registry) {
        // 浏览器发送/test , 就会跳转到test页面;
        registry.addViewController("/test2").setViewName("test");
      }
    }
    
  • 访问成功。表示扩展SpringMVC这么使用可以即保留自动配置的内容,也保留扩展配置的内容。

11.1. 能够扩展配置的原理

WebMvcAutoConfiguration 是 SpringMVC的自动配置类,里面有一个静态内部类WebMvcAutoConfigurationAdapter

@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class,
                                org.springframework.boot.autoconfigure.web.ResourceProperties.class, WebProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer

其中,这个类上有一个注解,在做其他自动配置时会导入

@Import(EnableWebMvcConfiguration.class)

而进入EnableWebMvcConfiguration

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebProperties.class)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware

可见EnableWebMvcConfiguration继承了DelegatingWebMvcConfiguration,在DelegatingWebMvcConfiguration中

@Configuration(proxyBeanMethods = false)
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);
        }
    }
  // ...
}

找到自定义的MyMvcConfig类重写的addViewControllers方法在DelegatingWebMvcConfiguration的源码,可以看到

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

再溯源,可以发现

@Override
public void addViewControllers(ViewControllerRegistry registry) {
  // 将所有的WebMvcConfigurer相关配置一起调用。包括我们自己配置的和Spring给我们配置的
  for (WebMvcConfigurer delegate : this.delegates) {
    delegate.addViewControllers(registry);
  }
}

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

11.2. 为什么不能加上@EnableWebMvc注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

这个注解实际上导入了DelegatingWebMvcConfiguration类,进入发现:

public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport

DelegatingWebMvcConfiguration是WebMvcConfigurationSupport的子类。

而,根据WebMvcAutoConfiguration自动配置类

@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)

即,当WebMvcConfigurationSupport类存在的时候,自动配置将失效。

如果加上@EnableWebMvc,意味着我们将全面接管Spring MVC,所有的东西需要自己配置。

12. 自定义拦截器

  1. 配置拦截器参见这里

  2. 将拦截器加入到mvc自定配置中

    MyMvcConfig类

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/asserts/**", "/user/login",
                                                                                                     "/index.html", "/");
    }
    

13. 自定义出错页

在templates目录下创建error目录,将HTTP常见状态码作为名字,创建网页文件就会自动识别。如404.html。

Copyright © rootwhois.cn 2021-2022 all right reserved,powered by GitbookFile Modify: 2023-03-05 10:55:52

results matching ""

    No results matching ""