springboot的Web开发-Web相关配置

一:Spring Boot提供自动配置

       通过查看WebMvcAutoConfiguration及WebMvcProperties的源码,可以发现Spring Boot为我们提供了如下的自动配置。

 1,自动配置的ViewResolver

1)ContentNegotiatingViewResolver

    这是Spring MVC提供的一个特殊的ViewResolver,ContentNegotiatingViewResolver不是自己处理View,而是代理给不同的ViewResolver来处理不同的View,所以它有最高的优先级。

2)BeanNameViewResolver

    在控制器(@Controller)中的一个方法的返回值的字符串(视图名)会根据 BeanNameViewResolver去查找Bean的名称为返回字符串的View来渲染视图,下面举个例子

     定义BeanNameViewResolver的Bean

@Bean  
 public BeanNameViewResolver beanNameViewResolver(){  
        BeanNameViewResolver resolver= new BeanNameViewResolver();  
 return resolver  
    }  

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

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

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

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

3)InternalResourceViewResolver

    这是一个常用的ViewResolver,主要通过设置前缀,后缀,以及控制器中方法来返回视图名的字符串,以得到实际页面,Spring Boot的源码如下:

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

下面是WebMvcAutoConfiguration的源代码:

//  
// Source code recreated from a .class file by IntelliJ IDEA  
// (powered by Fernflower decompiler)  
//  
 
package org.springframework.boot.autoconfigure.web;  
 
import java.util.Collection;  
import java.util.Collections;  
import java.util.Date;  
import java.util.Iterator;  
import java.util.List;  
import java.util.ListIterator;  
import java.util.Map;  
import java.util.Map.Entry;  
import javax.servlet.Servlet;  
import javax.servlet.http.HttpServletRequest;  
import org.apache.commons.logging.Log;  
import org.apache.commons.logging.LogFactory;  
import org.springframework.beans.factory.BeanFactory;  
import org.springframework.beans.factory.ListableBeanFactory;  
import org.springframework.beans.factory.NoSuchBeanDefinitionException;  
import org.springframework.beans.factory.ObjectProvider;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.autoconfigure.AutoConfigureAfter;  
import org.springframework.boot.autoconfigure.AutoConfigureOrder;  
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;  
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;  
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;  
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;  
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;  
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;  
import org.springframework.boot.autoconfigure.web.ResourceProperties.Chain;  
import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy;  
import org.springframework.boot.context.properties.EnableConfigurationProperties;  
import org.springframework.boot.web.filter.OrderedHiddenHttpMethodFilter;  
import org.springframework.boot.web.filter.OrderedHttpPutFormContentFilter;  
import org.springframework.boot.web.filter.OrderedRequestContextFilter;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.context.annotation.Import;  
import org.springframework.context.annotation.Lazy;  
import org.springframework.context.annotation.Primary;  
import org.springframework.core.convert.converter.Converter;  
import org.springframework.core.convert.converter.GenericConverter;  
import org.springframework.core.io.Resource;  
import org.springframework.format.Formatter;  
import org.springframework.format.FormatterRegistry;  
import org.springframework.format.datetime.DateFormatter;  
import org.springframework.http.MediaType;  
import org.springframework.http.converter.HttpMessageConverter;  
import org.springframework.util.ClassUtils;  
import org.springframework.util.StringUtils;  
import org.springframework.validation.DefaultMessageCodesResolver;  
import org.springframework.validation.MessageCodesResolver;  
import org.springframework.validation.Validator;  
import org.springframework.web.HttpMediaTypeNotAcceptableException;  
import org.springframework.web.accept.ContentNegotiationManager;  
import org.springframework.web.accept.ContentNegotiationStrategy;  
import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;  
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;  
import org.springframework.web.context.request.NativeWebRequest;  
import org.springframework.web.context.request.RequestContextListener;  
import org.springframework.web.filter.HiddenHttpMethodFilter;  
import org.springframework.web.filter.HttpPutFormContentFilter;  
import org.springframework.web.filter.RequestContextFilter;  
import org.springframework.web.servlet.DispatcherServlet;  
import org.springframework.web.servlet.HandlerExceptionResolver;  
import org.springframework.web.servlet.LocaleResolver;  
import org.springframework.web.servlet.View;  
import org.springframework.web.servlet.ViewResolver;  
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;  
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;  
import org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration;  
import org.springframework.web.servlet.config.annotation.ResourceChainRegistration;  
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;  
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;  
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;  
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;  
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;  
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;  
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;  
import org.springframework.web.servlet.i18n.FixedLocaleResolver;  
import org.springframework.web.servlet.mvc.ParameterizableViewController;  
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;  
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;  
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;  
import org.springframework.web.servlet.resource.AppCacheManifestTransformer;  
import org.springframework.web.servlet.resource.GzipResourceResolver;  
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;  
import org.springframework.web.servlet.resource.ResourceResolver;  
import org.springframework.web.servlet.resource.VersionResourceResolver;  
import org.springframework.web.servlet.view.BeanNameViewResolver;  
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;  
import org.springframework.web.servlet.view.InternalResourceViewResolver;  
 
