Browse Source

InternalResourceViewResolver's exposure of context beans is now available at UrlBasedViewResolver level

Issue: SPR-8064
pull/621/head
Juergen Hoeller 11 years ago
parent
commit
a05b748d42
  1. 67
      spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java
  2. 68
      spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceView.java
  3. 33
      spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java
  4. 43
      spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java

67
spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java

@ -18,10 +18,13 @@ package org.springframework.web.servlet.view; @@ -18,10 +18,13 @@ package org.springframework.web.servlet.view;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
@ -30,6 +33,7 @@ import javax.servlet.http.HttpServletResponse; @@ -30,6 +33,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.support.ContextExposingHttpServletRequest;
import org.springframework.web.context.support.WebApplicationObjectSupport;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.support.RequestContext;
@ -68,12 +72,14 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement @@ -68,12 +72,14 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
private String requestContextAttribute;
/** Map of static attributes, keyed by attribute name (String) */
private final Map<String, Object> staticAttributes = new LinkedHashMap<String, Object>();
/** Whether or not the view should add path variables in the model */
private boolean exposePathVariables = true;
private boolean exposeContextBeansAsAttributes = false;
private Set<String> exposedContextBeanNames;
/**
* Set the view's name. Helpful for traceability.
@ -248,6 +254,36 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement @@ -248,6 +254,36 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
return this.exposePathVariables;
}
/**
* Set whether to make all Spring beans in the application context accessible
* as request attributes, through lazy checking once an attribute gets accessed.
* <p>This will make all such beans accessible in plain {@code ${...}}
* expressions in a JSP 2.0 page, as well as in JSTL's {@code c:out}
* value expressions.
* <p>Default is "false". Switch this flag on to transparently expose all
* Spring beans in the request attribute namespace.
* <p><b>NOTE:</b> Context beans will override any custom request or session
* attributes of the same name that have been manually added. However, model
* attributes (as explicitly exposed to this view) of the same name will
* always override context beans.
* @see #getRequestToExpose
*/
public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) {
this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes;
}
/**
* Specify the names of beans in the context which are supposed to be exposed.
* If this is non-null, only the specified beans are eligible for exposure as
* attributes.
* <p>If you'd like to expose all Spring beans in the application context, switch
* the {@link #setExposeContextBeansAsAttributes "exposeContextBeansAsAttributes"}
* flag on but do not list specific bean names for this property.
*/
public void setExposedContextBeanNames(String... exposedContextBeanNames) {
this.exposedContextBeanNames = new HashSet<String>(Arrays.asList(exposedContextBeanNames));
}
/**
* Prepares the view given the specified model, merging it with static
@ -264,7 +300,7 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement @@ -264,7 +300,7 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
renderMergedOutputModel(mergedModel, request, response);
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
/**
@ -276,12 +312,13 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement @@ -276,12 +312,13 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
@SuppressWarnings("unchecked")
Map<String, Object> pathVars = (this.exposePathVariables ?
(Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);
(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;
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) {
@ -344,6 +381,24 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement @@ -344,6 +381,24 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
return false;
}
/**
* 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;
}
/**
* Subclasses must implement this method to actually render the view.
* <p>The first step will be preparing the request: In the JSP case,

68
spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceView.java

@ -68,10 +68,6 @@ public class InternalResourceView extends AbstractUrlBasedView { @@ -68,10 +68,6 @@ public class InternalResourceView extends AbstractUrlBasedView {
private boolean alwaysInclude = false;
private boolean exposeContextBeansAsAttributes = false;
private Set<String> exposedContextBeanNames;
private boolean preventDispatchLoop = false;
@ -115,36 +111,6 @@ public class InternalResourceView extends AbstractUrlBasedView { @@ -115,36 +111,6 @@ public class InternalResourceView extends AbstractUrlBasedView {
this.alwaysInclude = alwaysInclude;
}
/**
* Set whether to make all Spring beans in the application context accessible
* as request attributes, through lazy checking once an attribute gets accessed.
* <p>This will make all such beans accessible in plain {@code ${...}}
* expressions in a JSP 2.0 page, as well as in JSTL's {@code c:out}
* value expressions.
* <p>Default is "false". Switch this flag on to transparently expose all
* Spring beans in the request attribute namespace.
* <p><b>NOTE:</b> Context beans will override any custom request or session
* attributes of the same name that have been manually added. However, model
* attributes (as explicitly exposed to this view) of the same name will
* always override context beans.
* @see #getRequestToExpose
*/
public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) {
this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes;
}
/**
* Specify the names of beans in the context which are supposed to be exposed.
* If this is non-null, only the specified beans are eligible for exposure as
* attributes.
* <p>If you'd like to expose all Spring beans in the application context, switch
* the {@link #setExposeContextBeansAsAttributes "exposeContextBeansAsAttributes"}
* flag on but do not list specific bean names for this property.
*/
public void setExposedContextBeanNames(String... exposedContextBeanNames) {
this.exposedContextBeanNames = new HashSet<String>(Arrays.asList(exposedContextBeanNames));
}
/**
* Set whether to explicitly prevent dispatching back to the
* current handler path.
@ -173,32 +139,29 @@ public class InternalResourceView extends AbstractUrlBasedView { @@ -173,32 +139,29 @@ public class InternalResourceView extends AbstractUrlBasedView {
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine which request handle to expose to the RequestDispatcher.
HttpServletRequest requestToExpose = getRequestToExpose(request);
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, requestToExpose);
exposeModelAsRequestAttributes(model, request);
// Expose helpers as request attributes, if any.
exposeHelpers(requestToExpose);
exposeHelpers(request);
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(requestToExpose, response);
String dispatcherPath = prepareForRendering(request, response);
// Obtain a RequestDispatcher for the target resource (typically a JSP).
RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
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(requestToExpose, response)) {
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.include(requestToExpose, response);
rd.include(request, response);
}
else {
@ -206,25 +169,8 @@ public class InternalResourceView extends AbstractUrlBasedView { @@ -206,25 +169,8 @@ public class InternalResourceView extends AbstractUrlBasedView {
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
}
rd.forward(requestToExpose, response);
}
}
/**
* Get the request handle to expose to the RequestDispatcher, 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 org.springframework.web.context.support.ContextExposingHttpServletRequest
*/
protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) {
if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null) {
return new ContextExposingHttpServletRequest(
originalRequest, getWebApplicationContext(), this.exposedContextBeanNames);
rd.forward(request, response);
}
return originalRequest;
}
/**

33
spring-webmvc/src/main/java/org/springframework/web/servlet/view/InternalResourceViewResolver.java

@ -52,10 +52,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver { @@ -52,10 +52,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver {
private Boolean alwaysInclude;
private Boolean exposeContextBeansAsAttributes;
private String[] exposedContextBeanNames;
/**
* Sets the default {@link #setViewClass view class} to {@link #requiredViewClass}:
@ -89,29 +85,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver { @@ -89,29 +85,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver {
this.alwaysInclude = alwaysInclude;
}
/**
* Set whether to make all Spring beans in the application context accessible
* as request attributes, through lazy checking once an attribute gets accessed.
* <p>This will make all such beans accessible in plain {@code ${...}}
* expressions in a JSP 2.0 page, as well as in JSTL's {@code c:out}
* value expressions.
* <p>Default is "false".
* @see InternalResourceView#setExposeContextBeansAsAttributes
*/
public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) {
this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes;
}
/**
* Specify the names of beans in the context which are supposed to be exposed.
* If this is non-null, only the specified beans are eligible for exposure as
* attributes.
* @see InternalResourceView#setExposedContextBeanNames
*/
public void setExposedContextBeanNames(String... exposedContextBeanNames) {
this.exposedContextBeanNames = exposedContextBeanNames;
}
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
@ -119,12 +92,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver { @@ -119,12 +92,6 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver {
if (this.alwaysInclude != null) {
view.setAlwaysInclude(this.alwaysInclude);
}
if (this.exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(this.exposeContextBeansAsAttributes);
}
if (this.exposedContextBeanNames != null) {
view.setExposedContextBeanNames(this.exposedContextBeanNames);
}
view.setPreventDispatchLoop(true);
return view;
}

43
spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java

@ -119,6 +119,10 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements @@ -119,6 +119,10 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
private Boolean exposePathVariables;
private Boolean exposeContextBeansAsAttributes;
private String[] exposedContextBeanNames;
private String[] viewNames;
private int order = Integer.MAX_VALUE;
@ -327,6 +331,37 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements @@ -327,6 +331,37 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
return this.exposePathVariables;
}
/**
* Set whether to make all Spring beans in the application context accessible
* as request attributes, through lazy checking once an attribute gets accessed.
* <p>This will make all such beans accessible in plain {@code ${...}}
* expressions in a JSP 2.0 page, as well as in JSTL's {@code c:out}
* value expressions.
* <p>Default is "false".
* @see AbstractView#setExposeContextBeansAsAttributes
*/
public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) {
this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes;
}
protected Boolean getExposeContextBeansAsAttributes() {
return this.exposeContextBeansAsAttributes;
}
/**
* Specify the names of beans in the context which are supposed to be exposed.
* If this is non-null, only the specified beans are eligible for exposure as
* attributes.
* @see AbstractView#setExposedContextBeanNames
*/
public void setExposedContextBeanNames(String... exposedContextBeanNames) {
this.exposedContextBeanNames = exposedContextBeanNames;
}
protected String[] getExposedContextBeanNames() {
return this.exposedContextBeanNames;
}
/**
* Set the view names (or name patterns) that can be handled by this
* {@link org.springframework.web.servlet.ViewResolver}. View names can contain
@ -482,6 +517,14 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements @@ -482,6 +517,14 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
if (exposePathVariables != null) {
view.setExposePathVariables(exposePathVariables);
}
Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
if (exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
}
String[] exposedContextBeanNames = getExposedContextBeanNames();
if (exposedContextBeanNames != null) {
view.setExposedContextBeanNames(exposedContextBeanNames);
}
return view;
}

Loading…
Cancel
Save