MVC的原理
官方文档:If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.大概意思:扩展mvc只需要添加 @Configuration实现WebMvcConfigurer接口即可
1.接下来我们自定义视图解析器,去看springBoot怎么做的
官方文档要我们查看ContentNegotiatingViewResolver类
(1)发现这个类实现了ViewResolver接口(实现了这个接口就可以看作视图解析器),接口中有View resolveViewName(String var1, Locale var2) throws Exception;
方法,看看ContentNegotiatingViewResolver类怎么实现这个方法的。
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean {
...
}
(2)找到resolveViewName方法,重点的两行代码表示获取候选视图,找到最好的视图
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
if (requestedMediaTypes != null) {
//重点
List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
//重点
if (bestView != null) {
return bestView;
}
}
String mediaTypeInfo = this.logger.isDebugEnabled() && requestedMediaTypes != null ? " given " + requestedMediaTypes.toString() : "";
if (this.useNotAcceptableStatusCode) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo);
}
return NOT_ACCEPTABLE_VIEW;
} else {
this.logger.debug("View remains unresolved" + mediaTypeInfo);
return null;
}
}
(3)点开getCandidateViews方法(获取候选视图)
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {
List<View> candidateViews = new ArrayList();
if (this.viewResolvers != null) {
Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
Iterator var5 = this.viewResolvers.iterator();
//遍历视图
while(var5.hasNext()) {
ViewResolver viewResolver = (ViewResolver)var5.next();
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
//满足条件将试图添加candidateViews容器中
candidateViews.add(view);
}
Iterator var8 = requestedMediaTypes.iterator();
while(var8.hasNext()) {
MediaType requestedMediaType = (MediaType)var8.next();
List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
Iterator var11 = extensions.iterator();
while(var11.hasNext()) {
String extension = (String)var11.next();
String viewNameWithExtension = viewName + '.' + extension;
view = viewResolver.resolveViewName(viewNameWithExtension, locale);
if (view != null) {
candidateViews.add(view);
}
}
}
}
}
if (!CollectionUtils.isEmpty(this.defaultViews)) {
candidateViews.addAll(this.defaultViews);
}
//返回满足条件视图
return candidateViews;
}
结论:我们明白了springboot使用视图解析器的方式,将满足条件的视图添加到一个IOC容器中,然后从容器中获取(spring使用容器中的东西@bean即可)
2.此刻我们应该知道如何自定义视图解析器了
1.实现视图解析器接口
2.将自定义的视图解析器注入到ioc容器之中
MVC的扩展(官方建议)
我们扩展视图跳转功能
步骤:添加 @Configuration实现WebMvcConfigurer接口
@Configuration
public class MyMVCConfig implements WebMvcConfigurer {
//视图跳转
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/aa").setViewName("index");
}
}