1. 程式人生 > >Spring Boot 學習筆記(二)—— WEB相關配置

Spring Boot 學習筆記(二)—— WEB相關配置

一、前言

上次我們快速搭建了一個Spring Boot專案,我們只需新增業務邏輯就能直接執行訪問了,說明Spring Boot已經自動為我們做完了配置工作,這次我們就來看看具體是哪些工作,如果我們想接管配置又該怎麼做。

二、WEB相關配置

檢視WebMvcAutoConfigurationWebMvcProperties的原始碼,可以發現Spring MVC全域性配置以spring.mvc開頭,而Spring Boot提供瞭如下配置

1.自動配置的ViewResolver

1)ContentNegotiatingViewResolver

優先順序最高,自己不處理View,而是將View代理給其他ViewResolver處理

        @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 uses all the other view resolvers to locate // a view so it should have a high precedence
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE); return resolver; }

2)BeanNameViewResolver

根據Controller中方法的返回值來查詢ViewResolver處理View

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

3)InternalResourceViewResolver

這個很常見了,設定檢視路徑前後綴

        @Bean
        @ConditionalOnMissingBean
        public InternalResourceViewResolver defaultViewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix(this.mvcProperties.getView().getPrefix());
            resolver.setSuffix(this.mvcProperties.getView().getSuffix());
            return resolver;
        }

上篇文章我們添加了Thymeleaf,就自動為我們配置了前後綴。

2.自動配置的靜態資源

addResourceHandlers方法中可以看到有以下靜態資源的配置

@Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
                return;
            }
            Integer cachePeriod = this.resourceProperties.getCachePeriod();
            if (!registry.hasMappingForPattern("/webjars/**")) {
            //對映webjar路徑為 /webjars/**,可直接訪問,有關webjar的內容可訪問 www.webjars.org
                customizeResourceHandlerRegistration(
                        registry.addResourceHandler("/webjars/**")
                                .addResourceLocations(
                                        "classpath:/META-INF/resources/webjars/")
                        .setCachePeriod(cachePeriod));
            }
            String staticPathPattern = this.mvcProperties.getStaticPathPattern();
            if (!registry.hasMappingForPattern(staticPathPattern)) {
            //"classpath:/META-INF/resources/", "classpath:/resources/","classpath:/static/", "classpath:/public/",統統對映為 "/**",可以直接訪問
                customizeResourceHandlerRegistration(
                        registry.addResourceHandler(staticPathPattern)
                                .addResourceLocations(
                                        this.resourceProperties.getStaticLocations())
                        .setCachePeriod(cachePeriod));
            }
        }

3.自動配置Formatter和Converter

檢視Formatter配置原始碼

@Override
        public void addFormatters(FormatterRegistry registry) {
            for (Converter<?, ?> converter : getBeansOfType(Converter.class)) {
                registry.addConverter(converter);
            }
            for (GenericConverter converter : getBeansOfType(GenericConverter.class)) {
                registry.addConverter(converter);
            }
            for (Formatter<?> formatter : getBeansOfType(Formatter.class)) {
                registry.addFormatter(formatter);
            }
        }

可以看到只要我們定義了ConverterGenericConverterFormatter實現類的Bean,就會自動註冊到Spring MVC中。

4.自動配置的HttpMessageConverter

        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            converters.addAll(this.messageConverters.getConverters());
        }

除了預設的StringHttpMessageConverterByteArrayHttpMessageConverter等,Spring MVC預設使用MappingJackson2HttpMessageConverterMappingJackson2XmlHttpMessageConverter,如果要新增自定義的HttpMessageConverter,只需定義一個HttpMessageConverters的bean即可

5.靜態首頁支援

private WelcomePageHandlerMapping(Resource welcomePage,
                String staticPathPattern) {
            if (welcomePage != null && "/**".equals(staticPathPattern)) {
                logger.info("Adding welcome page: " + welcomePage);
                ParameterizableViewController controller = new ParameterizableViewController();
                controller.setViewName("forward:index.html");
                setRootHandler(controller);
                setOrder(0);
            }
        }

在以下目錄放置index.html會自動設為首頁

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/

三、接管Spring Boot的WEB配置

如果要完全接管Web配置,只需新建一個配置類(註解@Configuration @EnableWebMvc),然後就能實現自己完全控制的Spring MVC。如果要保留自動配置並新增額外配置的話也很簡單,定義一個配置類(註解@Configuration不需要 @EnableWebMvc)繼承WebMvcConfigurerAdapter,就能在保留自動配置的基礎上新增自己想要的配置了,以下是個小例子

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //此方法不會覆蓋自動配置,而是額外新增
        registry.addViewController("/login").setViewName("/login");
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //配置fastjson替換jackson
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter ();
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
        stringConverter.setDefaultCharset(Charset.forName("UTF-8"));
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.PrettyFormat,
                                    SerializerFeature.DisableCircularReferenceDetect);
        converter.setFastJsonConfig(config);
        //新增字串解析器,防止返回字串時多出雙引號
        converters.add(stringConverter);
        converters.add(converter);
    }

}

四、註冊Servlet、Filter、Listener

ServletFilterListener宣告為Bean,或者註冊ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean 的Bean

    //直接註冊Bean
    @Bean
    public XxServlet xxServlet(){
        return new XxServlet();
    }
    @Bean
    public XxServlet xxServlet(){
        return new XxServlet();
    }
    @Bean
    public XxFilter xxFilter(){
        return new XxFilter();
    }
    //通過RegistrationBean註冊
    @Bean
    public ServletRegistrationBean servletRegistrationBean(){
        return new ServletRegistrationBean(new XxServlet(),"/xx/*");    
    }
    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new YyFilter()); 
        registrationBean.setOrder(2);
        return registrationBean;
    }
    @Bean
    public ServletListenerRegistrationBean<ZzListener> zzListenerServletRegistrationBean(){
        return new ServletListenerRegistrationBean<ZzListener>(new ZzListener());   
    }   

五、總結

本文介紹了Spring Boot關於Spring MVC的自動配置項,這樣我們在開發時也能根據業務需要手動修改配置,以實現我們想要的功能。
參考文獻:
《javaee開發的顛覆者 Spring Boot實戰》