@Configuration  
@ConditionalOnWebApplication  
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class})  
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})  
@AutoConfigureOrder(-2147483638)  
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})  
public class WebMvcAutoConfiguration {  
 public static final String DEFAULT_PREFIX = "";  
 public static final String DEFAULT_SUFFIX = "";  
 
 public WebMvcAutoConfiguration() {  
    }  
 
 @Bean  
 @ConditionalOnMissingBean({HiddenHttpMethodFilter.class})  
 public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {  
 return new OrderedHiddenHttpMethodFilter();  
    }  
 
 @Bean  
 @ConditionalOnMissingBean({HttpPutFormContentFilter.class})  
 @ConditionalOnProperty(  
        prefix = "spring.mvc.formcontent.putfilter",  
        name = {"enabled"},  
        matchIfMissing = true  
    )  
 public OrderedHttpPutFormContentFilter httpPutFormContentFilter() {  
 return new OrderedHttpPutFormContentFilter();  
    }  
 
 static class OptionalPathExtensionContentNegotiationStrategy implements ContentNegotiationStrategy {  
 private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class.getName() + ".SKIP";  
 private final ContentNegotiationStrategy delegate;  
 
        OptionalPathExtensionContentNegotiationStrategy(ContentNegotiationStrategy delegate) {  
 this.delegate = delegate;  
        }  
 
 public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {  
            Object skip = webRequest.getAttribute(SKIP_ATTRIBUTE, 0);  
 return skip != null && Boolean.parseBoolean(skip.toString()) ? Collections.emptyList() : this.delegate.resolveMediaTypes(webRequest);  
        }  
    }  
 
