springmvc由HandlerAdapter执行具体的handler后,返回的是ModelAndView对象,如何映射到具体的视图,生成页面返回到浏览器,就需要ViewResolver和View来操作了。
View的解析流程
1、org.springframework.web.servlet.DispatcherServlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
...
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
}
// 目标方法执行完成后的视图处理
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
...
}
....
}
2、在processDispatchResult方法中调用了DispatcherServlet#render方法
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
....
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
...
}
}
3、org.springframework.web.servlet.DispatcherServlet#render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
...
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 根据viewName找查resolve
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
...
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
}
...
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 获取渲染的视图
view.render(mv.getModelInternal(), request, response);
}
...
}
resolveViewName方法如下:
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
viewResolvers则是DispatcherServlet初始化时设置的,并且经过order排序之后的
4、org.springframework.web.servlet.view.AbstractView#render
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(reuest, response);
// 获取OutputStreaml输出的内容,不用同视图解决有不同的实现
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
FastJsonJsonView的renderMergedOutputModel实现
protected void renderMergedOutputModel(Map<String, Object> model, //
HttpServletRequest request, //
HttpServletResponse response) throws Exception {
ByteArrayOutputStream outnew = new ByteArrayOutputStream();
int len = JSON.writeJSONString(outnew, //
fastJsonConfig.getCharset(), //
value, //
fastJsonConfig.getSerializeConfig(), //
fastJsonConfig.getSerializeFilters(), //
fastJsonConfig.getDateFormat(), //
JSON.DEFAULT_GENERATE_FEATURE, //
fastJsonConfig.getSerializerFeatures());
ServletOutputStream out = response.getOutputStream();
outnew.writeTo(out);
outnew.close();
out.flush();
}
InternalResourceView的renderMergedOutputModel的实现
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
exposeModelAsRequestAttributes(model, request);
exposeHelpers(request);
String dispatcherPath = prepareForRendering(request, response);
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (useInclude(request, response)) {
response.setContentType(getContentType());
rd.include(request, response);
}else {
rd.forward(request, response);
}
}
常用的ViewResolver
ViewResolver
的主要作用是把一个逻辑上的视图名称解析为一个真正的视图,SpringMVC中用于把View
对象呈现给客户端的是View
对象本身,而ViewResolver
只是把逻辑视图名称解析为对象的View
对象。View
接口的主要作用是用于处理视图,然后返回给客户端。
IDE根据一个接口生产它的关系图方法:接口下右键Diagrams->Show Diagram,然后选中接口右键Show Implementations

-
AbstractCachingViewResolver
这是一个抽象类,这种视图解析器会把它曾经解析过的视图保存起来,然后每次要解析视图的时候先从缓存里面找,如果找到了对
应的视图就直接返回,如果没有就创建一个新的视图对象,然后把它放到一个用于缓存的
map
中,接着再把新建的视图返回。使用这种视图缓存的方式可以把解析视图的性能问题降到最低。
-
UrlBasedViewResolver
它是对
ViewResolver
的一种简单实现,而且继承了AbstractCachingViewResolver
,主要就是提供的一种拼接URL的方式来解析视图,它可以让我们通过prefix属性
指定一个指定的前缀,通过suffix属性
指定一个指定的后缀,然后把返回的逻辑视图名称加上指定的前缀和后缀就是指定的视图URL了。如prefix=/WEB-INF/jsps/
,suffix=.jsp
,返回的视图名称viewName=test/indx
, 则UrlBasedViewResolver
解析出来的视图URL就是/WEB-INF/jsps/test/index.jsp
。 -
InternalResourceViewResolver
InternalResourceViewResolver
会把返回的视图名称都解析为InternalResourceView
对象,InternalResourceView
会把Controller处理器方法返回的模型属性都存放到对应的request属性中,然后通过RequestDispatcher
在服务器端把请求forword重定向到目标URL。
网友评论