// 5.結果視圖對象的處理 applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
applyDefaultViewName(processedRequest, mv);
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
視圖渲染方法:
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
render方法中實現:
render方法:
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
//聲明一個view
View view;
//得到一個view名字
String viewName = mv.getViewName();
if (viewName != null) {
// We need to resolve the view name.
//創建對象
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
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() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
//渲染view
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;
}
}
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
//遍歷本地所有的viewResolver,找到合適的視圖解析器創建視圖
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
view.render()
View接口中:
void render(@Nullable Map<String, ?> model,HttpServletRequest request, HttpServletResponse response) throws Exception;
AbstractView類實現:
public void render(@Nullable 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);
//view視圖渲染與輸出數據
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
AbstractView類:
protected abstract void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
視圖解析器
視圖解析器 | 說明 |
AbstractCachingViewResolver | 一個抽象視圖,繼承該類可以讓視圖解析器具有緩存功能 |
XmlViewResolver | 接受XML文件的視圖解析器,默認配置文件在 /WEB-INF/views.xml |
ResourceBundleViewResolver | 使用properties配置文件的視圖解析器,默認配置文件是類路徑下的views.properties |
UrlBasedViewResolver | 一個簡單的視圖解析器,不做任何匹配,需要視圖名和實際視圖文件名相同 |
InternalResourceViewResolver | UrlBasedViewResolver的一個子類,支持Servlet容器的內部類型(JSP、Servlet、以及JSTL等),可以使用setViewClass(..)指定具體的視圖類型 |
FreeMarkerViewResolver | 也是UrlBasedViewResolver的子類,用於FreeMarker視圖技術 |
ContentNegotiatingViewResolver |
用於解析基於請求文件名或Accept header的視圖 |
BeanNameViewResolver | 將邏輯視圖名解析爲一個 Bean,Bean 的 id 等於邏輯視圖名 |
視圖:
視圖 |
說明 |
InternalResourceView | 將 JSP 或其他資源封裝成一個視圖,一般 JSP 頁面用該視圖類 |
JstlView | 繼承自InternalResourceView,如果 JSP 頁面使用了 JSTL 標籤,則需要使用該視圖類 |
AbstractPdfView | PDF視圖的抽象超類 |
AbstractXlsView | 傳統XLS格式的Excel文檔視圖的便捷超類,與Apache POI 3.5及更高版本兼容。 |
AbstractXlsxView | Office 2007 XLSX格式的Excel文檔視圖的便捷超類,兼容Apache POI 3.5及更高版本。 |
MappingJackson2JsonView | 將模型數據 通過 Jackson 開源框架的 ObjectMapper 以 JSON 方式輸出 |
我們看下InternalResourceViewResolver裏面的renderMergedOutputModel()方法:
InternalResourceView下面的renderMergedOutputModel(...)方法:
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Expose the model object as request attributes.
//model裏面的鍵值對數據寫入到RequestScope中
exposeModelAsRequestAttributes(model, request);
//請求轉發,頁面跳轉
// Expose helpers as request attributes, if any.
exposeHelpers(request);
// Determine the path for the request dispatcher.
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);
}
}
AbstractView類中:
protected void exposeModelAsRequestAttributes(Map<String, Object> model,
HttpServletRequest request) throws Exception {
//數據寫進request裏面
model.forEach((modelName, modelValue) -> {
if (modelValue != null) {
request.setAttribute(modelName, modelValue);
if (logger.isDebugEnabled()) {
logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +
"] to request in view with name '" + getBeanName() + "'");
}
}
else {
request.removeAttribute(modelName);
if (logger.isDebugEnabled()) {
logger.debug("Removed model object '" + modelName +
"' from request in view with name '" + getBeanName() + "'");
}
}
});
}
以上就是視圖渲染,返回頁面等操作。