 static final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {  
 private static final Log logger = LogFactory.getLog(WebMvcAutoConfiguration.WelcomePageHandlerMapping.class);  
 
 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");  
 this.setRootHandler(controller);  
 this.setOrder(0);  
            }  
 
        }  
 
 public Object getHandlerInternal(HttpServletRequest request) throws Exception {  
            Iterator var2 = this.getAcceptedMediaTypes(request).iterator();  
 
            MediaType mediaType;  
 do {  
 if (!var2.hasNext()) {  
 return null;  
                }  
 
                mediaType = (MediaType)var2.next();  
            } while(!mediaType.includes(MediaType.TEXT_HTML));  
 
 return super.getHandlerInternal(request);  
        }  
 
 private List<MediaType> getAcceptedMediaTypes(HttpServletRequest request) {  
            String acceptHeader = request.getHeader("Accept");  
 return MediaType.parseMediaTypes(StringUtils.hasText(acceptHeader) ? acceptHeader : "*/*");  
        }  
    }  
 
 private static class ResourceChainResourceHandlerRegistrationCustomizer implements WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer {  
 @Autowired  
 private ResourceProperties resourceProperties;  
 
 private ResourceChainResourceHandlerRegistrationCustomizer() {  
 this.resourceProperties = new ResourceProperties();  
        }  
 
 public void customize(ResourceHandlerRegistration registration) {  
            Chain properties = this.resourceProperties.getChain();  
 this.configureResourceChain(properties, registration.resourceChain(properties.isCache()));  
        }  
 
 private void configureResourceChain(Chain properties, ResourceChainRegistration chain) {  
            Strategy strategy = properties.getStrategy();  
 if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {  
                chain.addResolver(this.getVersionResourceResolver(strategy));  
            }  
 
 if (properties.isGzipped()) {  
                chain.addResolver(new GzipResourceResolver());  
            }  
 
 if (properties.isHtmlApplicationCache()) {  
                chain.addTransformer(new AppCacheManifestTransformer());  
            }  
 
        }  
 
 private ResourceResolver getVersionResourceResolver(Strategy properties) {  
            VersionResourceResolver resolver = new VersionResourceResolver();  
 if (properties.getFixed().isEnabled()) {  
                String version = properties.getFixed().getVersion();  
                String[] paths = properties.getFixed().getPaths();  
                resolver.addFixedVersionStrategy(version, paths);  
            }  
 
 if (properties.getContent().isEnabled()) {  
                String[] paths = properties.getContent().getPaths();  
                resolver.addContentVersionStrategy(paths);  
            }  
 
 return resolver;  
        }  
    }  
 
 interface ResourceHandlerRegistrationCustomizer {  
 void customize(ResourceHandlerRegistration var1);  
    }  
 
 @Configuration  
 @ConditionalOnEnabledResourceChain  
 static class ResourceChainCustomizerConfiguration {  
        ResourceChainCustomizerConfiguration() {  
        }  
 
 @Bean  
 public WebMvcAutoConfiguration.ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {  
 return new WebMvcAutoConfiguration.ResourceChainResourceHandlerRegistrationCustomizer();  
        }  
    }  
 
 @Configuration  
 public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {  
 private final WebMvcProperties mvcProperties;  
 private final ListableBeanFactory beanFactory;  
 private final WebMvcRegistrations mvcRegistrations;  
 
 public EnableWebMvcConfiguration(ObjectProvider<WebMvcProperties> mvcPropertiesProvider, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {  
 this.mvcProperties = (WebMvcProperties)mvcPropertiesProvider.getIfAvailable();  
 this.mvcRegistrations = (WebMvcRegistrations)mvcRegistrationsProvider.getIfUnique();  
 this.beanFactory = beanFactory;  
        }  
 
 @Bean  
 public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {  
            RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();  
            adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null ? true : this.mvcProperties.isIgnoreDefaultModelOnRedirect());  
 return adapter;  
        }  
 
 protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {  
 return this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerAdapter() != null ? this.mvcRegistrations.getRequestMappingHandlerAdapter() : super.createRequestMappingHandlerAdapter();  
        }  
 
 @Bean  
 @Primary  
 public RequestMappingHandlerMapping requestMappingHandlerMapping() {  
 return super.requestMappingHandlerMapping();  
        }  
 
 @Bean  
 public Validator mvcValidator() {  
 return !ClassUtils.isPresent("javax.validation.Validator", this.getClass().getClassLoader()) ? super.mvcValidator() : WebMvcValidator.get(this.getApplicationContext(), this.getValidator());  
        }  
 
 protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {  
 return this.mvcRegistrations != null && this.mvcRegistrations.getRequestMappingHandlerMapping() != null ? this.mvcRegistrations.getRequestMappingHandlerMapping() : super.createRequestMappingHandlerMapping();  
        }  
 
 protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {  
 try {  
 return (ConfigurableWebBindingInitializer)this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);  
            } catch (NoSuchBeanDefinitionException var2) {  
 return super.getConfigurableWebBindingInitializer();  
            }  
        }  
 
 protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {  
 return this.mvcRegistrations != null && this.mvcRegistrations.getExceptionHandlerExceptionResolver() != null ? this.mvcRegistrations.getExceptionHandlerExceptionResolver() : super.createExceptionHandlerExceptionResolver();  
        }  
 
 protected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {  
 super.configureHandlerExceptionResolvers(exceptionResolvers);  
 if (exceptionResolvers.isEmpty()) {  
 this.addDefaultHandlerExceptionResolvers(exceptionResolvers);  
            }  
 
 if (this.mvcProperties.isLogResolvedException()) {  
                Iterator var2 = exceptionResolvers.iterator();  
 
 while(var2.hasNext()) {  
                    HandlerExceptionResolver resolver = (HandlerExceptionResolver)var2.next();  
 if (resolver instanceof AbstractHandlerExceptionResolver) {  
                        ((AbstractHandlerExceptionResolver)resolver).setWarnLogCategory(resolver.getClass().getName());  
                    }  
                }  
            }  
 
        }  
 
 @Bean  
 public ContentNegotiationManager mvcContentNegotiationManager() {  
            ContentNegotiationManager manager = super.mvcContentNegotiationManager();  
            List<ContentNegotiationStrategy> strategies = manager.getStrategies();  
            ListIterator iterator = strategies.listIterator();  
 
 while(iterator.hasNext()) {  
                ContentNegotiationStrategy strategy = (ContentNegotiationStrategy)iterator.next();  
 if (strategy instanceof PathExtensionContentNegotiationStrategy) {  
                    iterator.set(new WebMvcAutoConfiguration.OptionalPathExtensionContentNegotiationStrategy(strategy));  
                }  
            }  
 
 return manager;  
        }  
    }  
 
 @Configuration  
 @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})  
 @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})  
 public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {  
 private static final Log logger = LogFactory.getLog(WebMvcConfigurerAdapter.class);  
 private final ResourceProperties resourceProperties;  
 private final WebMvcProperties mvcProperties;  
 private final ListableBeanFactory beanFactory;  
 private final HttpMessageConverters messageConverters;  
 final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;  
 
 public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, @Lazy HttpMessageConverters messageConverters, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {  
 this.resourceProperties = resourceProperties;  
 this.mvcProperties = mvcProperties;  
 this.beanFactory = beanFactory;  
 this.messageConverters = messageConverters;  
 this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();  
        }  
 
 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {  
            converters.addAll(this.messageConverters.getConverters());  
        }  
 
 public void configureAsyncSupport(AsyncSupportConfigurer configurer) {  
            Long timeout = this.mvcProperties.getAsync().getRequestTimeout();  
 if (timeout != null) {  
                configurer.setDefaultTimeout(timeout.longValue());  
            }  
 
        }  
 
 public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {  
            Map<String, MediaType> mediaTypes = this.mvcProperties.getMediaTypes();  
            Iterator var3 = mediaTypes.entrySet().iterator();  
 
 while(var3.hasNext()) {  
                Entry<String, MediaType> mediaType = (Entry)var3.next();  
                configurer.mediaType((String)mediaType.getKey(), (MediaType)mediaType.getValue());  
            }  
 
        }  
 
 @Bean  
 @ConditionalOnMissingBean  
 public InternalResourceViewResolver defaultViewResolver() {  
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();  
            resolver.setPrefix(this.mvcProperties.getView().getPrefix());  
            resolver.setSuffix(this.mvcProperties.getView().getSuffix());  
 return resolver;  
        }  
 
 @Bean  
 @ConditionalOnBean({View.class})  
 @ConditionalOnMissingBean  
 public BeanNameViewResolver beanNameViewResolver() {  
            BeanNameViewResolver resolver = new BeanNameViewResolver();  
            resolver.setOrder(2147483637);  
 return resolver;  
        }  
 
 @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  
 @ConditionalOnMissingBean  
 @ConditionalOnProperty(  
            prefix = "spring.mvc",  
            name = {"locale"}  
        )  
 public LocaleResolver localeResolver() {  
 if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.WebMvcProperties.LocaleResolver.FIXED) {  
 return new FixedLocaleResolver(this.mvcProperties.getLocale());  
            } else {  
                AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();  
                localeResolver.setDefaultLocale(this.mvcProperties.getLocale());  
 return localeResolver;  
            }  
        }  
 
 @Bean  
 @ConditionalOnProperty(  
            prefix = "spring.mvc",  
            name = {"date-format"}  
        )  
 public Formatter<Date> dateFormatter() {  
 return new DateFormatter(this.mvcProperties.getDateFormat());  
        }  
 
 public MessageCodesResolver getMessageCodesResolver() {  
 if (this.mvcProperties.getMessageCodesResolverFormat() != null) {  
                DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();  
                resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());  
 return resolver;  
            } else {  
 return null;  
            }  
        }  
 
 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);  
            }  
 
        }  
 
 private <T> Collection<T> getBeansOfType(Class<T> type) {  
 return this.beanFactory.getBeansOfType(type).values();  
        }  
 
 public void addResourceHandlers(ResourceHandlerRegistry registry) {  
 if (!this.resourceProperties.isAddMappings()) {  
                logger.debug("Default resource handling disabled");  
            } else {  
                Integer cachePeriod = this.resourceProperties.getCachePeriod();  
 if (!registry.hasMappingForPattern("/webjars/**")) {  
 this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(cachePeriod));  
                }  
 
                String staticPathPattern = this.mvcProperties.getStaticPathPattern();  
 if (!registry.hasMappingForPattern(staticPathPattern)) {  
 this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));  
                }  
 
            }  
        }  
 
 @Bean  
 public WebMvcAutoConfiguration.WelcomePageHandlerMapping welcomePageHandlerMapping(ResourceProperties resourceProperties) {  
 return new WebMvcAutoConfiguration.WelcomePageHandlerMapping(resourceProperties.getWelcomePage(), this.mvcProperties.getStaticPathPattern());  
        }  
 
 private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {  
 if (this.resourceHandlerRegistrationCustomizer != null) {  
 this.resourceHandlerRegistrationCustomizer.customize(registration);  
            }  
 
        }  
 
 @Bean  
 @ConditionalOnMissingBean({RequestContextListener.class, RequestContextFilter.class})  
 public static RequestContextFilter requestContextFilter() {  
 return new OrderedRequestContextFilter();  
        }  
 
 @Configuration  
 @ConditionalOnProperty(  
            value = {"spring.mvc.favicon.enabled"},  
            matchIfMissing = true  
        )  
 public static class FaviconConfiguration {  
 private final ResourceProperties resourceProperties;  
 
 public FaviconConfiguration(ResourceProperties resourceProperties) {  
 this.resourceProperties = resourceProperties;  
            }  
 
 @Bean  
 public SimpleUrlHandlerMapping faviconHandlerMapping() {  
                SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();  
                mapping.setOrder(-2147483647);  
                mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", this.faviconRequestHandler()));  
 return mapping;  
            }  
 
 @Bean  
 public ResourceHttpRequestHandler faviconRequestHandler() {  
                ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();  
                requestHandler.setLocations(this.resourceProperties.getFaviconLocations());  
 return requestHandler;  
            }  
        }  
    }  
}  

