说在前面

前期回顾

sharding-jdbc源码解析 更新完毕

spring源码解析 更新完毕

spring-mvc源码解析 更新完毕

spring-tx源码解析 更新完毕

spring-boot源码解析 更新完毕

rocketmq源码解析 更新完毕

dubbbo源码解析 更新完毕

netty源码解析 更新完毕

spring源码架构更新完毕

springmvc源码架构更新中

springboot源码架构计划中

github https://github.com/tianheframe

sharding-jdbc源码解析 更新完毕

rocketmq源码解析 更新完毕

seata 源码解析 更新完毕

dubbo 源码解析 更新完毕

netty 源码解析 更新完毕

源码解析

org.springframework.web.servlet.View 用于web交互的MVC视图。实现负责呈现内容和公开模型。单个视图公开多个模型属性。这个类和与之相关的MVC方法在Rod Johnson (Wrox, 2002)的专家一对一J2EE设计和开发的第12章中进行了讨论。视图实现可能差别很大。一个明显的实现是基于jsp的。其他实现可能是基于xsl的,或者使用HTML生成库。此接口旨在避免限制可能实现的范围。视图应该是bean。它们很可能被视图解析器实例化为bean。由于这个接口是无状态的,所以视图实现应该是线程安全的。

  String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";

包含响应状态代码的HttpServletRequest属性的名称。注意:并非所有视图实现都支持此属性。

  String PATH_VARIABLES = View.class.getName() + ".pathVariables";

HttpServletRequest属性的名称,该属性包含带有路径变量的映射。映射由基于字符串的URI模板变量名作为键及其对应的基于对象的值组成——从URL的片段中提取并转换类型。注意:并非所有视图实现都支持此属性。

  String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";

在内容协商期间选择的MediaType,它可能比视图配置的MediaType更具体。例如:“应用程序/盾。example-v1 + xml”和“应用程序/ * + xml”。

  String getContentType();

如果预先确定,返回视图的内容类型。可用于提前检查视图的内容类型,即在实际呈现尝试之前。

  void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;

呈现给定指定模型的视图。第一步是准备请求:在JSP中,这意味着将模型对象设置为请求属性。第二步是视图的实际呈现,例如通过RequestDispatcher包含JSP。

org.springframework.web.servlet.SmartView 提供关于视图的附加信息,如视图是否执行重定向。

  boolean isRedirectView();

是否是重定向视图

org.springframework.web.servlet.view.AbstractView 视图实现的抽象基类。子类应该是javabean,以便作为spring管理的bean实例进行方便的配置。

提供对视图可用的静态属性的支持,并提供多种方法来指定它们。静态属性将与每个呈现操作的给定动态属性(控制器返回的模型)合并。扩展WebApplicationObjectSupport,这将对某些视图有帮助。子类只需要实现实际的呈现。

  public static final String DEFAULT_CONTENT_TYPE = "text/html;charset=ISO-8859-1";

默认contentType

  private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 4096;

初始化输出数组大小

public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) {    this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes;  }

设置是否让应用程序上下文中的所有Spring bean都可以作为请求属性进行访问,方法是在属性被访问后进行惰性检查。这将使所有此类bean在普通${…}表达式,以及JSTL的c:out值表达式。默认设置是“假”。打开此标志以透明地公开request属性名称空间中的所有Spring bean。注意:上下文bean将覆盖手动添加的任何相同名称的自定义请求或会话属性。然而,相同名称的模型属性(如显式地公开给这个视图)总是会覆盖上下文bean。

public void setExposedContextBeanNames(String... exposedContextBeanNames) {    this.exposedContextBeanNames = new HashSet<String>(Arrays.asList(exposedContextBeanNames));  }

指定应该公开的上下文中bean的名称。如果这是非空的,只有指定的bean才有资格作为属性公开。如果您想在应用程序上下文中公开所有Spring bean,请打开“exposeContextBeansAsAttributes”标志,但不要为此属性列出特定的bean名称。

@Override  public void render(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);    renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);  }

准备给定指定模型的视图,必要时将其与静态属性和RequestContext属性合并。将实际呈现委托给renderMergedOutputModel。这里是模板方法实现

org.springframework.web.servlet.view.AbstractView#createMergedOutputModel 创建包含动态值和静态属性的组合输出映射(从不为空)。动态值优先于静态属性。

