Announcement Announcement Module
Collapse
No announcement yet.
TIP: Integrating Spring Web with Tiles Page Title Module
Move Remove Collapse
This is a sticky topic.
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • TIP: Integrating Spring Web with Tiles

    In our project we use Tiles and we want to have the exact same functionality for mobile and for desktops. This tip will help you if you use Tiles and you want to reuse your controllers for the site and just change the View with minimal effort.

    Here are the steps:
    1. Use expressions in the tiles-defs.xml file (or whatever you named it) instead of values.
    Code:
    Before
    <definition name="template-main" template="/WEB-INF/jsp/layout/layout.jsp">
            <put-attribute name="header-content" value="/WEB-INF/jsp/layout/header.jsp" />
            <put-attribute name="main-content" value="" />
            <put-attribute name="footer-content" value="/WEB-INF/jsp/layout/footer.jsp"
    </definition>
        
    <definition name="home" extends="template-main">
            <put-attribute name="main-content" value="/WEB-INF/jsp/home/home.jsp" />
    </definition>
    
    ...
    
    After
    <definition name="template-main" templateExpression="/WEB-INF/jsp/layout/layout${mDeviceType}.jsp">
            <put-attribute name="header-content" expression="/WEB-INF/jsp/layout/header${mDeviceType}.jsp" />
            <put-attribute name="main-content" value="" />
            <put-attribute name="footer-content" expression="/WEB-INF/jsp/layout/footer${mDeviceType}.jsp"
    </definition>
        
    <definition name="home" extends="template-main">
            <put-attribute name="main-content" expression="/WEB-INF/jsp/home/home${mDeviceType}.jsp" />
    </definition>
    (You will need tiles-extras and tiles-el jars)

    2. Define a request parameter mDeviceType so it is used by Tiles, and it will use the right jsp for mobile/tablet/whatever.
    In order to do this, we had to do some hacking:
    Code:
    /**
     * A class that resolves view names base detecting mobile (or non-mobile)
     * devices. This is exactly the same as {@link LiteDeviceDelegatingViewResolver}
     * but on top of changing the view name a configurable Attribute is added to the request.
     * Useful, for example, to change the JSP name based on device in Tiles
     * @author Andres
     *
     */
    public class RequestAttributeLiteDeviceDelegatingViewResolver extends
    		LiteDeviceDelegatingViewResolver {
    
    	//the name of the attribute to put in scope
    	protected String attributeName = "mDeviceType";
    	//the value of the attribute #attributeName for Mobile
    	protected String mobileValue = "m";
    	protected String tabletValue = "t";
    	protected String normalValue = "";
    	
    	public RequestAttributeLiteDeviceDelegatingViewResolver(
    			ViewResolver delegate) {
    		super(delegate);
    	}
    
    	
    	@Override
    	protected String getDeviceViewNameInternal(String viewName) {
    		RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
    		Assert.isInstanceOf(ServletRequestAttributes.class, attrs);
    		HttpServletRequest request = ((ServletRequestAttributes) attrs).getRequest();
    		Device device = DeviceUtils.getCurrentDevice(request);
    		SitePreference sitePreference = SitePreferenceUtils.getCurrentSitePreference(request);
    		String resolvedViewName = viewName;
    		String attributeValue = normalValue;
    		if (ResolverUtils.isNormal(device, sitePreference)) {
    			resolvedViewName = getNormalPrefix() + viewName + getNormalSuffix();
    			attributeValue = normalValue;
    		} else if (ResolverUtils.isMobile(device, sitePreference)) {
    			resolvedViewName = getMobilePrefix() + viewName + getMobileSuffix();
    			attributeValue = mobileValue;
    		} else if (ResolverUtils.isTablet(device, sitePreference)) {
    			resolvedViewName = getTabletPrefix() + viewName + getTabletSuffix();
    			attributeValue = tabletValue;
    		}
    		request.setAttribute(attributeName, attributeValue);
    		return resolvedViewName;
    	}
    
    	public String getAttributeName() {
    		return attributeName;
    	}
    
    	/**
    	 * Specifies the name of the attribute to be put into the request
    	 * scope. Defaults to 'm.deviceType'
    	 * @param attributeName
    	 */
    	public void setAttributeName(String attributeName) {
    		this.attributeName = attributeName;
    	}
    
    	public String getMobileValue() {
    		return mobileValue;
    	}
    
    	/**
    	 * Specifies the value to be set to the AttributeName when the
    	 * detected device is Mobile
    	 * @param mobileValue
    	 */
    	public void setMobileValue(String mobileValue) {
    		this.mobileValue = mobileValue;
    	}
    
    	public String getTabletValue() {
    		return tabletValue;
    	}
    
    	/**
    	 * Specifies the value to be set to the AttributeName when the
    	 * detected device is Tablet
    	 * @param tabletValue
    	 */
    	public void setTabletValue(String tabletValue) {
    		this.tabletValue = tabletValue;
    	}
    
    	public String getNormalValue() {
    		return normalValue;
    	}
    
    	/**
    	 * Specifies the value to be set to the AttributeName when the
    	 * detected device is Normal (i.e. not-mobile and not-tablet)
    	 * @param normalValue
    	 */
    	public void setNormalValue(String normalValue) {
    		this.normalValue = normalValue;
    	}
    }
    Note: We could have used CURRENT_SITE_PREFERENCE_ATTRIBUTE but then we would have had to name our files after the SitePreference enum, making files harder to read.
    3. Configure the previous class in your Spring config:

    Code:
    <bean id="jstlViewResolver" class="com.marb.commons.support.spring.mobile.device.view.RequestAttributeLiteDeviceDelegatingViewResolver">
    		<constructor-arg>
    			    <bean id="tilesViewResolver" class="org.springframework.web.servlet.view.tiles2.TilesViewResolver">
    			    </bean>
    		</constructor-arg>
    		<!-- this allows us to set Expressions in Tiles based on the m.deviceType request attribute -->
    		<property name="attributeName" value="mDeviceType" />
    		<property name="mobileValue" value=".m" />
    		<property name="tabletValue" value = "" />
    		<property name="normalValue" value = "" />
    	</bean>
    4. Create the mobile, tablet and desktop JSPs as needed:

    login.jsp
    login.m.jsp
    login.t.jsp
    etc.

    If you have different controllers for different device types then it is just easier to use the path to differentiate between web versions.
    Hope this helps.
    ab

  • #2
    Nice tip! I've stuck the thread so others won't miss it. I've seen/heard questions on how to integrate with Tiles, so thanks for sharing. I'm sure this will help.

    Comment

    Working...
    X