WebMvcProperties的源码如下:

//  
// Source code recreated from a .class file by IntelliJ IDEA  
// (powered by Fernflower decompiler)  
//  
 
package org.springframework.boot.autoconfigure.web;  
 
import java.util.LinkedHashMap;  
import java.util.Locale;  
import java.util.Map;  
import org.springframework.boot.context.properties.ConfigurationProperties;  
import org.springframework.http.MediaType;  
import org.springframework.validation.DefaultMessageCodesResolver.Format;  
 
@ConfigurationProperties(  
    prefix = "spring.mvc"  
)  
public class WebMvcProperties {  
 private Format messageCodesResolverFormat;  
 private Locale locale;  
 private WebMvcProperties.LocaleResolver localeResolver;  
 private String dateFormat;  
 private boolean dispatchTraceRequest;  
 private boolean dispatchOptionsRequest;  
 private boolean ignoreDefaultModelOnRedirect;  
 private boolean throwExceptionIfNoHandlerFound;  
 private boolean logResolvedException;  
 private Map<String, MediaType> mediaTypes;  
 private String staticPathPattern;  
 private final WebMvcProperties.Async async;  
 private final WebMvcProperties.Servlet servlet;  
 private final WebMvcProperties.View view;  
 
 public WebMvcProperties() {  
 this.localeResolver = WebMvcProperties.LocaleResolver.ACCEPT_HEADER;  
 this.dispatchTraceRequest = false;  
 this.dispatchOptionsRequest = true;  
 this.ignoreDefaultModelOnRedirect = true;  
 this.throwExceptionIfNoHandlerFound = false;  
 this.logResolvedException = false;  
 this.mediaTypes = new LinkedHashMap();  
 this.staticPathPattern = "/**";  
 this.async = new WebMvcProperties.Async();  
 this.servlet = new WebMvcProperties.Servlet();  
 this.view = new WebMvcProperties.View();  
    }  
 