protected Map<String, Object> createMergedOutputModel(Map<String, ?> model, HttpServletRequest request,      HttpServletResponse response) {    @SuppressWarnings("unchecked")    Map<String, Object> pathVars = (this.exposePathVariables ?        (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);    // Consolidate static and dynamic model attributes.    int size = this.staticAttributes.size();    size += (model != null ? model.size() : 0);    size += (pathVars != null ? pathVars.size() : 0);    Map<String, Object> mergedModel = new LinkedHashMap<String, Object>(size);    mergedModel.putAll(this.staticAttributes);    if (pathVars != null) {      mergedModel.putAll(pathVars);    }    if (model != null) {      mergedModel.putAll(model);    }    // Expose RequestContext?    if (this.requestContextAttribute != null) {      mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));    }    return mergedModel;  }

org.springframework.web.servlet.view.AbstractView#createRequestContext 创建一个RequestContext,在指定的属性名下公开。默认实现为给定的请求和模型创建一个标准的RequestContext实例。可在自定义实例的子类中重写。

protected RequestContext createRequestContext(      HttpServletRequest request, HttpServletResponse response, Map<String, Object> model) {    return new RequestContext(request, response, getServletContext(), model);  }

org.springframework.web.servlet.view.AbstractView#prepareResponse 为呈现准备给定的响应。默认的实现在通过HTTPS发送下载内容时应用了IE bug的解决方案。

protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {    if (generatesDownloadContent()) {      response.setHeader("Pragma", "private");      response.setHeader("Cache-Control", "private, must-revalidate");    }  }

org.springframework.web.servlet.view.AbstractView#generatesDownloadContent 返回该视图是否生成下载内容(通常是PDF或Excel文件等二进制内容)。默认实现返回false。如果子类知道在客户端生成需要临时缓存的下载内容(通常是通过响应OutputStream),那么在这里鼓励它们返回true。

org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel 子类必须实现这个方法来实际呈现视图。第一步是准备请求:在JSP中,这意味着将模型对象设置为请求属性。第二步是视图的实际呈现,例如通过RequestDispatcher包含JSP。

org.springframework.web.servlet.view.AbstractView#exposeModelAsRequestAttributes 将给定映射中的模型对象公开为请求属性。名称将取自模型映射。此方法适用于javax.servlet.RequestDispatcher可访问的所有资源。

  protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {    for (Map.Entry<String, Object> entry : model.entrySet()) {      String modelName = entry.getKey();      Object modelValue = entry.getValue();      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() + "'");        }      }    }  }
protected ByteArrayOutputStream createTemporaryOutputStream() {    return new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);  }

为这个视图创建一个临时输出流。这通常用作IE解决方案,用于在实际将内容写入HTTP响应之前设置临时流的内容长度标头。

