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的运行原理。
相关文章推荐
- java解惑--谜题13:畜牧场
- java解惑--谜题12:ABC
- 取出json解析出来的对象列表的元素时报错java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be
- JAVA爬取亚马逊的商品信息
- Java虚拟机 堆和栈
- java中的异常处理
- java解惑--谜题11:最后的笑声
- JAVA sprintMVC maven搭建
- java解惑--谜题10:八两
- Java之数据类型、变量和数组
- java基础第四天——数组
- 第二个spring,第五天
- 第三篇 Java类文件结构
- JAVA中JDK与JRE的区别
- java解惑--谜题9:半斤
- MyBatis快捷键提示怎么调出来
- Java&Xml教程(四)使用DOM方式生成XML文件
- Java&Xml教程(四)使用DOM方式生成XML文件
- Java&Xml教程(四)使用DOM方式生成XML文件
- SpringMVC+Hibernate4 导致事务失效不提交的可能原因