SpringMVC响应结果的生成

来源:互联网 发布:好听有内涵的名字知乎 编辑:程序博客网 时间:2024/04/26 10:49

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的运行原理。
0 0
原创粉丝点击