protected void writeToResponse(HttpServletResponse response, ByteArrayOutputStream baos) throws IOException {    // Write content type and also length (determined via byte array).    response.setContentType(getContentType());    response.setContentLength(baos.size());    // Flush byte array to servlet output stream.    ServletOutputStream out = response.getOutputStream();    baos.writeTo(out);    out.flush();  }

将给定的临时输出流写入HTTP响应。

protected void setResponseContentType(HttpServletRequest request, HttpServletResponse response) {    MediaType mediaType = (MediaType) request.getAttribute(View.SELECTED_CONTENT_TYPE);    if (mediaType != null && mediaType.isConcrete()) {      response.setContentType(mediaType.toString());    }    else {      response.setContentType(getContentType());    }  }

设置响应到配置的内容类型的内容类型,除非视图。出现SELECTED_CONTENT_TYPE请求属性,并将其设置为具体的媒体类型。

org.springframework.web.servlet.view.AbstractUrlBasedView 基于url视图的抽象基类。提供以“URL”bean属性的形式保存视图包装的URL的一致方式。

private String url;

url

@Override  public void afterPropertiesSet() throws Exception {    if (isUrlRequired() && getUrl() == null) {      throw new IllegalArgumentException("Property 'url' is required");    }  }

校验url

org.springframework.web.servlet.view.RedirectView 重定向到绝对URL、上下文相对URL或当前请求相对URL的视图。URL可能是URI模板,在这种情况下,URI模板变量将被模型中可用的值替换。默认情况下,所有基本模型属性(或其集合)都作为HTTP查询参数公开(假设它们没有用作URI模板变量),但是可以通过覆盖isEligibleProperty(String, Object)方法来更改这种行为。这个视图的URL应该是一个HTTP重定向URL,即适合HttpServletResponse的sendRedirect方法,如果HTTP 1.0标志是打开的,或者通过发送一个HTTP 303代码(如果HTTP 1.0兼容标志是关闭的)来重定向。注意,虽然“contextRelative”标志的默认值为off,但您可能希望几乎总是将其设置为true。当标志关闭时,以“/”开头的url被认为是相对于web服务器根的,而当标志打开时,它们被认为是相对于web应用程序根的。由于大多数web应用程序永远不会知道或关心它们的上下文路径实际上是什么,因此最好将此标志设置为true,并提交相对于web应用程序根目录的路径。在Portlet环境中使用此重定向视图时请注意:确保您的控制器遵守Portlet sendRedirect约束。

public void setExposePathVariables(boolean exposePathVariables) {    this.exposePathVariables = exposePathVariables;  }

指定是否向模型中添加路径变量。路径变量通常通过@PathVariable注释绑定到URI模板变量。它们实际上是URI模板变量,类型转换应用于它们以派生类型化的对象值。视图中经常需要这些值来构造指向相同url和其他url的链接。添加到模型中的路径变量覆盖静态属性(参见setAttributes(Properties)),但不覆盖模型中已经存在的属性。默认情况下,此标志设置为true。具体的视图类型可以覆盖它。

public void setContextRelative(boolean contextRelative) {    this.contextRelative = contextRelative;  }

设置是否将以斜杠("/")开头的给定URL解释为相对于当前ServletContext,即相对于web应用程序根目录的URL。默认值是“false”:以斜杠开头的URL将被解释为绝对的,即按原样接受。如果“true”,在这种情况下,上下文路径将在URL之前。

public void setHttp10Compatible(boolean http10Compatible) {    this.http10Compatible = http10Compatible;  }

sendRedirect设置是否与HTTP 1.0客户端保持兼容。在默认实现中,这将在任何情况下强制执行HTTP状态码302,即委托给HttpServletResponse.sendRedirect。关闭此选项将发送HTTP状态代码303,这是HTTP 1.1客户端的正确代码,但HTTP 1.0客户端不能理解。许多HTTP 1.1客户端对待302就像对待303一样,没有任何区别。但是,有些客户端在POST请求后重定向时依赖于303;在这种情况下,关闭此标志。

public void setExposeModelAttributes(final boolean exposeModelAttributes) {    this.exposeModelAttributes = exposeModelAttributes;  }

设置说明文属性标志,它表示模型属性是否应该作为HTTP查询参数公开。默认值为true。

public void setExpandUriTemplateVariables(boolean expandUriTemplateVariables) {    this.expandUriTemplateVariables = expandUriTemplateVariables;  }

是否将重定向URL视为URI模板。如果重定向URL包含左花括号“{”和右花括号“}”,并且不希望它们被解释为URI变量,则将此标志设置为false。默认值为true。

public void setPropagateQueryParams(boolean propagateQueryParams) {    this.propagateQueryParams = propagateQueryParams;  }

当设置为true时,将追加当前URL的查询字符串,从而传播到重定向的URL。默认值为false。

@Override  public boolean isRedirectView() {    return true;  }

返回“true”,指示此视图执行重定向。

@Override  protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,      HttpServletResponse response) throws IOException {//    创建url    String targetUrl = createTargetUrl(model, request);//    更新url    targetUrl = updateTargetUrl(targetUrl, model, request, response);    FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);    if (!CollectionUtils.isEmpty(flashMap)) {      UriComponents uriComponents = UriComponentsBuilder.fromUriString(targetUrl).build();      flashMap.setTargetRequestPath(uriComponents.getPath());      flashMap.addTargetRequestParams(uriComponents.getQueryParams());      FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);      if (flashMapManager == null) {        throw new IllegalStateException("FlashMapManager not found despite output FlashMap having been set");      }      flashMapManager.saveOutputFlashMap(flashMap, request, response);    }//    重定向    sendRedirect(request, response, targetUrl, this.http10Compatible);  }

将模型转换为请求参数并重定向到给定的URL。

org.springframework.web.servlet.view.RedirectView#createTargetUrl 首先检查重定向字符串是否是URI模板,然后使用给定的模型展开它,然后可选地添加简单类型模型属性作为查询字符串参数,从而创建目标URL。

  protected final String createTargetUrl(Map<String, Object> model, HttpServletRequest request)      throws UnsupportedEncodingException {    // Prepare target URL.    StringBuilder targetUrl = new StringBuilder();    if (this.contextRelative && getUrl().startsWith("/")) {      // Do not apply context path to relative URLs.      targetUrl.append(getContextPath(request));    }    targetUrl.append(getUrl());    String enc = this.encodingScheme;    if (enc == null) {      enc = request.getCharacterEncoding();    }    if (enc == null) {      enc = WebUtils.DEFAULT_CHARACTER_ENCODING;    }    if (this.expandUriTemplateVariables && StringUtils.hasText(targetUrl)) {      Map<String, String> variables = getCurrentRequestUriVariables(request);      targetUrl = replaceUriTemplateVariables(targetUrl.toString(), model, variables, enc);    }    if (isPropagateQueryProperties()) {       appendCurrentQueryParams(targetUrl, request);    }    if (this.exposeModelAttributes) {      appendQueryProperties(targetUrl, model, enc);    }    return targetUrl.toString();  }

org.springframework.web.servlet.view.RedirectView#updateTargetUrl 找到注册的RequestDataValueProcessor(如果有的话),并允许它更新重定向目标URL。

protected String updateTargetUrl(String targetUrl, Map<String, Object> model,      HttpServletRequest request, HttpServletResponse response) {    WebApplicationContext wac = getWebApplicationContext();    if (wac == null) {      wac = RequestContextUtils.findWebApplicationContext(request, getServletContext());    }    if (wac != null && wac.containsBean(RequestContextUtils.REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME)) {      RequestDataValueProcessor processor = wac.getBean(          RequestContextUtils.REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME, RequestDataValueProcessor.class);      return processor.processUrl(request, targetUrl);    }    return targetUrl;  }

org.springframework.web.servlet.view.RedirectView#sendRedirect 将重定向发送回HTTP客户机

protected void sendRedirect(HttpServletRequest request, HttpServletResponse response,      String targetUrl, boolean http10Compatible) throws IOException {    String encodedURL = (isRemoteHost(targetUrl) ? targetUrl : response.encodeRedirectURL(targetUrl));    if (http10Compatible) {      HttpStatus attributeStatusCode = (HttpStatus) request.getAttribute(View.RESPONSE_STATUS_ATTRIBUTE);      if (this.statusCode != null) {        response.setStatus(this.statusCode.value());        response.setHeader("Location", encodedURL);      }      else if (attributeStatusCode != null) {        response.setStatus(attributeStatusCode.value());        response.setHeader("Location", encodedURL);      }      else {        // Send status code 302 by default. 执行response.sendRedirect重定向        response.sendRedirect(encodedURL);      }    }    else {      HttpStatus statusCode = getHttp11StatusCode(request, response, targetUrl);      response.setStatus(statusCode.value());      response.setHeader("Location", encodedURL);    }  }

org.springframework.web.servlet.view.document.AbstractPdfStamperView 抽象超类,用于对具有AcroForm的现有文档进行操作的PDF视图。特定于应用程序的视图类将扩展这个类以合并PDF表单和模型数据。这个视图实现使用Bruno Lowagie的iText API。已知可以使用原始的iText 2.1.7及其分支OpenPDF。我们强烈推荐OpenPDF,因为它是积极维护的,并且修复了不可信PDF内容的一个重要漏洞。

public AbstractPdfStamperView(){    setContentType("application/pdf");  }

创建AbstractPdfStamperView,设置contentType=application/pdf

@Override  protected final void renderMergedOutputModel(      Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {    // IE workaround: write into byte array first.创建输出流    ByteArrayOutputStream baos = createTemporaryOutputStream();    PdfReader reader = readPdfResource();    PdfStamper stamper = new PdfStamper(reader, baos);//    模板方法    mergePdfDocument(model, stamper, request, response);    stamper.close();    // Flush to HTTP response.    writeToResponse(response, baos);  }

渲染输出model

org.springframework.web.servlet.view.AbstractView#createTemporaryOutputStream 为这个视图创建一个临时输出流。这通常用作IE解决方案,用于在实际将内容写入HTTP响应之前设置临时流的内容长度标头。

protected ByteArrayOutputStream createTemporaryOutputStream() {    return new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE);  }

org.springframework.web.servlet.view.document.AbstractPdfStamperView#mergePdfDocument 子类必须实现此方法来将PDF表单与给定的模型数据合并。这是您可以在AcroForm上设置值的地方。在这一级可以做的一个例子是:请注意,传入的HTTP响应只用于设置cookie或其他HTTP报头。在此方法返回后,构建的PDF文档本身将自动写入响应。

protected abstract void mergePdfDocument(Map<String, Object> model, PdfStamper stamper,      HttpServletRequest request, HttpServletResponse response) throws Exception;

org.springframework.web.servlet.view.AbstractView#writeToResponse 将给定的临时输出流写入HTTP响应。

protected void writeToResponse(HttpServletResponse response, ByteArrayOutputStream baos) throws IOException {    // Write content type and also length (determined via byte array).    response.setContentType(getContentType());    response.setContentLength(baos.size());    // Flush byte array to servlet output stream.    ServletOutputStream out = response.getOutputStream();    baos.writeTo(out);    out.flush();  }

org.springframework.web.servlet.view.InternalResourceView 同一web应用程序中JSP或其他资源的包装器。将模型对象公开为请求属性,并使用RequestDispatcher将请求转发到指定的资源URL。这个视图的URL应该指定web应用程序中的一个资源,该资源适合RequestDispatcher的转发或包含方法。

如果在已包含的请求或已提交的响应中操作,该视图将退回到包含而不是转发。这可以通过在呈现视图之前调用response. flushbuffer()(它将提交响应)来实现。

public void setAlwaysInclude(boolean alwaysInclude) {        this.alwaysInclude = alwaysInclude;    }

指定是否总是包含视图而不是转发视图。默认设置是“假”。打开此标志以强制使用Servlet include,即使可能使用转发。

public void setPreventDispatchLoop(boolean preventDispatchLoop) {        this.preventDispatchLoop = preventDispatchLoop;    }

设置是否显式防止分派回当前处理程序路径。默认设置是“假”。对于基于约定的视图,将其切换为“true”,其中将分派回当前处理程序路径是一个确定的错误。

@Override    protected void renderMergedOutputModel(            Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {        // Expose the model object as request attributes.将模型对象公开为请求属性。        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. 如果include请求就执行,否则就转发        if (useInclude(request, response)) {            response.setContentType(getContentType());            if (logger.isDebugEnabled()) {                logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");            }//          执行include            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);        }    }

根据指定的模型呈现内部资源。这包括将模型设置为请求属性。这里是模板方法实现,如果inlude请求执行include请求,如果是forward执行请求转发

org.springframework.web.servlet.view.AbstractView#exposeModelAsRequestAttributes 将给定映射中的模型对象公开为请求属性。名称将取自模型映射。此方法适用于javax.servlet.RequestDispatcher可访问的所有资源。

  protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {        for (Map.Entry<String, Object> entry : model.entrySet()) {            String modelName = entry.getKey();            Object modelValue = entry.getValue();            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() + "'");                }            }        }    }

org.springframework.web.servlet.view.InternalResourceView#exposeHelpers 公开每个呈现操作唯一的助手。这是必要的,这样不同的呈现操作就不会覆盖彼此的上下文等等。由renderMergedOutputModel(Map, HttpServletRequest, HttpServletResponse)调用。默认实现为空。可以重写此方法,以将自定义助手添加为请求属性。

protected void exposeHelpers(HttpServletRequest request) throws Exception {    }

org.springframework.web.servlet.view.InternalResourceView#prepareForRendering 准备呈现,并确定转发(或包含)的请求分派器路径。此实现仅返回配置的URL。子类可以覆盖它以确定要呈现的资源,通常以不同的方式解释URL。

protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response)            throws Exception {        String path = getUrl();        if (this.preventDispatchLoop) {            String uri = request.getRequestURI();            if (path.startsWith("/") ? uri.equals(path) : uri.equals(StringUtils.applyRelativePath(uri, path))) {                throw new ServletException("Circular view path [" + path + "]: would dispatch back " +                        "to the current handler URL [" + uri + "] again. Check your ViewResolver setup! " +                        "(Hint: This may be the result of an unspecified view, due to default view name generation.)");            }        }        return path;    }

org.springframework.web.servlet.view.InternalResourceView#getRequestDispatcher 获取用于转发/包含的RequestDispatcher。默认实现只是调用HttpServletRequest.getRequestDispatcher(字符串)。可以在子类中重写。

protected RequestDispatcher getRequestDispatcher(HttpServletRequest request, String path) {        return request.getRequestDispatcher(path);    }
protected boolean useInclude(HttpServletRequest request, HttpServletResponse response) {        return (this.alwaysInclude || WebUtils.isIncludeRequest(request) || response.isCommitted());    }

确定是使用RequestDispatcher的include方法还是转发方法。执行检查请求中是否找到包含URI属性,指示包含请求,以及响应是否已经提交。在这两种情况下,都将执行include,因为转发不再可能。

org.springframework.web.util.WebUtils#isIncludeRequest 确定给定的请求是否是包含请求,即不是来自外部的顶级HTTP请求。检查“javax.servlet.include”的存在。request_uri”请求属性。可以检查仅出现在包含请求中的任何请求属性。

public static boolean isIncludeRequest(ServletRequest request) {    return (request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE) != null);  }

org.springframework.web.servlet.view.JstlView JSTL页面的InternalResourceView的专门化,即使用JSP标准标记库的JSP页面。使用Spring的区域设置和MessageSource公开特定于JSTL的请求属性,这些属性指定JSTL的格式化和消息标记的区域设置和资源包。

org.springframework.web.servlet.view.AbstractTemplateView 用于基于模板的视图技术(如Velocity和FreeMarker)的适配器基类,可以在模型中使用请求和会话属性,还可以为Spring的Velocity/FreeMarker宏库公开助手对象。JSP/JSTL和其他视图技术自动访问HttpServletRequest对象,从而访问当前用户的请求/会话属性。此外,它们还能够创建帮助对象并将其缓存为请求属性本身。

public void setExposeRequestAttributes(boolean exposeRequestAttributes) {    this.exposeRequestAttributes = exposeRequestAttributes;  }

设置是否应该在与模板合并之前将所有请求属性添加到模型中。默认设置是“假”。

public void setAllowRequestOverride(boolean allowRequestOverride) {    this.allowRequestOverride = allowRequestOverride;  }

设置是否允许HttpServletRequest属性覆盖(隐藏)控制器生成的同名模型属性。默认值是“false”,如果发现与模型属性同名的请求属性,将引发异常。

public void setExposeSessionAttributes(boolean exposeSessionAttributes) {    this.exposeSessionAttributes = exposeSessionAttributes;  }

设置是否应该在与模板合并之前将所有HttpSession属性添加到模型中。默认设置是“假”

public void setAllowSessionOverride(boolean allowSessionOverride) {    this.allowSessionOverride = allowSessionOverride;  }

设置是否允许HttpSession属性覆盖(隐藏)控制器生成的同名模型属性。默认值是“false”,如果发现与模型属性同名的会话属性,将引发异常。

public void setExposeSpringMacroHelpers(boolean exposeSpringMacroHelpers) {    this.exposeSpringMacroHelpers = exposeSpringMacroHelpers;  }

设置是否以“springMacroRequestContext”的名称公开一个RequestContext以供Spring的宏库使用。默认设置是“真实的”。目前需要为Spring的Velocity和FreeMarker默认宏。注意,对于使用HTML表单的模板,这不是必需的,除非您希望利用Spring helper宏。

@Override  protected final void renderMergedOutputModel(      Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {    if (this.exposeRequestAttributes) {      for (Enumeration<String> en = request.getAttributeNames(); en.hasMoreElements();) {        String attribute = en.nextElement();        if (model.containsKey(attribute) && !this.allowRequestOverride) {          throw new ServletException("Cannot expose request attribute '" + attribute +            "' because of an existing model object of the same name");        }        Object attributeValue = request.getAttribute(attribute);        if (logger.isDebugEnabled()) {          logger.debug("Exposing request attribute '" + attribute +              "' with value [" + attributeValue + "] to model");        }        model.put(attribute, attributeValue);      }    }    if (this.exposeSessionAttributes) {      HttpSession session = request.getSession(false);      if (session != null) {        for (Enumeration<String> en = session.getAttributeNames(); en.hasMoreElements();) {          String attribute = en.nextElement();          if (model.containsKey(attribute) && !this.allowSessionOverride) {            throw new ServletException("Cannot expose session attribute '" + attribute +              "' because of an existing model object of the same name");          }          Object attributeValue = session.getAttribute(attribute);          if (logger.isDebugEnabled()) {            logger.debug("Exposing session attribute '" + attribute +                "' with value [" + attributeValue + "] to model");          }          model.put(attribute, attributeValue);        }      }    }    if (this.exposeSpringMacroHelpers) {      if (model.containsKey(SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE)) {        throw new ServletException(            "Cannot expose bind macro helper '" + SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE +            "' because of an existing model object of the same name");      }      // Expose RequestContext instance for Spring macros.      model.put(SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE,          new RequestContext(request, response, getServletContext(), model));    }    applyContentType(response);//    模板方法    renderMergedTemplateModel(model, request, response);  }

渲染输出model,这里是模板方法实现,org.springframework.web.servlet.view.AbstractTemplateView#applyContentType 将“contentType”bean属性中指定的视图内容类型应用于给定的响应。只有在响应上没有设置内容类型的情况下,才应用视图的contentType。这允许处理程序预先覆盖默认的内容类型。

protected void applyContentType(HttpServletResponse response)  {    if (response.getContentType() == null) {      response.setContentType(getContentType());    }  }

org.springframework.web.servlet.view.AbstractTemplateView#renderMergedTemplateModel 子类必须实现这个方法来实际呈现视图。

protected abstract void renderMergedTemplateModel(      Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;

org.springframework.web.servlet.view.freemarker.FreeMarkerView 使用FreeMarker模板引擎查看。

公开以下JavaBean属性:url:要包装的FreeMarker模板相对于FreeMarker模板上下文(目录)的位置。编码(可选,默认由FreeMarker配置决定):FreeMarker模板文件的编码,依赖于一个单独的FreeMarkerConfig对象,例如FreeMarkerConfigurer,可以在当前web应用程序上下文中使用任何bean名称进行访问。或者,您可以将FreeMarker配置对象设置为bean属性。注意:Spring对FreeMarker的支持要求FreeMarker 2.3或更高。

private String encoding;

encoding

@Override  protected void initServletContext(ServletContext servletContext) throws BeansException {    if (getConfiguration() != null) {      this.taglibFactory = new TaglibFactory(servletContext);    }    else {      FreeMarkerConfig config = autodetectConfiguration();      setConfiguration(config.getConfiguration());      this.taglibFactory = config.getTaglibFactory();    }    GenericServlet servlet = new GenericServletAdapter();    try {//      初始化servlet      servlet.init(new DelegatingServletConfig());    }    catch (ServletException ex) {      throw new BeanInitializationException("Initialization of GenericServlet adapter failed", ex);    }    this.servletContextHashModel = new ServletContextHashModel(servlet, getObjectWrapper());  }

在启动时调用。查找单个FreeMarkerConfig bean以查找此工厂的相关配置。检查是否可以找到默认语言环境的模板:如果没有找到特定于语言环境的模板,FreeMarker将检查非特定于语言环境的模板。

@Override  protected void renderMergedTemplateModel(      Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {    exposeHelpers(model, request);    doRender(model, request, response);  }

通过将模型映射与FreeMarker模板合并来处理它。输出被定向到servlet响应。如果需要自定义行为,可以重写此方法。

  @Override  protected void renderMergedTemplateModel(      Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {    exposeHelpers(model, request);//    渲染模型    doRender(model, request, response);  }

org.springframework.web.servlet.view.freemarker.FreeMarkerView#exposeHelpers 公开每个呈现操作唯一的助手。这是必要的,以便不同的呈现操作不会覆盖彼此的格式等。叫renderMergedTemplateModel。默认实现为空。可以重写此方法以向模型中添加自定义助手。

protected void exposeHelpers(Map<String, Object> model, HttpServletRequest request) throws Exception {  }

org.springframework.web.servlet.view.freemarker.FreeMarkerView#doRender 使用包含要使用的完整模板模型的给定模型映射,将FreeMarker视图呈现给给定的响应。默认实现呈现由“url”bean属性指定的模板,该属性通过getTemplate检索。它委托processTemplate方法将模板实例与给定的模板模型合并。将标准的Freemarker散列模型添加到模型中:请求参数、请求、会话和应用程序(ServletContext),以及JSP标记库散列模型。可以重写以自定义行为,例如将多个模板呈现到单个视图中。

protected void doRender(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {    // Expose model to JSP tags (as request attributes). 解析请求参数    exposeModelAsRequestAttributes(model, request);    // Expose all standard FreeMarker hash models. 构建模板模型    SimpleHash fmModel = buildTemplateModel(model, request, response);    if (logger.isDebugEnabled()) {      logger.debug("Rendering FreeMarker template [" + getUrl() + "] in FreeMarkerView '" + getBeanName() + "'");    }    // Grab the locale-specific version of the template.    Locale locale = RequestContextUtils.getLocale(request);//    处理模板    processTemplate(getTemplate(locale), fmModel, response);  }

org.springframework.web.servlet.view.json.AbstractJackson2View 抽象基类,用于基于Jackson和内容类型独立的AbstractView实现。

private ObjectMapper objectMapper;

objectMapper

@Override  protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {    setResponseContentType(request, response);    response.setCharacterEncoding(this.encoding.getJavaName());    if (this.disableCaching) {      response.addHeader("Cache-Control", "no-store");    }  }

设置响应contentType、缓存相关header

  @Override  protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,      HttpServletResponse response) throws Exception {    OutputStream stream = (this.updateContentLength ? createTemporaryOutputStream() : response.getOutputStream());    Object value = filterAndWrapModel(model, request);    writeContent(stream, value);    if (this.updateContentLength) {      writeToResponse(response, (ByteArrayOutputStream) stream);    }  }

渲染输出model

org.springframework.web.servlet.view.xml.MappingJackson2XmlView Spring MVC视图,通过使用Jackson 2的XmlMapper序列化当前请求的模型来呈现XML内容。要序列化的对象作为模型中的参数提供。使用第一个可序列化条目。用户可以通过sourceKey属性在模型中指定一个特定的条目。默认构造函数使用Jackson2ObjectMapperBuilder提供的默认配置。

public static final String DEFAULT_CONTENT_TYPE = "application/xml";

默认contentType

  @Override  protected Object filterModel(Map model) {    Object value = null;    if (this.modelKey != null) {      value = model.get(this.modelKey);      if (value == null) {        throw new IllegalStateException(            "Model contains no object with key [" + this.modelKey + "]");      }    }    else {      for (Map.Entry entry : model.entrySet()) {        if (!(entry.getValue() instanceof BindingResult) && !entry.getKey().equals(JsonView.class.getName())) {          if (value != null) {            throw new IllegalStateException("Model contains more than one object to render, only one is supported");          }          value = entry.getValue();        }      }    }    return value;  }

解析json model

org.springframework.web.servlet.view.json.MappingJackson2JsonView Spring MVC视图,通过使用Jackson 2的ObjectMapper序列化当前请求的模型来呈现JSON内容。默认情况下,模型映射的整个内容(框架特定类除外)将被编码为JSON。如果模型只包含一个键,您可以通过setExtractValueFromSingleKeyModel将其提取编码为JSON。默认构造函数使用Jackson2ObjectMapperBuilder提供的默认配置。

public static final String DEFAULT_CONTENT_TYPE = "application/json";

默认内容类型:“application/json”。通过setContentType重写的。

public void setExtractValueFromSingleKeyModel(boolean extractValueFromSingleKeyModel) {    this.extractValueFromSingleKeyModel = extractValueFromSingleKeyModel;  }

设置是将包含单个属性的模型序列化为映射,还是从模型中提取单个值并直接序列化它。设置此标志的效果类似于使用带有@ResponseBody请求处理方法的MappingJackson2HttpMessageConverter。默认的是假的

org.springframework.web.servlet.view.xml.MarshallingView 允许响应上下文作为编组器编组的结果呈现的Spring-MVC视图。将编组的对象作为模型中的参数提供,然后在响应呈现期间检测。用户可以通过sourceKey属性在模型中指定一个特定的条目,或者让Spring定位源对象。

public static final String DEFAULT_CONTENT_TYPE = "application/xml";

默认contentType

private Marshaller marshaller;

marshaller

@Override  protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,      HttpServletResponse response) throws Exception {    Object toBeMarshalled = locateToBeMarshalled(model);    if (toBeMarshalled == null) {      throw new IllegalStateException("Unable to locate object to be marshalled in model: " + model);    }    ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);    this.marshaller.marshal(toBeMarshalled, new StreamResult(baos));    setResponseContentType(request, response);    response.setContentLength(baos.size());    baos.writeTo(response.getOutputStream());  }

渲染输出model

org.springframework.web.servlet.view.document.AbstractXlsView 方便的超类,用于传统XLS格式的Excel文档视图。兼容Apache POI 3.5及更高版本。

  public AbstractXlsView() {    setContentType("application/vnd.ms-excel");  }

设置contentType=application/vnd.ms-excel

@Override  protected final void renderMergedOutputModel(      Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {    // Create a fresh workbook instance for this render step.    Workbook workbook = createWorkbook(model, request);    // Delegate to application-provided document code.模板方法    buildExcelDocument(model, workbook, request, response);    // Set the content type.    response.setContentType(getContentType());    // Flush byte array to servlet output stream.    renderWorkbook(workbook, response);  }

渲染视图model,这里是模板方法实现,org.springframework.web.servlet.view.document.AbstractXlsView#buildExcelDocument 给定模型,应用程序提供的子类必须实现此方法来填充Excel工作簿文档。

protected abstract void buildExcelDocument(      Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response)      throws Exception;

org.springframework.web.servlet.view.document.AbstractXlsxView Office 2007 XLSX格式(由POI-OOXML支持)中Excel文档视图的方便超类。兼容Apache POI 3.5及更高版本。

public AbstractXlsxView() {    setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");  }

设置contentType=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

org.springframework.web.servlet.view.document.AbstractXlsxStreamingView  Office 2007 XLSX格式的Excel文档视图,使用POI的流媒体变体,方便的超类。兼容Apache POI 3.9及更高版本。

org.springframework.web.servlet.view.document.AbstractPdfView PDF视图的抽象超类。特定于应用程序的视图类将扩展这个类。视图将保存在子类本身中,而不是在模板中。这个视图实现使用Bruno Lowagie的iText API。已知可以使用原始的iText 2.1.7及其分支OpenPDF。我们强烈推荐OpenPDF,因为它是积极维护的,并且修复了不可信PDF内容的一个重要漏洞。注:Internet Explorer需要一个"。扩展,因为它并不总是尊重声明的内容类型。

public AbstractPdfView() {    setContentType("application/pdf");  }

此构造函数设置适当的内容类型“application/pdf”。请注意,IE不会注意到这一点,但我们对此无能为力。生成的文档应该有一个“”。pdf”扩展。

@Override  protected final void renderMergedOutputModel(      Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {    // IE workaround: write into byte array first.IE工作区:写入字节数组第一。    ByteArrayOutputStream baos = createTemporaryOutputStream();    // Apply preferences and build metadata.    Document document = newDocument();    PdfWriter writer = newWriter(document, baos);    prepareWriter(model, writer, request);//    模板方法    buildPdfMetadata(model, document, request);    // Build PDF document.    document.open();//    模板方法    buildPdfDocument(model, document, writer, request, response);    document.close();    // Flush to HTTP response.    writeToResponse(response, baos);  }

渲染输出model,这里是模板方法实现。org.springframework.web.servlet.view.document.AbstractPdfView#buildPdfMetadata 填充iText文档的元字段(作者、标题等)。默认值是一个空实现。子类可以重写此方法来添加元字段,如标题、主题、作者、创建者、关键字等。此方法在将PdfWriter分配给文档后调用,并在调用Document .open()之前调用。

protected void buildPdfMetadata(Map<String, Object> model, Document document, HttpServletRequest request) {  }

org.springframework.web.servlet.view.document.AbstractPdfView#buildPdfDocument 子类必须实现此方法来构建给定模型的iText PDF文档。在Document.open()和Document.close()调用之间调用。请注意,传入的HTTP响应只用于设置cookie或其他HTTP报头。在此方法返回后,构建的PDF文档本身将自动写入响应。

protected abstract void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer,      HttpServletRequest request, HttpServletResponse response) throws Exception;

org.springframework.web.servlet.view.AbstractView#writeToResponse 将给定的临时输出流写入HTTP响应。

protected void writeToResponse(HttpServletResponse response, ByteArrayOutputStream baos) throws IOException {    // Write content type and also length (determined via byte array).    response.setContentType(getContentType());    response.setContentLength(baos.size());    // Flush byte array to servlet output stream.    ServletOutputStream out = response.getOutputStream();    baos.writeTo(out);    out.flush();  }

说在最后

本次解析仅代表个人观点,仅供参考。

扫码进入技术微信群

钉钉技术群

qq技术群

yolov3之pytorch源码解析_springmvc源码架构解析之view相关推荐

  1. k8s源码分析 pdf_rook源码分析之一:rook架构解析

    rook简介 Rook是一款云原生环境下的开源分布式存储编排系统,目前支持 Ceph.NFS.Edegefs.Cassandra.CockroachDB等存储系统.它实现了一个自动管理的.自动扩容的. ...

  2. java mvc 源码分析_SpringMVC 源码解读笔记

    MVC 模式早已被大家熟知,多多少少大家都接触过一些MVC的框架比如stuts,webwork,springmvc,当我们谈论到MVC时其实就是了解他的这种分层理念,职责清晰化,抛弃了原来的混合开发模 ...

  3. NVIDIA VPI架构解析

    VPI 架构解析 文章目录 VPI 架构解析 概述 支持的平台 算法 算法负载 无负载算法 后端 CPU CUDA PVA VIC NVENC OFA 流 缓冲器 Images 图像视图 锁 图像格式 ...

  4. wireshark协议解析器 源码分析 封装调用

    源码分析 Wireshark启动时,所有解析器进行初始化和注册.要注册的信息包括协议名称.各个字段的信息.过滤用的关键字.要关联的下层协议与端口(handoff)等.在解析过程,每个解析器负责解析自己 ...

  5. japidocs怎么设置参数必填_JApiDocs 动态生成接口文档,并解析java 源码中的注释...

    1.介绍 JApiDocs 是一个符合 Java 编程习惯的 Api 文档生成工具.最大程度地利用 Java 的语法特性,你只管用心设计好接口,添加必要的注释,JApiDocs 会帮你导出一份漂亮的 ...

  6. dubbo源码深度解析_Spring源码深度解析:手把手教你搭建Spring开发环境

    Spring环境搭建流程,如果是第一次接触spring源码的环境搭建,确实还是比较麻烦的. 作者使用的编译器为目前流行的lntelliJ IDEA,版本为2018旗舰版.Eclipse用户还需要自己揣 ...

  7. Uboot中start.S源码的指令级的详尽解析 在线版

    http://bbs.chinaunix.net/thread-2312785-1-1.html 以后所有内容更新,都放在这里: Uboot中start.S源码的指令级的详尽解析 在线版 Uboot ...

  8. Spring源码解析:自定义标签的解析过程

    2019独角兽企业重金招聘Python工程师标准>>> spring version : 4.3.x Spring 中的标签分为默认标签和自定义标签两类,上一篇我们探究了默认标签的解 ...

  9. Uboot中start.S源码的指令级的详尽解析(转)

    Uboot中start.S源码的指令级的详尽解析 转载于:https://www.cnblogs.com/LittleTiger/p/10877516.html

最新文章

  1. 电脑退出全屏按哪个键_一款轻量级的电脑看图软件
  2. linux中xargs用法,Linux中xargs的用法
  3. ActiveMQ结合Spring收发消息
  4. 设计模式之_工厂系列_01
  5. 测试C语言malloc申请内存不释放结果
  6. Node.js Performance
  7. QueryDSL中包含通配符的字符串的精确匹配
  8. SQL Server 2019中的证书管理
  9. python动态页面元素爬取_python动态爬取网页
  10. Java VS Go,微服务究竟谁更快?
  11. BatchPreparedStatementSetter,用法
  12. 目前软件分析设计过程中的主要问题
  13. 知云文献翻译出现乱码的解决方式
  14. Charles mac版本进行https抓包的配置方法
  15. win10更改无线网卡的MAC地址
  16. 计算机考试的话语,为考试加油的暖心句子 期末考试加油鼓励的话
  17. latex表格水平垂直居中
  18. sql 排名前十_“一流大学”最新排名:浙大第三,复旦无缘前十,榜首无人撼动...
  19. HRM人力资源管理平台
  20. 解决Centos 7 下 tomcat字体异常 Font '宋体' is not available to the JVM

热门文章

  1. java 权限url权限_SpringBootSecurity学习(11)网页版登录之URL动态权限
  2. C++ MFC string转Cstring为什么会乱码
  3. Windows、Linux和MAC的CR, LF, CR/LF换行符
  4. 计算机网络流量图阅读与理解,计算机网络流量监控的设计与实现
  5. 干货|训练神经网络时要知道的几个要点
  6. Python应用实战-Clumper | dplyr式的Python数据操作包
  7. 异想维度 java_Java实现多字段(维度)复杂排序
  8. 正则表达式贪婪与非贪婪模式
  9. 一个Web前端自学者的自述
  10. 点击文本框后页面变大