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 上午于成都
网友评论