/** * Write the given temporary OutputStream to the HTTP response. * @param response current HTTP response * @param baos the temporary OutputStream to write * @throws IOException if writing/flushing failed */ 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(); }
/** * Set static attributes as a CSV string. * Format is: attname0={value1},attname1={value1} * <p>"Static" attributes are fixed attributes that are specified in * the View instance configuration. "Dynamic" attributes, on the other hand, * are values passed in as part of the model. */ public void setAttributesCSV(@Nullable String propString) throws IllegalArgumentException { if (propString != null) { StringTokenizer st = new StringTokenizer(propString, ","); while (st.hasMoreTokens()) { String tok = st.nextToken(); int eqIdx = tok.indexOf('='); if (eqIdx == -1) { throw new IllegalArgumentException( "Expected '=' in attributes CSV string '" + propString + "'"); } if (eqIdx >= tok.length() - 2) { throw new IllegalArgumentException( "At least 2 characters ([]) required in attributes CSV string '" + propString + "'"); } String name = tok.substring(0, eqIdx); String value = tok.substring(eqIdx + 1); // Delete first and last characters of value: { and } value = value.substring(1); value = value.substring(0, value.length() - 1); addStaticAttribute(name, value); } } }
/** * Prepares the view given the specified model, merging it with static * attributes and a RequestContext attribute, if necessary. * Delegates to renderMergedOutputModel for the actual rendering. * @see #renderMergedOutputModel */ @Override public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { logger.debug("View " + formatViewName() + ", model " + (model != null ? model : Collections.emptyMap()) + (this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes)); } Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }
protected String formatViewName() { return (getBeanName() != null ? "name '" + getBeanName() + "'" : "[" + getClass().getSimpleName() + "]"); }
/** * Prepare the given response for rendering. * <p>The default implementation applies a workaround for an IE bug * when sending download content via HTTPS. * @param request current HTTP request * @param response current HTTP response */ protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) { if (generatesDownloadContent()) { response.setHeader("Pragma", "private"); response.setHeader("Cache-Control", "private, must-revalidate"); } }
/** * Create a RequestContext to expose under the specified attribute name. * <p>The default implementation creates a standard RequestContext instance for the * given request and model. Can be overridden in subclasses for custom instances. * @param request current HTTP request * @param model combined output Map (never {@code null}), * with dynamic values taking precedence over static attributes * @return the RequestContext instance * @see #setRequestContextAttribute * @see org.springframework.web.servlet.support.RequestContext */ protected RequestContext createRequestContext( HttpServletRequest request, HttpServletResponse response, Map<String, Object> model) { return new RequestContext(request, response, getServletContext(), model); }
/** * Get the request handle to expose to {@link #renderMergedOutputModel}, i.e. to the view. * <p>The default implementation wraps the original request for exposure of Spring beans * as request attributes (if demanded). * @param originalRequest the original servlet request as provided by the engine * @return the wrapped request, or the original request if no wrapping is necessary * @see #setExposeContextBeansAsAttributes * @see #setExposedContextBeanNames * @see org.springframework.web.context.support.ContextExposingHttpServletRequest */ protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) { if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null) { WebApplicationContext wac = getWebApplicationContext(); Assert.state(wac != null, "No WebApplicationContext"); return new ContextExposingHttpServletRequest(originalRequest, wac, this.exposedContextBeanNames); } return originalRequest; }
/** * Creates a combined output Map (never {@code null}) that includes dynamic values and static attributes. * Dynamic values take precedence over static attributes. */ protected Map<String, Object> createMergedOutputModel(@Nullable 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<>(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; }
protected String formatViewName() { return (getBeanName() != null ? "name '" + getBeanName() + "'" : "[" + getClass().getSimpleName() + "]"); }
/** * Prepare the given response for rendering. * <p>The default implementation applies a workaround for an IE bug * when sending download content via HTTPS. * @param request current HTTP request * @param response current HTTP response */ protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) { if (generatesDownloadContent()) { response.setHeader("Pragma", "private"); response.setHeader("Cache-Control", "private, must-revalidate"); } }
/** * Create a RequestContext to expose under the specified attribute name. * <p>The default implementation creates a standard RequestContext instance for the * given request and model. Can be overridden in subclasses for custom instances. * @param request current HTTP request * @param model combined output Map (never {@code null}), * with dynamic values taking precedence over static attributes * @return the RequestContext instance * @see #setRequestContextAttribute * @see org.springframework.web.servlet.support.RequestContext */ protected RequestContext createRequestContext( HttpServletRequest request, HttpServletResponse response, Map<String, Object> model) { return new RequestContext(request, response, getServletContext(), model); }
/** * Get the request handle to expose to {@link #renderMergedOutputModel}, i.e. to the view. * <p>The default implementation wraps the original request for exposure of Spring beans * as request attributes (if demanded). * @param originalRequest the original servlet request as provided by the engine * @return the wrapped request, or the original request if no wrapping is necessary * @see #setExposeContextBeansAsAttributes * @see #setExposedContextBeanNames * @see org.springframework.web.context.support.ContextExposingHttpServletRequest */ protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) { if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null) { WebApplicationContext wac = getWebApplicationContext(); Assert.state(wac != null, "No WebApplicationContext"); return new ContextExposingHttpServletRequest(originalRequest, wac, this.exposedContextBeanNames); } return originalRequest; }
/** * Creates a combined output Map (never {@code null}) that includes dynamic values and static attributes. * Dynamic values take precedence over static attributes. */ protected Map<String, Object> createMergedOutputModel(@Nullable 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<>(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; }
/** * Prepares the view given the specified model, merging it with static * attributes and a RequestContext attribute, if necessary. * Delegates to renderMergedOutputModel for the actual rendering. * @see #renderMergedOutputModel */ @Override public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { logger.debug("View " + formatViewName() + ", model " + (model != null ? model : Collections.emptyMap()) + (this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes)); } Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }
/** * Set the content type of the response to the configured * {@link #setContentType(String) content type} unless the * {@link View#SELECTED_CONTENT_TYPE} request attribute is present and set * to a concrete media type. */ 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()); } }
@Override public String toString() { StringBuilder sb = new StringBuilder(getClass().getName()); if (getBeanName() != null) { sb.append(": name '").append(getBeanName()).append("'"); } else { sb.append(": unnamed"); } return sb.toString(); }
/** * Set static attributes as a CSV string. * Format is: attname0={value1},attname1={value1} * <p>"Static" attributes are fixed attributes that are specified in * the View instance configuration. "Dynamic" attributes, on the other hand, * are values passed in as part of the model. */ public void setAttributesCSV(@Nullable String propString) throws IllegalArgumentException { if (propString != null) { StringTokenizer st = new StringTokenizer(propString, ","); while (st.hasMoreTokens()) { String tok = st.nextToken(); int eqIdx = tok.indexOf('='); if (eqIdx == -1) { throw new IllegalArgumentException( "Expected '=' in attributes CSV string '" + propString + "'"); } if (eqIdx >= tok.length() - 2) { throw new IllegalArgumentException( "At least 2 characters ([]) required in attributes CSV string '" + propString + "'"); } String name = tok.substring(0, eqIdx); String value = tok.substring(eqIdx + 1); // Delete first and last characters of value: { and } value = value.substring(1); value = value.substring(0, value.length() - 1); addStaticAttribute(name, value); } } }
/** * Prepare the given response for rendering. * <p>The default implementation applies a workaround for an IE bug * when sending download content via HTTPS. * @param request current HTTP request * @param response current HTTP response */ protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) { if (generatesDownloadContent()) { response.setHeader("Pragma", "private"); response.setHeader("Cache-Control", "private, must-revalidate"); } }
/** * Create a RequestContext to expose under the specified attribute name. * <p>The default implementation creates a standard RequestContext instance for the * given request and model. Can be overridden in subclasses for custom instances. * @param request current HTTP request * @param model combined output Map (never {@code null}), * with dynamic values taking precedence over static attributes * @return the RequestContext instance * @see #setRequestContextAttribute * @see org.springframework.web.servlet.support.RequestContext */ protected RequestContext createRequestContext( HttpServletRequest request, HttpServletResponse response, Map<String, Object> model) { return new RequestContext(request, response, getServletContext(), model); }
/** * Get the request handle to expose to {@link #renderMergedOutputModel}, i.e. to the view. * <p>The default implementation wraps the original request for exposure of Spring beans * as request attributes (if demanded). * @param originalRequest the original servlet request as provided by the engine * @return the wrapped request, or the original request if no wrapping is necessary * @see #setExposeContextBeansAsAttributes * @see #setExposedContextBeanNames * @see org.springframework.web.context.support.ContextExposingHttpServletRequest */ protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) { if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null) { return new ContextExposingHttpServletRequest( originalRequest, getWebApplicationContext(), this.exposedContextBeanNames); } return originalRequest; }