viewResolver组件会将viewName解析成view对象,view对象会调用render完成结果的处理。
View接口及实现类结构图:
不同的实现类有不同的视图效果:
1、VelocityView是用来和Velocity框架结合生成页面视图
2、FreeMarkerView是用来和FreeMarker框架结合生成页面视图
3、JstlView是用来生成jstl页面
4、RedirectView是生成页面跳转视图的。
View接口提供的接口方法还是比较简单的,这也是springMVC接口一贯的方式。
public interface View {
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
String PATH_VARIABLES = View.class.getName() + ".pathVariables";
String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
String getContentType();
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
}
简单说一下render方法的最终实现机制
(1)model是一个Map结构,其实就是ModelAndView中map,存放了我们返回给请求的所有结果值
(2)request和response当然就是请求和返回了
render中做的操作就是将model中的值全部存放到request和response中,这样就完成了请求的处理操作,最终就是返回response请求。
DispatcherServlet中的处理流程操作:
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
//设置语言
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
//通过ViewResolver解析生成View对象
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
//直接从ModelAndView中获取View对象
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
try {
//调用View对象的render方法
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
DispatcherServlet调用的是view的render方法
讲一下实现类做的操作
AbstractView实现了render方法,主要做的操作是将model中的参数和request中的参数全部都放到Request中,然后就转发Request就可以了。
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
" and static attributes " + this.staticAttributes);
}
//将model和request中的参数全部放到mergedModel中
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
//存放头部信息
prepareResponse(request, response);
//将mergedModel中的参数值放到request中
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
createMergedOutputModel中的操作就是将所有的数据放到mergedModel中。
protected Map<String, Object> createMergedOutputModel(Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) {
@SuppressWarnings("unchecked")
Map<String, Object> pathVars = (this.exposePathVariables ?
(Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);
// Consolidate static and dynamic model attributes.
int size = this.staticAttributes.size();
size += (model != null ? model.size() : 0);
size += (pathVars != null ? pathVars.size() : 0);
Map<String, Object> mergedModel = new LinkedHashMap<String, Object>(size);
mergedModel.putAll(this.staticAttributes);
if (pathVars != null) {
mergedModel.putAll(pathVars);
}
if (model != null) {
mergedModel.putAll(model);
}
// Expose RequestContext?
if (this.requestContextAttribute != null) {
mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
}
return mergedModel;
}
prepareResponse中的操作就是在头部中添加信息。
protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
if (generatesDownloadContent()) {
response.setHeader("Pragma", "private");
response.setHeader("Cache-Control", "private, must-revalidate");
}
}
renderMergedOutputModel是在子类中实现的,我们介绍一下我们经常使用的普通jsp源码使用的InternalResourceView
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
//把model中的所有数据放到request中
exposeModelAsRequestAttributes(model, request);
exposeHelpers(request);
//看看是否有跳转页面
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// If already included or response already committed, perform include, else forward.
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
//加载页面
rd.include(request, response);
}
else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
//转发操作
rd.forward(request, response);
}
}
以上代码就完成了springMVC的所有处理操作,springMVC最终的操作就是调用request及response完成请求操作了。