Spring

SpringBoot-Web自动配置

2019-07-13  本文已影响0人  elijah777

spring-boot-web

一、在项目中使用thymeleaf

spring-boot-starter-thymeleaf会自动包含spring-boot-starter-web

ThymeleafPropertiese类

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(
        prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;

    /**
     * 前缀设置,springboot默认是模板防止在classpath:/templates/下
     */
    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";
    /**
     * 模板的编码设置,默认是UTF_8
     */
    private Charset encoding;
    private boolean cache;
    private Integer templateResolverOrder;
    private String[] viewNames;
    private String[] excludedViewNames;
    private boolean enableSpringElCompiler;
    private boolean renderHiddenMarkersBeforeCheckboxes;
    private boolean enabled;
    static {
        DEFAULT_ENCODING = StandardCharsets.UTF_8;
    }

    //  .......
}


二、Web相关配置

spring-boot提供相关自动配置

源码查看WebMvcAutoConfiguration 和 WebMvcProperties 的源码

public class WebMvcAutoConfiguration {


 @Bean
        @ConditionalOnBean({ViewResolver.class})
        @ConditionalOnMissingBean(
            name = {"viewResolver"},
            value = {ContentNegotiatingViewResolver.class}
        )
        public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
            ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
            resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
            resolver.setOrder(-2147483648);
            return resolver;
        }
        
        
        @Bean
        @ConditionalOnBean({View.class})
        @ConditionalOnMissingBean
        public BeanNameViewResolver beanNameViewResolver() {
            BeanNameViewResolver resolver = new BeanNameViewResolver();
            resolver.setOrder(2147483637);
            return resolver;
        }
        
        
    }
1、自动配置的viewResolver
a)、ContentNegotiatingViewResolver

ContentNegotiatingViewResolver是spring提供的特殊ViewResolve,ContentNegotiatingViewResolver不是自己处理View,而是代理给不同的ViewResolve来处理不同的View,所以它有最高优先级

package org.springframework.web.servlet.view;

public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean {
    // .....
}
b)、BeanNameViewResolver

在控制器(@Controller)中的一个方法的返回值的字符串(视图名,return “index”;)会根据BeanNameViewResolve 去查找Bean的名称为返回字符串的View来渲染视图。

package org.springframework.web.servlet.view;

public class BeanNameViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered {
     // .....
}

定义BeanNameViewResolve的Bean:

@Bean
        @ConditionalOnBean({View.class})
        @ConditionalOnMissingBean
        public BeanNameViewResolver beanNameViewResolver() {
            BeanNameViewResolver resolver = new BeanNameViewResolver();
            resolver.setOrder(2147483637);
            return resolver;
        }
        

定义一个View的Bean,名称为jsonView:

@Bean
public MappingJackson2JsonView  JsonView() {
    MappingJackson2JsonView JsonView = new MappingJackson2JsonView();
    return JsonView;
}

在控制器中,返回值为字符串json,它会找bean的名称为jsonView的视图来渲染:

 @RequestMapping(value = "/json", produces = {MediaType.APPLICATION_JSON_VALUE})
    public String json(Model model) {
        Person person = new Person("aa", 11);
        model.addAttribute("single", person);
        return "jsonView";
    }
    
c)、InternalResourceViewResolver

这是极为常用的ViewResolve,主要通过设置前缀、后缀,以及控制器中方法来返回视图名的字符串,以得到实际页面:

 @Bean
        @ConditionalOnMissingBean
        public InternalResourceViewResolver defaultViewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix(this.mvcProperties.getView().getPrefix());
            resolver.setSuffix(this.mvcProperties.getView().getSuffix());
            return resolver;
        }
        
package org.springframework.web.servlet.view;

public class InternalResourceViewResolver extends UrlBasedViewResolver {}

2、自动配置的静态资源

在自动配置类的addResourceHandlers方法中定义了以下静态资源的自动配置。

WebMvcAutoConfiguration类中方法

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(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

            }
        }
        

类路径文件和webjars

3、自动配置的Formatter和Converter

关于自动配置Formatter和Converter,

WebMvcAutoConfiguration类中方法

public void addFormatters(FormatterRegistry registry) {
            Iterator var2 = this.getBeansOfType(Converter.class).iterator();

            while(var2.hasNext()) {
                Converter<?, ?> converter = (Converter)var2.next();
                registry.addConverter(converter);
            }

            var2 = this.getBeansOfType(GenericConverter.class).iterator();

            while(var2.hasNext()) {
                GenericConverter converter = (GenericConverter)var2.next();
                registry.addConverter(converter);
            }

            var2 = this.getBeansOfType(Formatter.class).iterator();

            while(var2.hasNext()) {
                Formatter<?> formatter = (Formatter)var2.next();
                registry.addFormatter(formatter);
            }

        }


可以看出定义了Converter、GenericConverter和Formatter接口实现类的Bean,这个Bean会自动注册到Spring MVC中。

4、自动配置的HttpMessageConverters

在WebMvcAutoConfiguration中注册了MessageConverters

 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            this.messageConvertersProvider.ifAvailable((customConverters) -> {
                converters.addAll(customConverters.getConverters());
            });
        }
        

如果要新增自定义的HttpMessageConverter,则只需定义一个HttpMessageConverter的Bean,然后在此Bean中注册自定义HttpMessageConvertter即可。

@Bean
publie HttpMessageConverter constomConverters() {
    HttpMessageConverter<?> constomConverter1 = new ConstomConverter1();
    HttpMessageConverter<?> constomConverter2 = new ConstomConverter2();
    return new HttpMessageConverters(constomConverter1, constomConverter2);
}

思考一下

对于Web在印象中的成长,从最初的Servlet、JSP,到Struts2,JSF和SpringMVC,每一次都是巨大的飞跃,记得上学期间用JSP写的项目,代码真是一摞摞的,写着写着自己都找不到了,后来用了SSH框架,立马不一样,代码看起来清晰一些了,但是配置文件对一些,自己还是菜菜的,写的也是很乱,用了SpringMVC的注解之后,感觉到编码很愉快,也很清晰,到目前的springboot,自动配置更是省下了很多配置,但底层的原理没有变,读读源码依旧是头蒙蒙的,不仅要学习新的技术,也不能忘记老的基础。

2019/07/13 上午于成都

上一篇 下一篇

猜你喜欢

热点阅读