/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet.view;

import java.util.Map;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;

Wrapper for a JSP or other resource within the same web application. Exposes model objects as request attributes and forwards the request to the specified resource URL using a RequestDispatcher.

A URL for this view is supposed to specify a resource within the web application, suitable for RequestDispatcher's forward or include method.

If operating within an already included request or within a response that has already been committed, this view will fall back to an include instead of a forward. This can be enforced by calling response.flushBuffer() (which will commit the response) before rendering the view.

Typical usage with InternalResourceViewResolver looks as follows, from the perspective of the DispatcherServlet context definition:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/jsp/"/>
  <property name="suffix" value=".jsp"/>
</bean>
Every view name returned from a handler will be translated to a JSP resource (for example: "myView" -> "/WEB-INF/jsp/myView.jsp"), using this view class by default.
Author:Rod Johnson, Juergen Hoeller, Rob Harrop
See Also:
/** * Wrapper for a JSP or other resource within the same web application. * Exposes model objects as request attributes and forwards the request to * the specified resource URL using a {@link javax.servlet.RequestDispatcher}. * * <p>A URL for this view is supposed to specify a resource within the web * application, suitable for RequestDispatcher's {@code forward} or * {@code include} method. * * <p>If operating within an already included request or within a response that * has already been committed, this view will fall back to an include instead of * a forward. This can be enforced by calling {@code response.flushBuffer()} * (which will commit the response) before rendering the view. * * <p>Typical usage with {@link InternalResourceViewResolver} looks as follows, * from the perspective of the DispatcherServlet context definition: * * <pre class="code">&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt; * &lt;property name="prefix" value="/WEB-INF/jsp/"/&gt; * &lt;property name="suffix" value=".jsp"/&gt; * &lt;/bean&gt;</pre> * * Every view name returned from a handler will be translated to a JSP * resource (for example: "myView" -> "/WEB-INF/jsp/myView.jsp"), using * this view class by default. * * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop * @see javax.servlet.RequestDispatcher#forward * @see javax.servlet.RequestDispatcher#include * @see javax.servlet.ServletResponse#flushBuffer * @see InternalResourceViewResolver * @see JstlView */
public class InternalResourceView extends AbstractUrlBasedView { private boolean alwaysInclude = false; private boolean preventDispatchLoop = false;
Constructor for use as a bean.
See Also:
/** * Constructor for use as a bean. * @see #setUrl * @see #setAlwaysInclude */
public InternalResourceView() { }
Create a new InternalResourceView with the given URL.
Params:
  • url – the URL to forward to
See Also:
/** * Create a new InternalResourceView with the given URL. * @param url the URL to forward to * @see #setAlwaysInclude */
public InternalResourceView(String url) { super(url); }
Create a new InternalResourceView with the given URL.
Params:
  • url – the URL to forward to
  • alwaysInclude – whether to always include the view rather than forward to it
/** * Create a new InternalResourceView with the given URL. * @param url the URL to forward to * @param alwaysInclude whether to always include the view rather than forward to it */
public InternalResourceView(String url, boolean alwaysInclude) { super(url); this.alwaysInclude = alwaysInclude; }
Specify whether to always include the view rather than forward to it.

Default is "false". Switch this flag on to enforce the use of a Servlet include, even if a forward would be possible.

See Also:
/** * Specify whether to always include the view rather than forward to it. * <p>Default is "false". Switch this flag on to enforce the use of a * Servlet include, even if a forward would be possible. * @see javax.servlet.RequestDispatcher#forward * @see javax.servlet.RequestDispatcher#include * @see #useInclude(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */
public void setAlwaysInclude(boolean alwaysInclude) { this.alwaysInclude = alwaysInclude; }
Set whether to explicitly prevent dispatching back to the current handler path.

Default is "false". Switch this to "true" for convention-based views where a dispatch back to the current handler path is a definitive error.

/** * Set whether to explicitly prevent dispatching back to the * current handler path. * <p>Default is "false". Switch this to "true" for convention-based * views where a dispatch back to the current handler path is a * definitive error. */
public void setPreventDispatchLoop(boolean preventDispatchLoop) { this.preventDispatchLoop = preventDispatchLoop; }
An ApplicationContext is not strictly required for InternalResourceView.
/** * An ApplicationContext is not strictly required for InternalResourceView. */
@Override protected boolean isContextRequired() { return false; }
Render the internal resource given the specified model. This includes setting the model as request attributes.
/** * Render the internal resource given the specified model. * This includes setting the model as request attributes. */
@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. if (useInclude(request, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including [" + getUrl() + "]"); } rd.include(request, response); } else { // Note: The forwarded resource is supposed to determine the content type itself. if (logger.isDebugEnabled()) { logger.debug("Forwarding to [" + getUrl() + "]"); } rd.forward(request, response); } }
Expose helpers unique to each rendering operation. This is necessary so that different rendering operations can't overwrite each other's contexts etc.

Called by renderMergedOutputModel(Map<String,Object>, HttpServletRequest, HttpServletResponse). The default implementation is empty. This method can be overridden to add custom helpers as request attributes.

Params:
  • request – current HTTP request
Throws:
  • Exception – if there's a fatal error while we're adding attributes
See Also:
/** * Expose helpers unique to each rendering operation. This is necessary so that * different rendering operations can't overwrite each other's contexts etc. * <p>Called by {@link #renderMergedOutputModel(Map, HttpServletRequest, HttpServletResponse)}. * The default implementation is empty. This method can be overridden to add * custom helpers as request attributes. * @param request current HTTP request * @throws Exception if there's a fatal error while we're adding attributes * @see #renderMergedOutputModel * @see JstlView#exposeHelpers */
protected void exposeHelpers(HttpServletRequest request) throws Exception { }
Prepare for rendering, and determine the request dispatcher path to forward to (or to include).

This implementation simply returns the configured URL. Subclasses can override this to determine a resource to render, typically interpreting the URL in a different manner.

Params:
  • request – current HTTP request
  • response – current HTTP response
Throws:
See Also:
Returns:the request dispatcher path to use
/** * Prepare for rendering, and determine the request dispatcher path * to forward to (or to include). * <p>This implementation simply returns the configured URL. * Subclasses can override this to determine a resource to render, * typically interpreting the URL in a different manner. * @param request current HTTP request * @param response current HTTP response * @return the request dispatcher path to use * @throws Exception if preparations failed * @see #getUrl() */
protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response) throws Exception { String path = getUrl(); Assert.state(path != null, "'url' not set"); 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; }
Obtain the RequestDispatcher to use for the forward/include.

The default implementation simply calls ServletRequest.getRequestDispatcher(String). Can be overridden in subclasses.

Params:
Returns:a corresponding RequestDispatcher
/** * Obtain the RequestDispatcher to use for the forward/include. * <p>The default implementation simply calls * {@link HttpServletRequest#getRequestDispatcher(String)}. * Can be overridden in subclasses. * @param request current HTTP request * @param path the target URL (as returned from {@link #prepareForRendering}) * @return a corresponding RequestDispatcher */
@Nullable protected RequestDispatcher getRequestDispatcher(HttpServletRequest request, String path) { return request.getRequestDispatcher(path); }
Determine whether to use RequestDispatcher's include or forward method.

Performs a check whether an include URI attribute is found in the request, indicating an include request, and whether the response has already been committed. In both cases, an include will be performed, as a forward is not possible anymore.

Params:
  • request – current HTTP request
  • response – current HTTP response
See Also:
Returns:true for include, false for forward
/** * Determine whether to use RequestDispatcher's {@code include} or * {@code forward} method. * <p>Performs a check whether an include URI attribute is found in the request, * indicating an include request, and whether the response has already been committed. * In both cases, an include will be performed, as a forward is not possible anymore. * @param request current HTTP request * @param response current HTTP response * @return {@code true} for include, {@code false} for forward * @see javax.servlet.RequestDispatcher#forward * @see javax.servlet.RequestDispatcher#include * @see javax.servlet.ServletResponse#isCommitted * @see org.springframework.web.util.WebUtils#isIncludeRequest */
protected boolean useInclude(HttpServletRequest request, HttpServletResponse response) { return (this.alwaysInclude || WebUtils.isIncludeRequest(request) || response.isCommitted()); } }