初入spring boot(四 )web项目
1. 模板引擎
spring boot提供了大量的模板引擎,包括FreeMark、Groovy、Thymeleaf、Velocity等,但spring boot中推荐用Thymeleaf,因为Thymeleaf提供了完美的spring mvc的支持。
2. 与spring boot集成
在spring mvc中,若要集成一个模板引擎的话,需要定义ViewResolver,而ViewResolver需要定义一个View。Thymeleaf已经定义好了ViewResolver和View,分别是org.thymeleaf.spring4.view.ThymeleafViewResolver(默认使用ThymeleafView作为View)和org.thymeleaf.spring4.view.ThymeleafView。Thymeleaf提供了SpringTemplateEngine类,用来驱动在spring mvc下使用Thymeleaf模板引擎,另外还提供了一个TemplateResolver用来设置通用的模板引擎(包含前缀、后缀等),这使我们在spring mvc中集成Thymeleaf引擎变得十分简单。
上面说的是与spring mvc集成,但是ThymeleafView与Spring boot集成很方便,spring boot通过org.springframework.boot.autoconfigure.thymeleaf包对Thymeleaf进行了自动配置。
通过ThymeleafAutoConfiguration类对集成所需要的bean进行自动配置,包括templateResolver、templateEngine和thymeleafViewResolver的配置。
通过ThymeleafProperties来配置Thymeleaf,在application.properties中,以spring.thymeleaf开头来配置,通过查看ThymeleafProperties的主要源码,可以看出如何设置属性以及默认的配置:
1 @ConfigurationProperties(prefix = "spring.thymeleaf") 2 public class ThymeleafProperties { 3 4 private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8"); 5 6 private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html"); 7 8 public static final String DEFAULT_PREFIX = "classpath:/templates/"; 9 10 public static final String DEFAULT_SUFFIX = ".html"; 11 12 /** 13 * Check that the template exists before rendering it (Thymeleaf 3+). 14 */ 15 private boolean checkTemplate = true; 16 17 /** 18 * Check that the templates location exists. 19 */ 20 private boolean checkTemplateLocation = true; 21 22 /** 23 * Prefix that gets prepended to view names when building a URL. 24 */ 25 private String prefix = DEFAULT_PREFIX; 26 27 /** 28 * Suffix that gets appended to view names when building a URL. 29 */ 30 private String suffix = DEFAULT_SUFFIX; 31 32 /** 33 * Template mode to be applied to templates. See also StandardTemplateModeHandlers. 34 */ 35 private String mode = "HTML5"; 36 37 /** 38 * Template encoding. 39 */ 40 private Charset encoding = DEFAULT_ENCODING; 41 42 /** 43 * Content-Type value. 44 */ 45 private MimeType contentType = DEFAULT_CONTENT_TYPE; 46 47 /** 48 * Enable template caching. 49 */ 50 private boolean cache = true; 51 52 /** 53 * Order of the template resolver in the chain. By default, the template resolver is 54 * first in the chain. Order start at 1 and should only be set if you have defined 55 * additional "TemplateResolver" beans. 56 */ 57 private Integer templateResolverOrder; 58 59 /** 60 * Comma-separated list of view names that can be resolved. 61 */ 62 private String[] viewNames; 63 64 /** 65 * Comma-separated list of view names that should be excluded from resolution. 66 */ 67 private String[] excludedViewNames; 68 69 /** 70 * Enable MVC Thymeleaf view resolution. 71 */ 72 private boolean enabled = true; 73 74 public boolean isEnabled() { 75 return this.enabled; 76 } 77 78 public void setEnabled(boolean enabled) { 79 this.enabled = enabled; 80 } 81 82 public boolean isCheckTemplate() { 83 return this.checkTemplate; 84 } 85 86 public void setCheckTemplate(boolean checkTemplate) { 87 this.checkTemplate = checkTemplate; 88 } 89 90 public boolean isCheckTemplateLocation() { 91 return this.checkTemplateLocation; 92 } 93 94 public void setCheckTemplateLocation(boolean checkTemplateLocation) { 95 this.checkTemplateLocation = checkTemplateLocation; 96 } 97 98 public String getPrefix() { 99 return this.prefix; 100 } 101 102 public void setPrefix(String prefix) { 103 this.prefix = prefix; 104 } 105 106 public String getSuffix() { 107 return this.suffix; 108 } 109 110 public void setSuffix(String suffix) { 111 this.suffix = suffix; 112 } 113 114 public String getMode() { 115 return this.mode; 116 } 117 118 public void setMode(String mode) { 119 this.mode = mode; 120 } 121 122 public Charset getEncoding() { 123 return this.encoding; 124 } 125 126 public void setEncoding(Charset encoding) { 127 this.encoding = encoding; 128 } 129 130 public MimeType getContentType() { 131 return this.contentType; 132 } 133 134 public void setContentType(MimeType contentType) { 135 this.contentType = contentType; 136 } 137 138 public boolean isCache() { 139 return this.cache; 140 } 141 142 public void setCache(boolean cache) { 143 this.cache = cache; 144 } 145 146 public Integer getTemplateResolverOrder() { 147 return this.templateResolverOrder; 148 } 149 150 public void setTemplateResolverOrder(Integer templateResolverOrder) { 151 this.templateResolverOrder = templateResolverOrder; 152 } 153 154 public String[] getExcludedViewNames() { 155 return this.excludedViewNames; 156 } 157 158 public void setExcludedViewNames(String[] excludedViewNames) { 159 this.excludedViewNames = excludedViewNames; 160 } 161 162 public String[] getViewNames() { 163 return this.viewNames; 164 } 165 166 public void setViewNames(String[] viewNames) { 167 this.viewNames = viewNames; 168 } 169 170 }
3. web相关配置
3.1 spring boot提供的自动配置
通过查看WebMvcAutoConfiguration及WebMvcProperties的源码,可以发现spring boot提供了如下的自动配置
1 @Configuration 2 @ConditionalOnWebApplication 3 @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, 4 WebMvcConfigurerAdapter.class }) 5 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 6 @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) 7 @AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, 8 ValidationAutoConfiguration.class }) 9 public class WebMvcAutoConfiguration { 10 11 public static String DEFAULT_PREFIX = ""; 12 13 public static String DEFAULT_SUFFIX = ""; 14 15 @Bean 16 @ConditionalOnMissingBean(HiddenHttpMethodFilter.class) 17 public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() { 18 return new OrderedHiddenHttpMethodFilter(); 19 } 20 21 @Bean 22 @ConditionalOnMissingBean(HttpPutFormContentFilter.class) 23 @ConditionalOnProperty(prefix = "spring.mvc.formcontent.putfilter", name = "enabled", matchIfMissing = true) 24 public OrderedHttpPutFormContentFilter httpPutFormContentFilter() { 25 return new OrderedHttpPutFormContentFilter(); 26 } 27 28 // Defined as a nested config to ensure WebMvcConfigurerAdapter is not read when not 29 // on the classpath 30 @Configuration 31 @Import(EnableWebMvcConfiguration.class) 32 @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) 33 public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter { 34 35 private static final Log logger = LogFactory 36 .getLog(WebMvcConfigurerAdapter.class); 37 38 private final ResourceProperties resourceProperties; 39 40 private final WebMvcProperties mvcProperties; 41 42 private final ListableBeanFactory beanFactory; 43 44 private final HttpMessageConverters messageConverters; 45 46 final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer; 47 48 public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, 49 WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, 50 HttpMessageConverters messageConverters, 51 ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) { 52 this.resourceProperties = resourceProperties; 53 this.mvcProperties = mvcProperties; 54 this.beanFactory = beanFactory; 55 this.messageConverters = messageConverters; 56 this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider 57 .getIfAvailable(); 58 } 59 60 @Override 61 public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 62 converters.addAll(this.messageConverters.getConverters()); 63 } 64 65 @Override 66 public void configureAsyncSupport(AsyncSupportConfigurer configurer) { 67 Long timeout = this.mvcProperties.getAsync().getRequestTimeout(); 68 if (timeout != null) { 69 configurer.setDefaultTimeout(timeout); 70 } 71 } 72 73 @Override 74 public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { 75 Map<String, MediaType> mediaTypes = this.mvcProperties.getMediaTypes(); 76 for (Entry<String, MediaType> mediaType : mediaTypes.entrySet()) { 77 configurer.mediaType(mediaType.getKey(), mediaType.getValue()); 78 } 79 } 80 81 @Bean 82 @ConditionalOnMissingBean 83 public InternalResourceViewResolver defaultViewResolver() { 84 InternalResourceViewResolver resolver = new InternalResourceViewResolver(); 85 resolver.setPrefix(this.mvcProperties.getView().getPrefix()); 86 resolver.setSuffix(this.mvcProperties.getView().getSuffix()); 87 return resolver; 88 } 89 90 @Bean 91 @ConditionalOnBean(View.class) 92 @ConditionalOnMissingBean 93 public BeanNameViewResolver beanNameViewResolver() { 94 BeanNameViewResolver resolver = new BeanNameViewResolver(); 95 resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10); 96 return resolver; 97 } 98 99 @Bean 100 @ConditionalOnBean(ViewResolver.class) 101 @ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class) 102 public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) { 103 ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); 104 resolver.setContentNegotiationManager( 105 beanFactory.getBean(ContentNegotiationManager.class)); 106 // ContentNegotiatingViewResolver uses all the other view resolvers to locate 107 // a view so it should have a high precedence 108 resolver.setOrder(Ordered.HIGHEST_PRECEDENCE); 109 return resolver; 110 } 111 112 @Bean 113 @ConditionalOnMissingBean 114 @ConditionalOnProperty(prefix = "spring.mvc", name = "locale") 115 public LocaleResolver localeResolver() { 116 if (this.mvcProperties 117 .getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) { 118 return new FixedLocaleResolver(this.mvcProperties.getLocale()); 119 } 120 AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); 121 localeResolver.setDefaultLocale(this.mvcProperties.getLocale()); 122 return localeResolver; 123 } 124 125 @Bean 126 @ConditionalOnProperty(prefix = "spring.mvc", name = "date-format") 127 public Formatter<Date> dateFormatter() { 128 return new DateFormatter(this.mvcProperties.getDateFormat()); 129 } 130 131 @Override 132 public MessageCodesResolver getMessageCodesResolver() { 133 if (this.mvcProperties.getMessageCodesResolverFormat() != null) { 134 DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver(); 135 resolver.setMessageCodeFormatter( 136 this.mvcProperties.getMessageCodesResolverFormat()); 137 return resolver; 138 } 139 return null; 140 } 141 142 @Override 143 public void addFormatters(FormatterRegistry registry) { 144 for (Converter<?, ?> converter : getBeansOfType(Converter.class)) { 145 registry.addConverter(converter); 146 } 147 for (GenericConverter converter : getBeansOfType(GenericConverter.class)) { 148 registry.addConverter(converter); 149 } 150 for (Formatter<?> formatter : getBeansOfType(Formatter.class)) { 151 registry.addFormatter(formatter); 152 } 153 } 154 155 private <T> Collection<T> getBeansOfType(Class<T> type) { 156 return this.beanFactory.getBeansOfType(type).values(); 157 } 158 159 @Override 160 public void addResourceHandlers(ResourceHandlerRegistry registry) { 161 if (!this.resourceProperties.isAddMappings()) { 162 logger.debug("Default resource handling disabled"); 163 return; 164 } 165 Integer cachePeriod = this.resourceProperties.getCachePeriod(); 166 if (!registry.hasMappingForPattern("/webjars/**")) { 167 customizeResourceHandlerRegistration( 168 registry.addResourceHandler("/webjars/**") 169 .addResourceLocations( 170 "classpath:/META-INF/resources/webjars/") 171 .setCachePeriod(cachePeriod)); 172 } 173 String staticPathPattern = this.mvcProperties.getStaticPathPattern(); 174 if (!registry.hasMappingForPattern(staticPathPattern)) { 175 customizeResourceHandlerRegistration( 176 registry.addResourceHandler(staticPathPattern) 177 .addResourceLocations( 178 this.resourceProperties.getStaticLocations()) 179 .setCachePeriod(cachePeriod)); 180 } 181 } 182 183 @Bean 184 public WelcomePageHandlerMapping welcomePageHandlerMapping( 185 ResourceProperties resourceProperties) { 186 return new WelcomePageHandlerMapping(resourceProperties.getWelcomePage()); 187 } 188 189 private void customizeResourceHandlerRegistration( 190 ResourceHandlerRegistration registration) { 191 if (this.resourceHandlerRegistrationCustomizer != null) { 192 this.resourceHandlerRegistrationCustomizer.customize(registration); 193 } 194 195 } 196 197 @Bean 198 @ConditionalOnMissingBean({ RequestContextListener.class, 199 RequestContextFilter.class }) 200 public static RequestContextFilter requestContextFilter() { 201 return new OrderedRequestContextFilter(); 202 } 203 204 @Configuration 205 @ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true) 206 public static class FaviconConfiguration { 207 208 private final ResourceProperties resourceProperties; 209 210 public FaviconConfiguration(ResourceProperties resourceProperties) { 211 this.resourceProperties = resourceProperties; 212 } 213 214 @Bean 215 public SimpleUrlHandlerMapping faviconHandlerMapping() { 216 SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); 217 mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); 218 mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", 219 faviconRequestHandler())); 220 return mapping; 221 } 222 223 @Bean 224 public ResourceHttpRequestHandler faviconRequestHandler() { 225 ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler(); 226 requestHandler 227 .setLocations(this.resourceProperties.getFaviconLocations()); 228 return requestHandler; 229 } 230 231 } 232 233 } 234 235 /** 236 * Configuration equivalent to {@code @EnableWebMvc}. 237 */ 238 @Configuration 239 public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration { 240 241 private final WebMvcProperties mvcProperties; 242 243 private final ListableBeanFactory beanFactory; 244 245 private final WebMvcRegistrations mvcRegistrations; 246 247 public EnableWebMvcConfiguration( 248 ObjectProvider<WebMvcProperties> mvcPropertiesProvider, 249 ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, 250 ListableBeanFactory beanFactory) { 251 this.mvcProperties = mvcPropertiesProvider.getIfAvailable(); 252 this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique(); 253 this.beanFactory = beanFactory; 254 } 255 256 @Bean 257 @Override 258 public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { 259 RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(); 260 adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null ? true 261 : this.mvcProperties.isIgnoreDefaultModelOnRedirect()); 262 return adapter; 263 } 264 265 @Override 266 protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() { 267 if (this.mvcRegistrations != null 268 && this.mvcRegistrations.getRequestMappingHandlerAdapter() != null) { 269 return this.mvcRegistrations.getRequestMappingHandlerAdapter(); 270 } 271 return super.createRequestMappingHandlerAdapter(); 272 } 273 274 @Bean 275 @Primary 276 @Override 277 public RequestMappingHandlerMapping requestMappingHandlerMapping() { 278 // Must be @Primary for MvcUriComponentsBuilder to work 279 return super.requestMappingHandlerMapping(); 280 } 281 282 @Bean 283 @Override 284 public Validator mvcValidator() { 285 if (!ClassUtils.isPresent("javax.validation.Validator", 286 getClass().getClassLoader())) { 287 return super.mvcValidator(); 288 } 289 return WebMvcValidator.get(getApplicationContext(), 290 getValidator()); 291 } 292 293 @Override 294 protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() { 295 if (this.mvcRegistrations != null 296 && this.mvcRegistrations.getRequestMappingHandlerMapping() != null) { 297 return this.mvcRegistrations.getRequestMappingHandlerMapping(); 298 } 299 return super.createRequestMappingHandlerMapping(); 300 } 301 302 @Override 303 protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() { 304 try { 305 return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class); 306 } 307 catch (NoSuchBeanDefinitionException ex) { 308 return super.getConfigurableWebBindingInitializer(); 309 } 310 } 311 312 @Override 313 protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() { 314 if (this.mvcRegistrations != null && this.mvcRegistrations 315 .getExceptionHandlerExceptionResolver() != null) { 316 return this.mvcRegistrations.getExceptionHandlerExceptionResolver(); 317 } 318 return super.createExceptionHandlerExceptionResolver(); 319 } 320 321 @Override 322 protected void configureHandlerExceptionResolvers( 323 List<HandlerExceptionResolver> exceptionResolvers) { 324 super.configureHandlerExceptionResolvers(exceptionResolvers); 325 if (exceptionResolvers.isEmpty()) { 326 addDefaultHandlerExceptionResolvers(exceptionResolvers); 327 } 328 if (this.mvcProperties.isLogResolvedException()) { 329 for (HandlerExceptionResolver resolver : exceptionResolvers) { 330 if (resolver instanceof AbstractHandlerExceptionResolver) { 331 ((AbstractHandlerExceptionResolver) resolver) 332 .setWarnLogCategory(resolver.getClass().getName()); 333 } 334 } 335 } 336 } 337 338 } 339 340 @Configuration 341 @ConditionalOnEnabledResourceChain 342 static class ResourceChainCustomizerConfiguration { 343 344 @Bean 345 public ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() { 346 return new ResourceChainResourceHandlerRegistrationCustomizer(); 347 } 348 349 } 350 351 interface ResourceHandlerRegistrationCustomizer { 352 353 void customize(ResourceHandlerRegistration registration); 354 355 } 356 357 private static class ResourceChainResourceHandlerRegistrationCustomizer 358 implements ResourceHandlerRegistrationCustomizer { 359 360 @Autowired 361 private ResourceProperties resourceProperties = new ResourceProperties(); 362 363 @Override 364 public void customize(ResourceHandlerRegistration registration) { 365 ResourceProperties.Chain properties = this.resourceProperties.getChain(); 366 configureResourceChain(properties, 367 registration.resourceChain(properties.isCache())); 368 } 369 370 private void configureResourceChain(ResourceProperties.Chain properties, 371 ResourceChainRegistration chain) { 372 Strategy strategy = properties.getStrategy(); 373 if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) { 374 chain.addResolver(getVersionResourceResolver(strategy)); 375 } 376 if (properties.isGzipped()) { 377 chain.addResolver(new GzipResourceResolver()); 378 } 379 if (properties.isHtmlApplicationCache()) { 380 chain.addTransformer(new AppCacheManifestTransformer()); 381 } 382 } 383 384 private ResourceResolver getVersionResourceResolver( 385 ResourceProperties.Strategy properties) { 386 VersionResourceResolver resolver = new VersionResourceResolver(); 387 if (properties.getFixed().isEnabled()) { 388 String version = properties.getFixed().getVersion(); 389 String[] paths = properties.getFixed().getPaths(); 390 resolver.addFixedVersionStrategy(version, paths); 391 } 392 if (properties.getContent().isEnabled()) { 393 String[] paths = properties.getContent().getPaths(); 394 resolver.addContentVersionStrategy(paths); 395 } 396 return resolver; 397 } 398 399 } 400 401 static final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping { 402 403 private static final Log logger = LogFactory 404 .getLog(WelcomePageHandlerMapping.class); 405 406 private WelcomePageHandlerMapping(Resource welcomePage) { 407 if (welcomePage != null) { 408 logger.info("Adding welcome page: " + welcomePage); 409 ParameterizableViewController controller = new ParameterizableViewController(); 410 controller.setViewName("forward:index.html"); 411 setRootHandler(controller); 412 setOrder(0); 413 } 414 } 415 416 @Override 417 public Object getHandlerInternal(HttpServletRequest request) throws Exception { 418 for (MediaType mediaType : getAcceptedMediaTypes(request)) { 419 if (mediaType.includes(MediaType.TEXT_HTML)) { 420 return super.getHandlerInternal(request); 421 } 422 } 423 return null; 424 } 425 426 private List<MediaType> getAcceptedMediaTypes(HttpServletRequest request) { 427 String acceptHeader = request.getHeader(HttpHeaders.ACCEPT); 428 return MediaType.parseMediaTypes( 429 StringUtils.hasText(acceptHeader) ? acceptHeader : "*/*"); 430 } 431 432 } 433 434 }
1 @ConfigurationProperties(prefix = "spring.mvc") 2 public class WebMvcProperties { 3 4 /** 5 * Formatting strategy for message codes (PREFIX_ERROR_CODE, POSTFIX_ERROR_CODE). 6 */ 7 private DefaultMessageCodesResolver.Format messageCodesResolverFormat; 8 9 /** 10 * Locale to use. By default, this locale is overridden by the "Accept-Language" 11 * header. 12 */ 13 private Locale locale; 14 15 /** 16 * Define how the locale should be resolved. 17 */ 18 private LocaleResolver localeResolver = LocaleResolver.ACCEPT_HEADER; 19 20 /** 21 * Date format to use (e.g. dd/MM/yyyy). 22 */ 23 private String dateFormat; 24 25 /** 26 * Dispatch TRACE requests to the FrameworkServlet doService method. 27 */ 28 private boolean dispatchTraceRequest = false; 29 30 /** 31 * Dispatch OPTIONS requests to the FrameworkServlet doService method. 32 */ 33 private boolean dispatchOptionsRequest = true; 34 35 /** 36 * If the content of the "default" model should be ignored during redirect scenarios. 37 */ 38 private boolean ignoreDefaultModelOnRedirect = true; 39 40 /** 41 * If a "NoHandlerFoundException" should be thrown if no Handler was found to process 42 * a request. 43 */ 44 private boolean throwExceptionIfNoHandlerFound = false; 45 46 /** 47 * Enable warn logging of exceptions resolved by a "HandlerExceptionResolver". 48 */ 49 private boolean logResolvedException = false; 50 51 /** 52 * Maps file extensions to media types for content negotiation, e.g. yml->text/yaml. 53 */ 54 private Map<String, MediaType> mediaTypes = new LinkedHashMap<String, MediaType>(); 55 56 /** 57 * Path pattern used for static resources. 58 */ 59 private String staticPathPattern = "/**"; 60 61 private final Async async = new Async(); 62 63 private final Servlet servlet = new Servlet(); 64 65 private final View view = new View(); 66 67 public DefaultMessageCodesResolver.Format getMessageCodesResolverFormat() { 68 return this.messageCodesResolverFormat; 69 } 70 71 public void setMessageCodesResolverFormat( 72 DefaultMessageCodesResolver.Format messageCodesResolverFormat) { 73 this.messageCodesResolverFormat = messageCodesResolverFormat; 74 } 75 76 public Locale getLocale() { 77 return this.locale; 78 } 79 80 public void setLocale(Locale locale) { 81 this.locale = locale; 82 } 83 84 public LocaleResolver getLocaleResolver() { 85 return this.localeResolver; 86 } 87 88 public void setLocaleResolver(LocaleResolver localeResolver) { 89 this.localeResolver = localeResolver; 90 } 91 92 public String getDateFormat() { 93 return this.dateFormat; 94 } 95 96 public void setDateFormat(String dateFormat) { 97 this.dateFormat = dateFormat; 98 } 99 100 public boolean isIgnoreDefaultModelOnRedirect() { 101 return this.ignoreDefaultModelOnRedirect; 102 } 103 104 public void setIgnoreDefaultModelOnRedirect(boolean ignoreDefaultModelOnRedirect) { 105 this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect; 106 } 107 108 public boolean isThrowExceptionIfNoHandlerFound() { 109 return this.throwExceptionIfNoHandlerFound; 110 } 111 112 public void setThrowExceptionIfNoHandlerFound( 113 boolean throwExceptionIfNoHandlerFound) { 114 this.throwExceptionIfNoHandlerFound = throwExceptionIfNoHandlerFound; 115 } 116 117 public boolean isLogResolvedException() { 118 return this.logResolvedException; 119 } 120 121 public void setLogResolvedException(boolean logResolvedException) { 122 this.logResolvedException = logResolvedException; 123 } 124 125 public Map<String, MediaType> getMediaTypes() { 126 return this.mediaTypes; 127 } 128 129 public void setMediaTypes(Map<String, MediaType> mediaTypes) { 130 this.mediaTypes = mediaTypes; 131 } 132 133 public boolean isDispatchOptionsRequest() { 134 return this.dispatchOptionsRequest; 135 } 136 137 public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) { 138 this.dispatchOptionsRequest = dispatchOptionsRequest; 139 } 140 141 public boolean isDispatchTraceRequest() { 142 return this.dispatchTraceRequest; 143 } 144 145 public void setDispatchTraceRequest(boolean dispatchTraceRequest) { 146 this.dispatchTraceRequest = dispatchTraceRequest; 147 } 148 149 public String getStaticPathPattern() { 150 return this.staticPathPattern; 151 } 152 153 public void setStaticPathPattern(String staticPathPattern) { 154 this.staticPathPattern = staticPathPattern; 155 } 156 157 public Async getAsync() { 158 return this.async; 159 } 160 161 public Servlet getServlet() { 162 return this.servlet; 163 } 164 165 public View getView() { 166 return this.view; 167 } 168 169 public static class Async { 170 171 /** 172 * Amount of time (in milliseconds) before asynchronous request handling times 173 * out. If this value is not set, the default timeout of the underlying 174 * implementation is used, e.g. 10 seconds on Tomcat with Servlet 3. 175 */ 176 private Long requestTimeout; 177 178 public Long getRequestTimeout() { 179 return this.requestTimeout; 180 } 181 182 public void setRequestTimeout(Long requestTimeout) { 183 this.requestTimeout = requestTimeout; 184 } 185 186 } 187 188 public static class Servlet { 189 190 /** 191 * Load on startup priority of the dispatcher servlet. 192 */ 193 private int loadOnStartup = -1; 194 195 public int getLoadOnStartup() { 196 return this.loadOnStartup; 197 } 198 199 public void setLoadOnStartup(int loadOnStartup) { 200 this.loadOnStartup = loadOnStartup; 201 } 202 203 } 204 205 public static class View { 206 207 /** 208 * Spring MVC view prefix. 209 */ 210 private String prefix; 211 212 /** 213 * Spring MVC view suffix. 214 */ 215 private String suffix; 216 217 public String getPrefix() { 218 return this.prefix; 219 } 220 221 public void setPrefix(String prefix) { 222 this.prefix = prefix; 223 } 224 225 public String getSuffix() { 226 return this.suffix; 227 } 228 229 public void setSuffix(String suffix) { 230 this.suffix = suffix; 231 } 232 233 } 234 235 public enum LocaleResolver { 236 237 /** 238 * Always use the configured locale. 239 */ 240 FIXED, 241 242 /** 243 * Use the "Accept-Language" header or the configured locale if the header is not 244 * set. 245 */ 246 ACCEPT_HEADER 247 248 } 249 250 }
3.2 接管spring boot的web配置
在既需要保留spring boot提供的便利,又需要增加自己的额外的配置的时候,可以定义一个配置类并继承WebMvcConfigurerAdapter,无须使用@EnableWebMvc注解,然后按照spring mvc的配置方法来添加spring boot其他配置。值得指出的是重写addViewControllers方法,并不会覆盖WebMvcConfigurerAdapter中的addViewControllers(在此方法中,spring boot 将“/”映射至index.html),这也就意味着我们自己的配置和spring boot的自动配置同时有效,这也是推荐添加自己的mvc配置的方式。
3.3 注册servlet、filter、Listener
当使用嵌入式的servlet容器(tomcat、jetty等)时,通过将servlet、filter和listener声明为spring bean而达到注册的效果;或者注册ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean的bean。
3.4 Tomcat配置
关于tomcat的所有属性都在org.springframework.boot.autoconfigure.web.ServerProperties配置类中做了定义,我们只需要在application.Properties配置属性做配置即可。通用的Servlet容器配置都以“server”作为前缀,而tomcat特有的配置都以“server.tomcat”作为前缀。配置tomcat还可以用代码的方式配置,以后再说。