 public Format getMessageCodesResolverFormat() {  
 return this.messageCodesResolverFormat;  
    }  
 
 public void setMessageCodesResolverFormat(Format messageCodesResolverFormat) {  
 this.messageCodesResolverFormat = messageCodesResolverFormat;  
    }  
 
 public Locale getLocale() {  
 return this.locale;  
    }  
 
 public void setLocale(Locale locale) {  
 this.locale = locale;  
    }  
 
 public WebMvcProperties.LocaleResolver getLocaleResolver() {  
 return this.localeResolver;  
    }  
 
 public void setLocaleResolver(WebMvcProperties.LocaleResolver localeResolver) {  
 this.localeResolver = localeResolver;  
    }  
 
 public String getDateFormat() {  
 return this.dateFormat;  
    }  
 
 public void setDateFormat(String dateFormat) {  
 this.dateFormat = dateFormat;  
    }  
 
 public boolean isIgnoreDefaultModelOnRedirect() {  
 return this.ignoreDefaultModelOnRedirect;  
    }  
 
 public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) {  
 this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;  
    }  
 
 public boolean isThrowExceptionIfNoHandlerFound() {  
 return this.throwExceptionIfNoHandlerFound;  
    }  
 
 public void setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound) {  
 this.throwExceptionIfNoHandlerFound = throwExceptionIfNoHandlerFound;  
    }  
 
 public boolean isLogResolvedException() {  
 return this.logResolvedException;  
    }  
 
 public void setLogResolvedException(boolean logResolvedException) {  
 this.logResolvedException = logResolvedException;  
    }  
 
 public Map<String, MediaType> getMediaTypes() {  
 return this.mediaTypes;  
    }  
 
 public void setMediaTypes(Map<String, MediaType> mediaTypes) {  
 this.mediaTypes = mediaTypes;  
    }  
 
 public boolean isDispatchOptionsRequest() {  
 return this.dispatchOptionsRequest;  
    }  
 
 public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) {  
 this.dispatchOptionsRequest = dispatchOptionsRequest;  
    }  
 
 public boolean isDispatchTraceRequest() {  
 return this.dispatchTraceRequest;  
    }  
 
 public void setDispatchTraceRequest(boolean dispatchTraceRequest) {  
 this.dispatchTraceRequest = dispatchTraceRequest;  
    }  
 
 public String getStaticPathPattern() {  
 return this.staticPathPattern;  
    }  
 
 public void setStaticPathPattern(String staticPathPattern) {  
 this.staticPathPattern = staticPathPattern;  
    }  
 
 public WebMvcProperties.Async getAsync() {  
 return this.async;  
    }  
 
 public WebMvcProperties.Servlet getServlet() {  
 return this.servlet;  
    }  
 
 public WebMvcProperties.View getView() {  
 return this.view;  
    }  
 
 public static enum LocaleResolver {  
        FIXED,  
        ACCEPT_HEADER;  
 
 private LocaleResolver() {  
        }  
    }  
 
 public static class View {  
 private String prefix;  
 private String suffix;  
 
 public View() {  
        }  
 
 public String getPrefix() {  
 return this.prefix;  
        }  
 
 public void setPrefix(String prefix) {  
 this.prefix = prefix;  
        }  
 
 public String getSuffix() {  
 return this.suffix;  
        }  
 
 public void setSuffix(String suffix) {  
 this.suffix = suffix;  
        }  
    }  
 
 public static class Servlet {  
 private int loadOnStartup = -1;  
 
 public Servlet() {  
        }  
 
 public int getLoadOnStartup() {  
 return this.loadOnStartup;  
        }  
 
 public void setLoadOnStartup(int loadOnStartup) {  
 this.loadOnStartup = loadOnStartup;  
        }  
    }  
 
 public static class Async {  
 private Long requestTimeout;  
 
 public Async() {  
        }  
 
 public Long getRequestTimeout() {  
 return this.requestTimeout;  
        }  
 
 public void setRequestTimeout(Long requestTimeout) {  
 this.requestTimeout = requestTimeout;  
        }  
    }  
}  

