您的位置:首页 > 编程语言 > Java开发

SpringMVC响应结果的生成

2015-12-10 21:55 429 查看

SpringMVC响应结果的生成

前面的文章讲过,SpringMVC接收到来自客户端的请求,找到处理请求的Handler,然后构造适配器HandleAdapter。HandleAdapter处理请求后返回ModelAndView对象(也可能返回null)。以RequestMappingHandlerAdapter为例,看看ModelAndView是怎样生成的,它的invokeHandlerMethod方法用来处理请求,生成ModelAndView。
private ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response,
			HandlerMethod handlerMethod) throws Exception {
		
		ServletWebRequest webRequest = new ServletWebRequest(request, response);

		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
		ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

		requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
		modelFactory.updateModel(webRequest, mavContainer);

		if (mavContainer.isRequestHandled()) {
			return null;
		}
		else {
			ModelMap model = mavContainer.getModel();
			ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
			if (!mavContainer.isViewReference()) {
				mav.setView((View) mavContainer.getView());
			}
			if (model instanceof RedirectAttributes) {
				Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
			return mav;
		}
	}


它先创建一个ModelAndViewContainer对象,这个对象包含了请求的处理结果。然后根据ModelAndViewContainer的结果创建、设置ModelAndView。如果请求的结果已经发送到客户端了(比如直接向response的OutputStream写入返回数据)则返回null,否则利用view的名字或者view创建ModelAndView并返回。那么ModelAndViewContainer中的结果是如何被设置的呢?要看ServletInvocableHandlerMethod的invokeAndHandle方法:
public final void invokeAndHandle(
			NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		Object returnValue = invokeForRequest(request, mavContainer, providedArgs);

		setResponseStatus((ServletWebRequest) request);

		if (returnValue == null) {
			if (isRequestNotModified(request) || hasResponseStatus() || mavContainer.isRequestHandled()) {
				mavContainer.setRequestHandled(true);
				return;
			}
		}

		mavContainer.setRequestHandled(false);

		try {
			returnValueHandlers.handleReturnValue(returnValue, getReturnType(), mavContainer, request);
		} catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
			}
			throw ex;
		}
	}


下面我们详细分析一下这个方法,returnValue就是调用Controller方法的返回值,它可以是任意类型的值,但是并不意味着我们返回任何值,spring都能正确处理。具体我们可以返回哪些值,由returnValueHandlers决定。returnValueHandlers的设计采用了SpringMVC中随处可见的组合模式和策略模式。默认情况下,有如下的returnValueHandler:



根据名字可以推断,Controller方法可以直接返回ModelAndView,也可以返回view的名字等等。DispatcherServlet获取到ModelAndView之后需要解析出View对象,然后渲染这个View。
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.resolveLocale(request);
		response.setLocale(locale);

		View view;
		if (mv.isReference()) {
			// We need to resolve the view name.
			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 {
			// 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() + "'");
		}
		view.render(mv.getModelInternal(), request, response);
	}


一般情况下,ModelAndView并不包含View对象,而是包含View的名字。然后Spring在利用view的名字找到View对象,一般情况下即JstlView。今天先到这里,后续研究一下JSP的运行原理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: