Richard’s Weblog

February 23, 2009

Apache Tiles 2, integration with Spring-MVC

Filed under: Spring Framework,template system,Web development — Richard @ 5:26 pm
Tags: ,

UPDATE : I’ve written another example using Tiles 3.0.3 and SpringMVC 3.2.7. See here.

In a recent post, I showed a brief example of using Apache Tiles 2 to configure a classic layout in a J2EE environment. In this one, I’ll take that old book inventory search engine example I used in other previous writings, adding Tiles 2 support.

But before diving into the Tiles integration, let’s summarize the example. I have a single controller, managing a form submission and displaying the search results. This controller only uses one view, the same to display the form and the results. No particular ViewResolver nor HandlerMapping were configured, so I’m using the ones supplied by Spring MVC, out-of-the-box. Now let’s take a look at my configuration files, starting with the deployment descriptor, web.xml :

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">

    <servlet>
        <servlet-name>core</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
	</init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>core</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>/searchBook.do</welcome-file>
    </welcome-file-list>

</web-app>

Nothing particular here, just configuring the DispatcherServlet to be mapped on all “.do” urls.
My applicationContext.xml file looks like this :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean name="/searchBook.do" class="com.x.samples.bookbay.search.SearchController">
        <property name="commandClass" value="com.x.samples.bookbay.search.SearchCriteria"/>
        <property name="formView" value="/book/searchForm.jsp"/>
        <property name="successView" value="/book/searchForm.jsp"/>
    </bean>

</beans>

My controller is a SimpleFormController, directly pointing at the target JSP.
My directory structure looks like this :
springtilesintegration-dir11

I want to define a template, so I create a directory named “template” directly under the root directory of my application. This directory will contain my template file, the header file etc :

  • template.jsp
  • header.jsp
  • menu.jsp
  • footer.jsp

Using Tiles requires me to define my tiles in a configuration file. I’ll stack my Tiles specific configurations in a “defs” directory, under WEB-INF. For now, I have only one Tiles configuration file, called “myTilesConfigurationFile.xml” :

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>

    <definition name="defaultTemplate" template="/template/template.jsp">
        <put-attribute name="header" value="/template/header.jsp" />
        <put-attribute name="menu" value="/template/menu.jsp" />
        <put-attribute name="footer" value="/template/footer.jsp" />
    </definition>

    <definition name="searchBook" extends="defaultTemplate">
        <put-attribute name="body" value="/book/searchForm.jsp"/>
    </definition>

</tiles-definitions>

I won’t show the code of these JSP, since it’s pretty much the same as in my previous example on using Tiles.
My Tiles configuration file defines two tiles : the template and a tile named “searchBook”, that only extends the template, specifying the body will be the search form (the page that displays the form and the search results, “/book/searchForm.jsp”). Now I must have a JSP that uses tiles tag library to include the “searchBook” definition. This file will be “/book/search.jsp” :

<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<tiles:insertDefinition name="searchBook" />

Three things remain for the example to be completed. I must tell my controller to use my new search.jsp file as a success and form view. I also need to add tiles library and related dependency to my project, and finally I must “bootstrap” Tiles to have it read my definition file. I start by telling my controller to use search.jsp :

<bean name="/searchBook.do" class="com.x.samples.bookbay.search.SearchController">
    <property name="commandClass" value="com.x.samples.bookbay.search.SearchCriteria"/>
    <property name="formView" value="/book/search.jsp"/>
    <property name="successView" value="/book/search.jsp"/>
</bean>

For my example to work (I’m using Tiles 2.1.2 and Spring 2.5.6), I have to include all the libs:

  • tiles-servlet-2.1.2.jar
  • tiles-jsp-2.1.2.jar
  • tiles-core-2.1.2.jar
  • tiles-api-2.1.2.jar
  • commons-beanutils-1.8.0.jar (dependency)
  • commons-digester-1.8.1.jar (dependency)
  • commons-logging-1.1.1.jar (dependency)
  • spring-core.jar
  • spring-web.jar
  • spring-context.jar
  • spring-beans.jar
  • spring-webmvc.jar
  • aopalliance.jar
  • jstl-1.2.jar ( can be found here )

Now the only thing that is left to do is to “bootstrap” Tiles. According to the Spring 2.5 documentation, I should do it this way, in my applicationContext.xml :

<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
    <property name="definitions">
        <list>
            <value>/WEB-INF/defs/myTilesConfigFile.xml</value>
        </list>
    </property>
</bean>

This should work perfectly, BUT
There seems to be a problem bootstrapping Tiles versions 2.1 with the TilesConfigurer of Spring 2.5.6. When launching the web application with this configuration, I get this error :

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tilesConfigurer' defined i
n ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is
 java.lang.UnsupportedOperationException: Class org.apache.tiles.web.util.ServletContextAdapter not recognized a T