2,自动配置的静态资源

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

1)类路径文件

    把类路径下的/static,/public,/resources和/META-INF/resources文件夹下的静态文件直接映射为/**,可以通过http://localhost:8080/**来访问。

2)webjar

        何谓webjar,webjar就是将是我们常用的脚本框架封装在jar包中的jar包,更多关于webjar的内容请访问http://www.webjars.org网站

    把webjar的/META-INF/resources/webjars/下的静态文件映射为/webjar/**,可以通过http://localhost:8080/webjar/**来访问

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,代码如下:

@Configuration  
 @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})  
 @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})  
 public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {  
 private static final Log logger = LogFactory.getLog(WebMvcConfigurerAdapter.class);  
 private final ResourceProperties resourceProperties;  
 private final WebMvcProperties mvcProperties;  
 private final ListableBeanFactory beanFactory;  
 private final HttpMessageConverters messageConverters;  
 final WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;  
 
 public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, @Lazy HttpMessageConverters messageConverters, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {  
 this.resourceProperties = resourceProperties;  
 this.mvcProperties = mvcProperties;  
 this.beanFactory = beanFactory;  
 this.messageConverters = messageConverters;  
 this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();  
        }  
 
 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {  
            converters.addAll(this.messageConverters.getConverters());  
        }  
 
 public void configureAsyncSupport(AsyncSupportConfigurer configurer) {  
            Long timeout = this.mvcProperties.getAsync().getRequestTimeout();  
 if (timeout != null) {  
                configurer.setDefaultTimeout(timeout.longValue());  
            }  
 
        }  

       在这里直接注入了HttpMessageConverters的Bean,而这个Bean是在HttpMessageConvertersAutoConfiguration类中定义的,我们自动扫描注册的HttpMessage Converter除了Spring MVC默认的ByteArrayHttpMessageConverter,StringHttpMessage Converter,Resource HttpMessageConverter等外,还自动配置文件里引入了JacksonHttpMessageConverters Configuration和GsonHttpMessage ConverterConfiguration,使我们获得了额外的HttpMessageConverter:

      若jackson的jar包在路径上,则Spring Boot通过JacksonHttpMessage Converters Configuration增加了MappingJackson2HttpMessage Converter和Mapping Jackson2XmlHttpMessageConverter

     若gson的jar包在路径上,则Spring Boot通过GsonHttpMessageConverterConfiguration增加GsonHttpMessageConverter

      在Spring Boot中如果要新增自定义的HttpMessageConverter,则只需定义一个你自己的HttpMessageConverters的Bean,然后在此Bean中注册自定义的HttpMessageConverter即可,如下:

@Bean  
 public HttpMessageConverters customConverters(){  
        HttpMessageConverter<?> customConverter1 = new CustomConverter1();  
        HttpMessageConverter<?> customConverter2 = new CustomConverter2();  
 return new HttpMessageConverters(customConverter1,customConverter2)  
    }  

5,静态首页的支持

把静态index.html文件放置在如下目录

classpath:/META-INF/resources/index.html

classpath:/resources/index.html

classpath:/static/index.html

classpath:/public/index.html

当我们访问应用根目录http://localhost:8080/时,会直接映射

二:接管Spring Boot的Web配置

        如果Spring Boot提供的Spring MVC默认配置不符合需求,则可以通过一个配置类(注解有@Configuration的类)加上@EnableWebMvc注解来实现完全自己控制的MVC配置。

       通常情况下,Spring Boot的自动配置是符合我们大多数需求的。在你既需要保留Spring Boot提供的便利,又需要增加自己额外的配置的时候,可以定义一个配置类并继承WebMvcConfigurerAdapter,无须使用@EnableWebMvc,例如:

package jack.springmvc.config;  
 
import jack.springmvc.interceptor.DemoInterceptor;  
import jack.springmvc.messageconverter.MyMessageConverter;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.ComponentScan;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.http.converter.HttpMessageConverter;  
import org.springframework.scheduling.annotation.EnableScheduling;  
import org.springframework.web.multipart.MultipartResolver;  
import org.springframework.web.multipart.commons.CommonsMultipartResolver;  
import org.springframework.web.servlet.config.annotation.*;  
import org.springframework.web.servlet.view.InternalResourceViewResolver;  
import org.springframework.web.servlet.view.JstlView;  
 
import java.util.List;  
 
/** 
 * Created by jack on 2017/7/16. 
 */  
