zoukankan      html  css  js  c++  java
  • Springboot 2.x 欢迎页配置

    Springboot 2.x 对于欢迎页的配置都是由 WebMvcAutoConfiguration 这个类完成的,我们这里选取 Springboot-2.3.7.RELEASE 这个版本来探究一下 Springboot 底层对于欢迎页是如何定义的

    一、欢迎页配置原理

    在 WebMvcAutoConfiguration 配置类中有一个静态内部类 EnableWebMvcConfiguration ,由该类完成对 Springboot 欢迎页的配置

    // 1、标记该类是个配置类, proxyBeanMethods 默认值为 true , 由于组件之间没有依赖关系,为了加快 Spring 检索效率,设置其值为 false
    @Configuration(proxyBeanMethods = false)
    public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
    	// 成员变量
    	private final ResourceProperties resourceProperties;
    	private final WebMvcProperties mvcProperties;
    	private final ListableBeanFactory beanFactory;
    	private final WebMvcRegistrations mvcRegistrations;
    	private ResourceLoader resourceLoader;
    	
      // 2、这里有一个知识点,由于该类只有一个有参数的构造方法,所以构造方法中的参数值都是从 IOC 容器中获取的
    	public EnableWebMvcConfiguration(
    			// 2.1、与 ResourceProperties 进行配置绑定 ----> 详情见代码块一
    			ResourceProperties resourceProperties,
    			// 2.2、与 WebMvcProperties 进行配置绑定 ----> 详情见代码块二
    			ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
    			// 2.3、Web 模块注册的接口
    			ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, 
    			// 2.4、IOC 容器
    			ListableBeanFactory beanFactory) {
    		// 2.5、从 IOC 容器中获取到组件,并且将这些组件赋值给 EnableWebMvcConfiguration 的成员变量
    		this.resourceProperties = resourceProperties;
    		this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
    		this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
    		this.beanFactory = beanFactory;
    	}
    
    	// 3、向容器中注册欢迎页处理器映射组件
    	@Bean
    	public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
    			FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
    		// 3.1、获取欢迎页处理器映射 -----> 详情见代码块七
    		WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
    				new TemplateAvailabilityProviders(applicationContext), applicationContext, 
    				// 3.2、获取欢迎页面 ----> 详情见代码块三
    				getWelcomePage(),
    				// 3.3、获取静态资源前缀 ----> 详情见代码块六
    				this.mvcProperties.getStaticPathPattern());
    		// 3.4、设置拦截器
    		welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
    		// 3.5、设置 CorsConfiguration
    		welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
    		// 3.6、返回欢迎页处理器映射
    		return welcomePageHandlerMapping;
    	}
    
    	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");
    	}
    	
    	.......注册其它的一些组件
    }

    代码块一、与 ResourceProperties 进行配置绑定

    打开 ResourceProperties 这个类,该类的声明如下

    // 1、与 application.properties 配置文件中以 spring.resources 开头的配置项进行属性绑定
    @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
    public class ResourceProperties {
    	// 2、默认的静态资源路径
    	private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
    			"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
    
    	private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
    
    	 // 3、是否开启默认的静态资源配置
    	private boolean addMappings = true;
    
    	private final Chain chain = new Chain();
    
    	private final Cache cache = new Cache();
    
    	......
    }

    代码块二、与 WebMvcProperties 进行配置绑定

    打开 WebMvcProperties 这个类,该类的声明如下

    // 1、与 application.properties 配置文件中以 spring.mvc 开头的配置项进行属性绑定
    @ConfigurationProperties(prefix = "spring.mvc")
    public class WebMvcProperties {
    	/**
    	 * Formatting strategy for message codes. For instance, `PREFIX_ERROR_CODE`.
    	 */
    	private DefaultMessageCodesResolver.Format messageCodesResolverFormat;
    
    	/**
    	 * Locale to use. By default, this locale is overridden by the "Accept-Language"
    	 * header.
    	 */
    	private Locale locale;
    
    	......
    }

    代码块三、getWelcomePage():获取欢迎页面

    private Optional<Resource> getWelcomePage() {
    	// 1、this.resourceProperties.getStaticLocations():获取静态资源路径 ----> 详情见代码块四
    	// 2、getResourceLocations:获取最终的映射路径 ----> 详情见代码块五
    	String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
      // 3、通过筛选、过滤等操作,遍历上述所有的路径查看这些路径是否存在 index.html 页面,如果有则将该页面作为可选择的欢迎页面
    	return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
    }

    代码块四、this.resourceProperties.getStaticLocations()

    @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
    public class ResourceProperties {
    	// 1、Springboot 默认的静态资源路径
    	private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
    			"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
    
    	private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
    
    	public String[] getStaticLocations() {
    		return this.staticLocations;
    	}
    	
    	......
    }
    

    代码块五、getResourceLocations(...)

    static String[] getResourceLocations(String[] staticLocations) {
    	// 1、创建一个 String 类型的路径数组,其长度为静态资源路径长度 + 1
    	// staticLocations 为静态资源路径,SERVLET_LOCATIONS 为常量 / ,其长度为 1
    	String[] locations = new String[staticLocations.length + SERVLET_LOCATIONS.length];
    	// 2、将静态资源路径数组复制到新数组中
    	System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
    	// 3、将 SERVLET_LOCATIONS 复制到新数组中
    	System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length, SERVLET_LOCATIONS.length);
    	// 4、返回新的路径数组,该数组包含了 springboot 的静态资源路径和 /
    	return locations;
    }
    

    代码块六、this.mvcProperties.getStaticPathPattern()

    // 1、该配置类中的属性与 application.properties 中的 spring.mvc 开头的配置项动态绑定
    @ConfigurationProperties(prefix = "spring.mvc")
    public class WebMvcProperties {
    	// 2、staticPathPattern 默认值为 /** ,可以在配置 spring.mvc.static-path-pattern 来替换默认值 /**
    	private String staticPathPattern = "/**";
    
    	public String getStaticPathPattern() {
    		return this.staticPathPattern;
    	}
    
    	......
    }

    代码块七、new WelcomePageHandlerMapping(...)

    WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
    		ApplicationContext applicationContext, Optional<Resource> welcomePage, String staticPathPattern) {
    	
    	// 1、首先判断类路径和静态资源路径下是否存在 index.html 页面
    	// 代码块三 第 3 小点中,如果静态资源路径和类路径 / 下面有 index.html 页面,那么 welcomePage.isPresent() 为 true
    	// staticPathPattern 的值必须要为 /** ,如果我们改变了 staticPathPattern 的值,那么首页的配置将失效
    	if (welcomePage.isPresent() && "/**".equals(staticPathPattern)) {
    		logger.info("Adding welcome page: " + welcomePage.get());
    		setRootViewName("forward:index.html");
    	}
    	// 2、如果上述条件不成立,接着才从模板引擎下寻找是否存在 index.html 
    	// 例如 Springboot 推荐的 thymeleaf (即 resources/templates/ 文件夹下是否存在 index.html ,如果有就把其作为首页
    	else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
    		logger.info("Adding welcome page template: index");
    		setRootViewName("index");
    	}
    }
    

      

    二、总结

    1、默认情况下 Springboot 会去  /、 classpath:/META-INF/resources/、classpath:/resources/、classpath:/static/、classpath:/public/ 这五个路径下寻找是否存在 index.html ,如果存在就当其作为首页,

    2、如果 staticPathPattern 的值改变了,那么首页配置将失效(注意,如果你想使用 Springboot 的首页功能,就不要去配置文件中配置 spring.mvc.static-path-pattern 选项 )

    3、上述五个路径下如果找不到 index.html , Springboot 会尝试去模板引擎特定的文件夹下寻找 index.html ,如果存在就将其作为首页

    三、案例

    通过上面的分析,我们可以进行自定义静态资源的访问路径和首页的访问路径

    注意:如果我们修改了 Springboot 的配置文件 application.properties 中的配置项,那么 Springboot 的默认值就会被覆盖

    1、application.properties 不进行任何配置,全部使用 Springboot 默认的配置

    可以看到,只要你将 index.html 放置在 Springboot 的默认静态资源文件夹下, Springboot 就能够识别到 index.html ,并且将其作为首页

    2、修改 application.properties 中配置(修改了静态资源访问前缀、修改了默认的静态资源文件夹) 在 classpath:/static2/ 路径下放置 index.html

    # 给静态资源访问配置一个前缀 /bluefatty/ ,配置了该配置项之后,Springboot 默认的首页访问将失效
    spring.mvc.static-path-pattern=/bluefatty/**
    # 修改 Springboot 默认的静态资源文件夹,启用了该配置之后 Springboot 默认的静态资源文件夹将失效
    spring.resources.static-locations=classpath:/static2/,
                                      classpath:/public2/
    

    浏览器发起请求 http://localhost:8080/  访问 index.html ,则会出现如下报错

    为什么会出现这种原因呢? 因为我们在 application.properties 配置文件中修改了 staticPathPattern 的值,在不使用模板引擎的情况下 staticPathPattern 的值必须要为 /** (这个可以从代码块七中找到答案)否则就无法定位到静态资源文件夹下的 index.html 了

    3、自定义配置

    需求如下

    上述需求该如何实现呢? 我们可以分析一下

    通过 http://localhost:8080/ 能访问到首页,那么我们就不能改变 staticPathPattern 的值,因为改变了它的值之后代码七中的判断条件不成立,也就不能映射到静态资源文件夹下的 index.html,也就是我们就不能在 application.properties 中配置 spring.mvc.static-path-pattern 选项,因为在配置文件中配置的值会覆盖 Springboot 默认值

    通过 http://localhost:8080/banner/xiaomaomao.txt 能访问到资源,那么就需要保留 Springboot 默认的静态资源文件夹,也就是不能在 application.properties 中配置 spring.resources.static-locations ,因为配置了该选项之后,Springboot 默认的静态资源文件夹会被覆盖,从而失效

    通过 http://localhost:8080/slas/images/tiger.jpg 和 http://localhost:8080/slas/txt/Mango.txt 能够访问到对应的资源,我们可以考虑给其扩展额外的映射路径

    综上:我们不能在 application.properties 中配置 spring.mvc.static-path-pattern 和 spring.resources.static-locations ,并且需要额外扩展静态资源的映射路径

    那么只需要定义一个配置类

    @Configuration
    public class MyWebMvcConfigurerAdapter implements WebMvcConfigurer {
        @Override
    	// 添加静态资源映射路径,它不会改变 Springboot 默认的值它会和 Springboot 默认的 
    	// /** 映射 {classpath:/META-INF/resources/、classpath:/resources/、
    	// classpath:/static/、classpath:/public/}共同生效
        public void addResourceHandlers(ResourceHandlerRegistry registry){
            registry.addResourceHandler("/slas/**")
                    .addResourceLocations("classpath:slasResources/static/");
        }
    }
    

    测试都是生效的

    4、改变首页的路径

    需求如下

    需要在 application.properties 中配置 spring.resources.static-locations ,配置之后 Springboot 默认的静态资源文件夹就被 /slasResources/static/ 替代了

    # 修改 Springboot 默认的静态资源文件夹,启用了该配置之后 Springboot 默认的静态资源文件夹将失效
    spring.resources.static-locations=classpath:/slasResources/static/
    

    自定义配置类并注册组件

    @Configuration
    public class MyWebMvcConfigurerAdapter implements WebMvcConfigurer {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry){
            registry.addResourceHandler("/slas/**")
                    .addResourceLocations("classpath:/static/");
        }
    }
    

    测试如下

  • 相关阅读:
    python:窗口化和制作图形
    python:随机数 random
    python:数组/列表(remove()函数、append()函数、sort()函数、reverse()函数)
    python:一个轻松的递归逻辑
    python:while 语句的使用方法
    python:ord()和chr()——字符串和ASCll编码转换
    hive引擎的选择:tez和spark
    解决ideal使用maven打包OutOfMemory
    元数据 概念及分类
    hive on mr 参数设置
  • 原文地址:https://www.cnblogs.com/xiaomaomao/p/14283524.html
Copyright © 2011-2022 走看看