ilesApplicationContext
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAut
owireCapableBeanFactory.java:1338)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutow
ireCapableBeanFactory.java:473)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapa
bleBeanFactory.java:409)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowir
eCapableBeanFactory.java:380)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBea
nRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
        at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:402)
        at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:316)
        at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:316)
        at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:282)
        at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
        at javax.servlet.GenericServlet.init(GenericServlet.java:212)
        at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1172)
        at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:992)
        at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4058)
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:4371)
        at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1116)
        at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1214)
        at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:293)
        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
        at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
        at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
        at java.lang.Thread.run(Thread.java:595)
Caused by: java.lang.UnsupportedOperationException: Class org.apache.tiles.web.util.ServletContextAdapter not recognized a TilesApplicationContext
        at org.apache.tiles.factory.TilesContainerFactory.createContainer(TilesContainerFactory.java:219)
        at org.springframework.web.servlet.view.tiles2.TilesConfigurer.createTilesContainer(TilesConfigurer.java:214)
        at org.springframework.web.servlet.view.tiles2.TilesConfigurer.afterPropertiesSet(TilesConfigurer.java:201)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
        ... 30 more

The reason to this, basically, is that since Tiles 2.1, some configuration elements became deprecated, and Spring 2.5.6 is still using these elements. A JIRA issue is already created for this bug, and a fix seems to be planned for version 3.0.0 M3. However, at the time of this writing, the code of org.springframework.web.servlet.view.tiles2.TilesConfigurer is the same in the 2.5.6 as in the latest 3.0.0 build. So, to patch the problem, I wrote this little TilesConfigurer based on the one provided by Spring. It is essentially an adapted copy of the original TilesConfigurer :

/*
 * Copyright 2002-2007 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 com.x.web.tiles2;

import java.util.Enumeration;
import java.util.Properties;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tiles.TilesApplicationContext;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.TilesException;
import org.apache.tiles.access.TilesAccess;
import org.apache.tiles.context.AbstractTilesApplicationContextFactory;
import org.apache.tiles.definition.DefinitionsFactory;
import org.apache.tiles.definition.digester.DigesterDefinitionsReader;
import org.apache.tiles.evaluator.el.ELAttributeEvaluator;
import org.apache.tiles.factory.AbstractTilesContainerFactory;
import org.apache.tiles.factory.TilesContainerFactory;
import org.apache.tiles.preparer.BasicPreparerFactory;
import org.apache.tiles.servlet.context.ServletTilesApplicationContext;
import org.apache.tiles.servlet.context.wildcard.WildcardServletTilesApplicationContextFactory;
import org.apache.tiles.web.util.ServletContextAdapter;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.view.tiles2.SpringLocaleResolver;
import org.springframework.web.servlet.view.tiles2.TilesView;

/**
 * Helper class to configure Tiles2 for the Spring Framework. See
 * <a href="http://tiles.apache.org">http://tiles.apache.org</a>
 * for more information about Tiles, which basically is a templating
 * mechanism for JSP-based web applications.
 *
 * <p>The TilesConfigurer simply configures a TilesContainer using a set
 * of files containing definitions, to be accessed by {@link TilesView}
 * instances.
 *
 * <p>TilesViews can be managed by any {@link org.springframework.web.servlet.ViewResolver}.
 * For simple convention-based view resolution, consider using
 * {@link org.springframework.web.servlet.view.UrlBasedViewResolver} with the
 * "viewClass" property set to "org.springframework.web.servlet.view.tiles2.TilesView".
 *
 * <p>A typical TilesConfigurer bean definition looks as follows:
 *
 * <pre>
 * &lt;bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
 *   &lt;property name="definitions">
 *     &lt;list>
 *       &lt;value>/WEB-INF/defs/general.xml&lt;/value>
 *       &lt;value>/WEB-INF/defs/widgets.xml&lt;/value>
 *       &lt;value>/WEB-INF/defs/administrator.xml&lt;/value>
 *       &lt;value>/WEB-INF/defs/customer.xml&lt;/value>
 *       &lt;value>/WEB-INF/defs/templates.xml&lt;/value>
 *     &lt;/list>
 *   &lt;/property>
 * &lt;/bean></pre>
 *
 * The values in the list are the actual files containing the definitions.
 *
 * @author Juergen Hoeller
 * @author Richard Jr Barabé
 * @since 2.5
 * @see TilesView
 * @see org.springframework.web.servlet.view.UrlBasedViewResolver
 */
public class SpringTilesConfigurer implements ServletContextAware, InitializingBean, DisposableBean {

    protected final static Log logger = LogFactory.getLog(SpringTilesConfigurer.class);

    private final Properties tilesPropertyMap = new Properties();

    private ServletContext servletContext;

