在调用完我们的业务逻辑之后,springmvc会生成一个modelAndView对象,然后将他处理解析成view视图返回给前端。所以我们再来分析一下视图的生成以及解析规则。
接着我们上一节在handlerAdapter的初始化时说的调用handlerAdapter的handle方法,看看他到底是怎么生成view的
业务处理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
视图生成
AbstractHandlerMethodAdapter 39 line
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return this.handleInternal(request, response, (HandlerMethod)handler);
}
RequestMappinjgHandlerAdapter 464 line
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//检查请求是否合法 (请求方式以及session的检查)
this.checkRequest(request);
ModelAndView mav;
//使用session加锁 这一块是false 所以看esle分支
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized(mutex) {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
} else {
//执行业务 往下看
mav = this.invokeHandlerMethod(request, response, handlerMethod);
}
//缓存的处理
if (!response.containsHeader("Cache-Control")) {
if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
this.prepareResponse(response);
}
}
return mav;
}
业务逻辑的处理
RequestMappingHandlerAdapter 503 line
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//包装一个ServletWebRequest
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ModelAndView var15;
try {
一些准备工作 创建ModelFactory、ModelAndViewContainer、WebAsyncManager并设置一些属性值
......
//执行业务
invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
if (asyncManager.isConcurrentHandlingStarted()) {
result = null;
return (ModelAndView)result;
}
//获取视图
var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
return var15;
}
执行业务
ServletInvocableHandlerMethod 50 line
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//解析请求的参数,并且执行我们的controller的方法,拿到返回值
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
//设置相应状态
this.setResponseStatus(webRequest);
if (returnValue == null) {
if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
this.disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
//标识请求结果还没处理
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
//处理请求结果 使用converter将结果写出去 outputstream流
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(this.formatErrorForReturnValue(returnValue), var6);
}
throw var6;
}
}
处理请求结果 这一块会决定返回试图还是返回json数据
HandlerMethodReturnValueHandlerComposite 49 line
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//根据返回值与返回值类型去获取返回值处理的handler
HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
} else {
//使用handler来处理返回结果
//如果是json数据,则使用RequestResponseBodyMethodProcessor
//如果是ModelAndView,则使用ModelAndViewMethodRetuenValueHandler来处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
获取视图
RequestMappingHandlerAdapter 654 line
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//更新下默认的Model
modelFactory.updateModel(webRequest, mavContainer);
//如果需要返回视图,那么上面使用handler处理结果的时候会将这个置为false
if (mavContainer.isRequestHandled()) {
return null;
} else {
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
//设置视图的名字
mav.setView((View)mavContainer.getView());
}
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes)model).getFlashAttributes();
HttpServletRequest request = (HttpServletRequest)webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
}
设置视图的名字
DispatcherServlet 504 line
this.applyDefaultViewName(processedRequest, mv);
536 line
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
//如果需要返回试图,并且视图名字为null,也就是我们没设置视图名字,那么使用默认的接口名作为视图名字
if (mv != null && !mv.hasView()) {
String defaultViewName = this.getDefaultViewName(request);
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
视图渲染
DispatcherServlet 546 line
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
boolean errorView = false;
异常处理
......
if (mv != null && !mv.wasCleared()) {
//视图渲染 往下看
this.render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
......
}
DispatcherServlet 713 line
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
response.setLocale(locale);
String viewName = mv.getViewName();
View view;
if (viewName != null) {
//这一块使用我们配置的视图解析器去解析这个视图, 将视图名字拼上我们的请求转发的前后缀
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
}
try {
//视图渲染
view.render(mv.getModelInternal(), request, response);
}
}
AbstractView 141 line
public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
Map<String, Object> mergedModel = this.createMergedOutputModel(model, request, response);
this.prepareResponse(request, response);
//处理视图
this.renderMergedOutputModel(mergedModel, this.getRequestToExpose(request), response);
}
处理视图
InternalResourceView 46 line
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
this.exposeModelAsRequestAttributes(model, request);
this.exposeHelpers(request);
//获取页面跳转路径 视图解析其实就是获取页面跳转的地址,然后去进行页面跳转
String dispatcherPath = this.prepareForRendering(request, response);
RequestDispatcher rd = this.getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
} else {
if (this.useInclude(request, response)) {
response.setContentType(this.getContentType());
rd.include(request, response);
} else {
//请求转发 这里也就是setvlet的forward方法
rd.forward(request, response);
}
}
}
这一块代码很繁杂,很乱,简单总结一下