@Configuration  
@EnableWebMvc   //开启Spring MVC支持,若无此句,重写WebMvcConfigurerAdapter方法无效  
@ComponentScan("jack.springmvc")  
@EnableScheduling   //开启计划任务的支持  
//继承WebMvcConfigurerAdapter类,重写其方法可对Spring MVC进行配置  
public class MyMvcConfig extends WebMvcConfigurerAdapter{  
 
 /** 
     * 配置拦截器的Bean 
     * @return 
     */  
 @Bean  
 public DemoInterceptor demoInterceptor(){  
 return new DemoInterceptor();  
    }  
 
 /** 
     * 配置文件上传Bean 
     * @return 
     */  
 @Bean  
 public MultipartResolver multipartResolver(){  
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();  
        multipartResolver.setMaxUploadSize(1000000);  
 return multipartResolver;  
    }  
 
 /** 
     * c重写addInterceptors方法,注册拦截器 
     * @param registry 
     */  
 @Override  
 public void addInterceptors(InterceptorRegistry registry) {  
 //super.addInterceptors(registry);  
        registry.addInterceptor(demoInterceptor());  
    }  
 
 @Bean  
 public InternalResourceViewResolver viewResolver(){  
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();  
 //viewResolver.setPrefix("/WEB-INF/classes/views/");  
        viewResolver.setPrefix("/WEB-INF/classes/views/");  
        viewResolver.setSuffix(".jsp");  
        viewResolver.setViewClass(JstlView.class);  
 return  viewResolver;  
    }  
 
 @Override  
 public void addResourceHandlers(ResourceHandlerRegistry registry) {  
 //super.addResourceHandlers(registry);  
 //addResourceLocations指的是文件放置的目录,addResourceHandler指的是对外暴露的访问路径  
        registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");  
    }  
 
    /**  
     * 统一处理没啥业务逻辑处理的controller请求,实现代码的简洁  
     * @param registry  
     */  
 @Override  
 public void addViewControllers(ViewControllerRegistry registry) {  
 //super.addViewControllers(registry);  
        registry.addViewController("/index").setViewName("/index");  
        registry.addViewController("/toUpload").setViewName("upload");  
        registry.addViewController("/converter").setViewName("/converter");  
        registry.addViewController("/sse").setViewName("/sse");  
        registry.addViewController("/async").setViewName("/async");  
    }  
 
 @Override  
 public void configurePathMatch(PathMatchConfigurer configurer) {  
 //super.configurePathMatch(configurer);  
        configurer.setUseSuffixPatternMatch(false);  
    }  
 