    private TilesApplicationContext tilesContext;

    public SpringTilesConfigurer() {
            this.tilesPropertyMap.put(
		            AbstractTilesApplicationContextFactory.APPLICATION_CONTEXT_FACTORY_INIT_PARAM,
		            WildcardServletTilesApplicationContextFactory.class.getName());
            this.tilesPropertyMap.put(
				    TilesContainerFactory.PREPARER_FACTORY_INIT_PARAM,
				    BasicPreparerFactory.class.getName());
		    this.tilesPropertyMap.put(
				    DefinitionsFactory.LOCALE_RESOLVER_IMPL_PROPERTY,
				    SpringLocaleResolver.class.getName());
		    this.tilesPropertyMap.put(TilesContainerFactory.ATTRIBUTE_EVALUATOR_INIT_PARAM, ELAttributeEvaluator.class.getName());
		    this.tilesPropertyMap.put(TilesContainerFactory.CONTAINER_FACTORY_MUTABLE_INIT_PARAM,
	                Boolean.toString(false));
    }

    /**
     * Set the Tiles definitions, i.e. the list of files containing the definitions.
     * Default is "/WEB-INF/tiles.xml".
     */
    public void setDefinitions(String[] definitions) {
        if (definitions != null) {
            String defs = StringUtils.arrayToCommaDelimitedString(definitions);
            if (logger.isInfoEnabled()) {
                logger.info("TilesConfigurer: adding definitions [" + defs + "]");
            }
            this.tilesPropertyMap.put(DefinitionsFactory.DEFINITIONS_CONFIG, defs);            
        }
    }
    
    /**
     * Set whether to validate the Tiles XML definitions. Default is "true".
     */
    public void setValidateDefinitions(boolean validateDefinitions) {
        this.tilesPropertyMap.put(DigesterDefinitionsReader.PARSER_VALIDATE_PARAMETER_NAME,
                Boolean.toString(validateDefinitions));
    }
    
    /**
     * Set the {@link org.apache.tiles.definition.DefinitionsFactory} implementation to use.
     * Default is {@link org.apache.tiles.definition.UrlDefinitionsFactory},
     * operating on definition resource URLs.
     * <p>Specify a custom DefinitionsFactory, e.g. a UrlDefinitionsFactory subclass,
     * to customize the creation of Tiles Definition objects. Note that such a
     * DefinitionsFactory has to be able to handle {@link java.net.URL} source objects,
     * unless you configure a different TilesContainerFactory.
     */
    public void setDefinitionsFactoryClass(Class<?> definitionsFactoryClass) {
        this.tilesPropertyMap.put(TilesContainerFactory.DEFINITIONS_FACTORY_INIT_PARAM,
                definitionsFactoryClass.getName());
    }
    
    /**
     * Set the {@link org.apache.tiles.preparer.PreparerFactory} implementation to use.
     * Default is {@link org.apache.tiles.preparer.BasicPreparerFactory}, creating
     * shared instances for specified preparer classes.
     * <p>Specify {@link SimpleSpringPreparerFactory} to autowire
     * {@link org.apache.tiles.preparer.ViewPreparer} instances based on specified
     * preparer classes, applying Spring's container callbacks as well as applying
     * configured Spring BeanPostProcessors. If Spring's context-wide annotation-config
     * has been activated, annotations in ViewPreparer classes will be automatically
     * detected and applied.
     * <p>Specify {@link SpringBeanPreparerFactory} to operate on specified preparer
     * <i>names</i> instead of classes, obtaining the corresponding Spring bean from
     * the DispatcherServlet's application context. The full bean creation process
     * will be in the control of the Spring application context in this case,
     * allowing for the use of scoped beans etc. Note that you need to define one
     * Spring bean definition per preparer name (as used in your Tiles definitions).
     * @see SimpleSpringPreparerFactory
     * @see SpringBeanPreparerFactory
     */
    public void setPreparerFactoryClass(Class<?> preparerFactoryClass) {
        this.tilesPropertyMap.put(TilesContainerFactory.PREPARER_FACTORY_INIT_PARAM,
                preparerFactoryClass.getName());
    }
    
    /**
     * Set whether to use a MutableTilesContainer for this application.
     * Default is "false".
     */
    public void setUseMutableTilesContainer(boolean useMutableTilesContainer) {
        this.tilesPropertyMap.put(TilesContainerFactory.CONTAINER_FACTORY_MUTABLE_INIT_PARAM,
                Boolean.toString(useMutableTilesContainer));
    }
    
