In Spring MVC I can access my beans in JSP using JstlView’s exposedContextBeanNames (or exposeContextBeansAsAttributes). For example, then, in my JSP I can write (${properties.myProperty). But when the same JSP is a part of a tiles view, these properties aren’t accessible. Is possible to configure Tiles properly or access these properties in another way?
I’m using Spring MVC 3.0.2 and Tiles 2.2.1. Here’s a bit of my configuration:
<bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="order" value="1"/>
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView" />
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="order" value="2"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
<property name="exposedContextBeanNames">
<list><value>properties</value></list>
</property>
</bean>
EDIT: I’ve implemented Skaffman’s solution.
TilesExposingBeansViewResolver.java:
package es.kcsolutions.util.spring.servlet.view;
import org.springframework.web.servlet.view.*;
public class TilesExposingBeansViewResolver extends UrlBasedViewResolver {
private Boolean exposeContextBeansAsAttributes;
private String[] exposedContextBeanNames;
public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) {
this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes;
}
public void setExposedContextBeanNames(String[] exposedContextBeanNames) {
this.exposedContextBeanNames = exposedContextBeanNames;
}
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
AbstractUrlBasedView superView = super.buildView(viewName);
if (superView instanceof TilesExposingBeansView) {
TilesExposingBeansView view = (TilesExposingBeansView) superView;
if (this.exposeContextBeansAsAttributes != null) view.setExposeContextBeansAsAttributes(this.exposeContextBeansAsAttributes);
if (this.exposedContextBeanNames != null) view.setExposedContextBeanNames(this.exposedContextBeanNames);
}
return superView;
}
}
TilesExposingBeansView.java:
package es.kcsolutions.util.spring.servlet.view;
import java.util.*;
import javax.servlet.http.*;
import org.springframework.web.context.support.ContextExposingHttpServletRequest;
import org.springframework.web.servlet.view.tiles2.TilesView;
public class TilesExposingBeansView extends TilesView {
private boolean exposeContextBeansAsAttributes = false;
private Set<String> exposedContextBeanNames;
public void setExposeContextBeansAsAttributes(boolean exposeContextBeansAsAttributes) {
this.exposeContextBeansAsAttributes = exposeContextBeansAsAttributes;
}
public void setExposedContextBeanNames(String[] exposedContextBeanNames) {
this.exposedContextBeanNames = new HashSet<String>(Arrays.asList(exposedContextBeanNames));
}
protected HttpServletRequest getRequestToExpose(HttpServletRequest originalRequest) {
if (this.exposeContextBeansAsAttributes || this.exposedContextBeanNames != null)
return new ContextExposingHttpServletRequest(originalRequest, getWebApplicationContext(), this.exposedContextBeanNames);
return originalRequest;
}
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest requestToExpose = getRequestToExpose(request);
exposeModelAsRequestAttributes(model, requestToExpose);
super.renderMergedOutputModel(model, requestToExpose, response);
}
}
Spring configuration:
<bean id="tilesViewResolver" class="es.kcsolutions.util.spring.servlet.view.TilesExposingBeansViewResolver">
<property name="order" value="1"/>
<property name="viewClass" value="es.kcsolutions.util.spring.servlet.view.TilesExposingBeansView"/>
<property name="exposedContextBeanNames">
<list><value>properties</value></list>
</property>
</bean>
If you have some problem, take a look at TilesExposingBeansView.renderMergedOutputModel. I’ve made some tests, but maybe it’s necessary to make a lot more.
As you’ve noticed, this functionality is part of
InternalResourceViewResolverandInternalResourceView, whereas the Tiles stuff inherits directly fromUrlBasedViewResolverandAbstractUrlBasedView, so you can’t make use of it.Looking at the code, there’s no reason why this stuff couldn’t have been put into
AbstractUrlBasedView. The magic happens inInternalResourceView.getRequestToExpose, and it looks perfectly applicable toAbstractUrlBasedViewtoo.In the short term, I suggest subclassing
UrlBasedViewResolverandTilesView, copying thegetRequestToExposestuff fromInternalResourceView. In the longer term, I encourage you to file a issue with SpringSource asking them to move this functionality up the class hierarchy intoAbstractUrlBasedView, making it more widely available.