 /** 
     * 配置自定义的HttpMessageConverter的bean,在spring mvc里注册HttpMessageConverter有两个方法: 
     * configureMessageConverters:重载会覆盖掉Spring MVC默认注册的多个HttpMessageConverter 
     * extendMessageConverters:仅添加一个自定义的HttpMessageConverter,不覆盖默认注册的HttpMessageConverter 
     * @param converters 
     */  
 @Override  
 public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {  
 //super.extendMessageConverters(converters);  
        converters.add(converter());  
    }  
 
 @Bean  
 public MyMessageConverter converter(){  
 return new MyMessageConverter();  
    }  
 
}  

     上注意,上面重写了了addViewController方法,并不会覆盖WebMvcAutoConfiguration中的addViewController(在此方法中Spring Boot将“/”映射至index.html),这也就意味着我们自己的配置和Spring Boot的自动配置同时有效,这也是推荐添加自己的MVC配置的方式。

三:接注册Servlet,Filter,Listener

      当使用嵌入式的Servlet容器时,我们通过将Servlet,Filter和Listener声明为Spring Bean而达到注册的效果;或者注册ServletRegistrationBean,FilterRegistrationBean和ServletListenerRegistrationBean的Bean。

1)直接注册Bean示例,代码如下:

@Bean  
 public XxServlet xxServlet(){  
 return new XxServlet();  
    }  
 
 @Bean  
 public YyFilter yyFilter(){  
 return new YyFilter();  
    }  
 
 @Bean  
 public ZzListener zzListener(){  
 return new ZzListener()  
    }  

2)通过RegistrationBean

@Bean  
 public ServeletRegistrationBean serveletRegistrationBean(){  
 return new ServeletRegistrationBean(new Xxservlet(),"/xx/*");  
   }  
 
 @Bean  
 public FilterRegistrationBean filterRegistrationBean(){  
       FilterRegistrationBean registrationBean = new FilterRegistrationBean();  
       registrationBean.setFilter(new YyFilter());  
       registrationBean.setOrder(2);  
 return registrationBean;  
   }  
 @Bean  
 public ServletListenerRegistrationBean<ZzListener> zzListenerServletListenerRegistrationBean(){  
 return new ServletListenerRegistrationBean<ZzListener>(new ZzListener())  

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端之路

SpringBoot之自动配置

背景 提到SpringBoot各位开发者大概能想到一些标签 “新” “快” “FatJar” “微服务” “SpringCloud” “约定大约配置” “开箱即...

4779
来自专栏Jaycekon

Spring-Blog:个人博客(一)-Mybatis 读写分离

概述: 2018,在平(tou)静(lan)了一段时间后,开始找点事情来做。这一次准备开发一个个人博客,在开发过程之中完善一下自己的技术。本系列博客只会提出一...

3109
来自专栏Java帮帮-微信公众号-技术文章全总结

Java开发Spring第一天

今日内容 Spring框架的概述 Spring的快速入门 IoC容器装配Bean(xml配置方式) Ioc容器装配Bean(注解方式) 在web项目中集成Sp...

2729
来自专栏Java帮帮-微信公众号-技术文章全总结

Java面试系列17-编程题-读取服务器字符、实现序列化、计数器、1000阶乘、n出列问题等

一,Java的通信编程,编程题(或问答),用JAVA SOCKET编程,读服务器几个字符,再写入本地显示? Server端程序: package test;...

3648
来自专栏码匠的流水账

聊聊spring cloud的HystrixAutoConfiguration

本文主要研究一下spring cloud的HystrixAutoConfiguration

462
来自专栏静默虚空的博客

[Spring]IoC容器之进击的注解

概述 Spring2.5 引入了注解。 于是,一个问题产生了:使用注解方式注入 JavaBean 是不是一定完爆 xml方式? 未必。正所谓,仁者见仁智者见...

1677
来自专栏玩转JavaEE

Spring Cloud中Feign的继承特性

上篇文章我们了解了Feign的基本使用,在HelloService类中声明接口时,我们发现这里的代码可以直接从服务提供者的Controller中复制过来,这些可...

3176
来自专栏码匠的流水账

聊聊spring cloud gateway的NettyConfiguration

本文主要研究下spring cloud gateway的NettyConfiguration

591
来自专栏Android点滴积累

Android监听系统短信数据库变化-提取短信内容

由于监听系统短信广播受到权限的限制,所以很多手机可能使用这种方式没法监听广播,从而没办法获取到系统短信,所以又重新开辟一条路。 Android监听系统短信数据库...

26710
来自专栏后端之路

saiku刷缓存之卡卡卡

背景 今天saiku突然爆发 缓存刷新导致各种卡的不得了===》其实所有的请求在等待 由于增加了新的db连接导致后台系统判断重新刷新 导致页面无法加载 使用js...

3326

扫描关注云+社区