    /**
     * Set Tiles properties (equivalent to the ServletContext init-params in
     * the Tiles documentation), overriding the default settings.
     */
    public void setTilesProperties(Properties tilesProperties) {
        CollectionUtils.mergePropertiesIntoMap(tilesProperties, this.tilesPropertyMap);
    }

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    /**
     * Creates and exposes a TilesContainer for this web application.
     * @throws TilesException in case of setup failure
     */
    public void afterPropertiesSet() throws TilesException {
        TilesContainer container = createTilesContainer();
	TilesAccess.setContainer(this.tilesContext, container);
    }

    /**
     * Create a TilesContainer for this web application.
     * @param context this web application's ServletContext
     * @return the TilesContainer to expose
     * @throws TilesException in case of setup failure
     */
    protected TilesContainer createTilesContainer() throws TilesException {
        ServletContextAdapter adaptedContext = new ServletContextAdapter(new DelegatingServletConfig());
        TilesApplicationContext preliminaryContext = new ServletTilesApplicationContext(adaptedContext);
        AbstractTilesApplicationContextFactory contextFactory = AbstractTilesApplicationContextFactory.createFactory(preliminaryContext);
        this.tilesContext = contextFactory.createApplicationContext(adaptedContext);
        AbstractTilesContainerFactory factory = AbstractTilesContainerFactory.getTilesContainerFactory(this.tilesContext);
        return factory.createContainer(this.tilesContext);
    }

    /**
     * Removes the TilesContainer from this web application.
     * @throws TilesException in case of cleanup failure
     */
    public void destroy() throws TilesException {
        TilesAccess.setContainer(this.tilesContext, null);
    }

    /**
     * Internal implementation of the ServletConfig interface, to be passed
     * to the wrapped servlet. Delegates to ServletWrappingController fields
     * and methods to provide init parameters and other environment info.
     */
    private class DelegatingServletConfig implements ServletConfig {

        public String getServletName() {
            return "TilesConfigurer";
        }

        public ServletContext getServletContext() {
            return servletContext;
        }

        public String getInitParameter(String paramName) {
            return tilesPropertyMap.getProperty(paramName);
        }

        public Enumeration<?> getInitParameterNames() {
            return tilesPropertyMap.keys();
        }
    }
    
}

This version of the TilesConfigurer enables by default the EL support. It also allow to use Wildcards in it’s definitions, and will also allow definition files to be located in the classpath ie :

<bean id="tilesConfigurer" class="com.x.web.tiles2.SpringTilesConfigurer">
    <property name="definitions">
	<list>
	    <value>/WEB-INF/**/*.tiles-def.xml</value>
            <value>classpath:/your/package/directory/anotherTileConfigFile.xml</value>
            <value>classpath:**/*.tiles-def.xml</value>
        </list>
    </property>
</bean>

In this example, I dont use wildcard nor classpath definitions, so my applicationContext looks like this :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="tilesConfigurer" class="com.x.web.tiles2.SpringTilesConfigurer">
        <property name="definitions">
            <list>
	        <value>/WEB-INF/defs/myTilesConfigFile.xml</value>
            </list>
        </property>
    </bean>

    <bean name="/searchBook.do" class="com.x.samples.bookbay.search.SearchController">
        <property name="commandClass" value="com.x.samples.bookbay.search.SearchCriteria"/>
        <property name="formView" value="/book/search.jsp"/>
        <property name="successView" value="/book/search.jsp"/>
    </bean>
</beans>

This starts perfectly, and calling the URL http://host:port/searchBook.do in my browser makes my search form to be displayed in the configured template :

spingtilesintegrationfinalscreenshot

My application is now ready to use Tiles 2, but my controller still uses the JSP directly for resolving its views. It is possible to tell spring MVC to map logical view names directly to defined tiles. For this we have to set a ViewResolver to use “org.springframework.web.servlet.view.tiles2.TilesView” as its view class.
Taking a look back to my Tiles integration, one thing annoys me. The fact that I must create a jsp (/book/search.jsp) whose only purpose is to tell the web application to use the “searchBook” Tile. I can solve this by making my Controller directly call the “searchBook” tiles instead of “/book/search.jsp”.
Before configuring our Tiles view resolver, I deleted the useless /book/search.jsp, to make sure my application doesn’t use it. Next, I just have to change my applicationContext.xml to configure the ViewResolver and make my controller use the “searchBook” tile :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="tilesConfigurer" class="com.x.web.tiles2.SpringTilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/defs/myTilesConfigFile.xml</value>
            </list>
        </property>
    </bean>

    <bean id="tilesViewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
    </bean>

    <bean name="/searchBook.do" class="com.x.samples.bookbay.search.SearchController">
        <property name="commandClass" value="com.x.samples.bookbay.search.SearchCriteria"/>
        <property name="formView" value="searchBook"/>
        <property name="successView" value="searchBook"/>
    </bean>

</beans>

And now I have a Web application built on top of Spring, using Apache Tiles as its web template system.

Advertisements
Next Page »

Blog at WordPress.com.