类图
属性
结合InternalResourceView及其父类,我们可以发现它有如下一些属性:
String beanName;
String contentType = "text/html;charset=ISO-8859-1";
String requestContextAttribute;
Map<String, Object> staticAttributes = new LinkedHashMap<String, Object>(); // 静态属性,会与model进行合并
exposePathVariables = true; // 决定请求路径中的变量是否与合并到model中
String url;
boolean alwaysInclude = false; // 如果为true,则总是调用RequestDispatcher的include方式
boolean exposeContextBeansAsAttributes = false; // 决定是否将context中的beans作为属性暴露
Set<String> exposedContextBeanNames; // 决定需要暴露的beans的名称
boolean preventDispatchLoop = false; // 决定是否允许循环循环
渲染流程
整合InternalResourceView及其父类的渲染部分,
// AbstractView
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);
}
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response); // 用来解决IE的https下载的bug
renderMergedOutputModel(mergedModel, request, response);
}
// InternalResourceView
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine which request handle to expose to the RequestDispatcher.
HttpServletRequest requestToExpose = getRequestToExpose(request);
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, requestToExpose);
// Expose helpers as request attributes, if any.
exposeHelpers(requestToExpose);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(requestToExpose, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(requestToExpose, 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(requestToExpose, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(requestToExpose, 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(requestToExpose, response);
}
}
我们可以分析整个处理流程如下,
- 进行model合并(将静态属性、地址变量和原model合并,与staticAttributes和exposePathVariables属性有关)
- 将请求处理器暴露给RequestDispatcher(与exposeContextBeansAsAttributes和exposedContextBeanNames属性有关)
- 将合并后的model作为属性暴露给请求
- 将helper作为请求属性暴露
- 设置路径(这里主要是做了一个url循环判断,与preventDispatchLoop属性的设置有关)
- 获取请求、路径对应的RequestDispatcher
- 通过include或forward进行请求处理