tiles2的布局管理(一)spring+struts2+tiles2
时间:2010-07-19 来源:sillycat
tiles2的布局管理(一)spring+struts2+tiles2
official web site
http://tiles.apache.org/
the document is here
http://tiles.apache.org/framework/index.html
The Composite View Pattern
Using the composite view pattern, the other part of the page have been reused, and the layout consistence has been preserved.
Tiles is a composite view framework, it allows to reuse page pieces across the application. But another approach to achive the same result is using the Decorator pattern. For example, Sitemesh is based on the Decorator pattern.
Configuring Tiles
I use spring to integrate struts2 to work as command actions. The configuration file web.xml:
<context-param>
<param-name>org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</param-name>
<param-value>/WEB-INF/tiles.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:main-context.xml</param-value>
</context-param>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listerner-class>org.apache.struts2.tiles.StrutsTilesListener</listerner-class>
</listener>
the tiles configuration file tiles.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://struts.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="base.definition" template="/layout/layout.jsp">
<put-attribute name="title" value="当前客户起始页面"/>
<put-attribute name="banner" value="/content/top.jsp"/>
<put-attribute name="menu" value="/content/menu.jsp"/>
<put-attribute name="sidebar" value="/content/sidebar.jsp"/>
<put-attribute name="hintbar" value="/content/error.jsp"/>
<put-attribute name="body" value="/screen/body.jsp"/>
</definition>
<definition name="index.definition" extends="base.definition">
<put-attribute name="body" value="/screen/index.jsp"/>
</definition>
</tiles-definitions>
we defined one template here named base.definition and every time we can use <put-attribute> to replace one part to form a new page.
the struts2 configuration file struts.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="testp" namespace="/testn" extends="tiles-default">
<action name="hello" method="hello" class="helloAction">
<result name="hello" type="tiles">base.definition</result>
</action>
<action name="ads" method="ads" class="helloAction">
<result name="hello" type="tiles">index.definition</result>
</action>
</package>
</struts>
If we call the method in action, we will render to different tiles template page.
the struts.properties file here is just the same as in spring+struts2:
struts.i18n.encoding=utf-8
#spring configuration
struts.objectFactory=spring
#dev mode flag
struts.devMode=true
struts.action.extension=do
ok, every thing goes well and We can try the urls index.jsp:
you can see this page<br />
<a href="testn/testp/hello.do">hello</a><br />
<a href="testn/testp/ads.do">ads</a><br />
Problem One:
Struts Problem Report
Struts has detected an unhandled exception:
Messages:
File: org/apache/struts2/views/tiles/TilesResult.java
Line number: 105
Stacktraces
java.lang.NullPointerException
org.apache.struts2.views.tiles.TilesResult.doExecute(TilesResult.java:105)
org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:186)
com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:362)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:266)
com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:165)
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:252)
org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
Solution:
check out the java source file TilesResult.java and view the codes:
TilesContainer container = TilesAccess.getContainer(servletContext);
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
container.render(location, request, response);
the problem is here, the contrainer is null from the serveletContext, and when the web start, we just put the container in listener.but I don't know why, but the org.apache.struts2.tiles.StrutsTilesListener never be called in web.xml, so that may be the problem that we can not have two listeners in one web.xml. So I just recode all the method and function in startupListener.java extends ContextLoaderListener, I just used to do this in spring2.5.6 and spring mvc controller,and it works well.
but here, since we use spring 3.0 + struts2, it still cause problem.
Problem Two:
严重: ********** FATAL ERROR STARTING UP STRUTS-SPRING INTEGRATION **********
Looks like the Spring listener was not configured for your web app!
Nothing will work until WebApplicationContextUtils returns a valid ApplicationContext.
You might need to add the following to web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2010-7-13 17:09:32 com.opensymphony.xwork2.util.logging.commons.CommonsLogger error
严重: Dispatcher initialization failed
java.lang.NullPointerException
at com.opensymphony.xwork2.spring.SpringObjectFactory.getClassInstance(SpringObjectFactory.java:209)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.verifyResultType(XmlConfigurationProvider.java:519)
it seems that the xwork2.spring.SpringObjectFactory just knows to find org.springframework.web.context.ContextLoaderListener,even my StartupListener is extending the ContextLoaderListener, it is really silly. So I just have to code a new java file org.springframework.web.context.ContextLoaderListener with the same name and same package.But I add the tiles codes there:
package org.springframework.web.context;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.tiles.ConfiguredServletContext;
import org.apache.struts2.tiles.StrutsTilesContainerFactory;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.TilesException;
import org.apache.tiles.access.TilesAccess;
import org.apache.tiles.factory.TilesContainerFactory;
@SuppressWarnings("unchecked")
public class ContextLoaderListener extends ContextLoader implements
ServletContextListener {
protected static final Log LOG = LogFactory
.getLog(ContextLoaderListener.class);
private ContextLoader contextLoader;
private static final Map INIT;
static {
INIT = new HashMap();
INIT.put(TilesContainerFactory.CONTAINER_FACTORY_INIT_PARAM,
StrutsTilesContainerFactory.class.getName());
}
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());
ServletContext servletContext = event.getServletContext();
try {
TilesContainer container = createContainer(servletContext);
TilesAccess.setContainer(servletContext, container);
} catch (TilesException e) {
throw new IllegalStateException("Unable to instantiate container.");
}
}
@Deprecated
protected ContextLoader createContextLoader() {
return null;
}
@Deprecated
public ContextLoader getContextLoader() {
return this.contextLoader;
}
public void contextDestroyed(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
try {
TilesAccess.setContainer(servletContext, null);
} catch (TilesException e) {
LOG.warn("Unable to remove tiles container from service.");
}
if (this.contextLoader != null) {
this.contextLoader.closeWebApplicationContext(event
.getServletContext());
}
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
protected TilesContainer createContainer(ServletContext context)
throws TilesException {
if (context
.getInitParameter(TilesContainerFactory.CONTEXT_FACTORY_INIT_PARAM) == null) {
context = decorate(context);
} else {
LOG
.warn("Tiles container factory is explicitly set. Not injecting struts configuration.");
}
TilesContainerFactory factory = TilesContainerFactory
.getFactory(context);
return factory.createContainer(context);
}
protected ServletContext decorate(ServletContext context) {
return new ConfiguredServletContext(context, INIT);
}
}
then it works fine.
official web site
http://tiles.apache.org/
the document is here
http://tiles.apache.org/framework/index.html
The Composite View Pattern
Using the composite view pattern, the other part of the page have been reused, and the layout consistence has been preserved.
Tiles is a composite view framework, it allows to reuse page pieces across the application. But another approach to achive the same result is using the Decorator pattern. For example, Sitemesh is based on the Decorator pattern.
Configuring Tiles
I use spring to integrate struts2 to work as command actions. The configuration file web.xml:
<context-param>
<param-name>org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG</param-name>
<param-value>/WEB-INF/tiles.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:main-context.xml</param-value>
</context-param>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listerner-class>org.apache.struts2.tiles.StrutsTilesListener</listerner-class>
</listener>
the tiles configuration file tiles.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://struts.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="base.definition" template="/layout/layout.jsp">
<put-attribute name="title" value="当前客户起始页面"/>
<put-attribute name="banner" value="/content/top.jsp"/>
<put-attribute name="menu" value="/content/menu.jsp"/>
<put-attribute name="sidebar" value="/content/sidebar.jsp"/>
<put-attribute name="hintbar" value="/content/error.jsp"/>
<put-attribute name="body" value="/screen/body.jsp"/>
</definition>
<definition name="index.definition" extends="base.definition">
<put-attribute name="body" value="/screen/index.jsp"/>
</definition>
</tiles-definitions>
we defined one template here named base.definition and every time we can use <put-attribute> to replace one part to form a new page.
the struts2 configuration file struts.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="testp" namespace="/testn" extends="tiles-default">
<action name="hello" method="hello" class="helloAction">
<result name="hello" type="tiles">base.definition</result>
</action>
<action name="ads" method="ads" class="helloAction">
<result name="hello" type="tiles">index.definition</result>
</action>
</package>
</struts>
If we call the method in action, we will render to different tiles template page.
the struts.properties file here is just the same as in spring+struts2:
struts.i18n.encoding=utf-8
#spring configuration
struts.objectFactory=spring
#dev mode flag
struts.devMode=true
struts.action.extension=do
ok, every thing goes well and We can try the urls index.jsp:
you can see this page<br />
<a href="testn/testp/hello.do">hello</a><br />
<a href="testn/testp/ads.do">ads</a><br />
Problem One:
Struts Problem Report
Struts has detected an unhandled exception:
Messages:
File: org/apache/struts2/views/tiles/TilesResult.java
Line number: 105
Stacktraces
java.lang.NullPointerException
org.apache.struts2.views.tiles.TilesResult.doExecute(TilesResult.java:105)
org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:186)
com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:362)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:266)
com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:165)
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:252)
org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
Solution:
check out the java source file TilesResult.java and view the codes:
TilesContainer container = TilesAccess.getContainer(servletContext);
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
container.render(location, request, response);
the problem is here, the contrainer is null from the serveletContext, and when the web start, we just put the container in listener.but I don't know why, but the org.apache.struts2.tiles.StrutsTilesListener never be called in web.xml, so that may be the problem that we can not have two listeners in one web.xml. So I just recode all the method and function in startupListener.java extends ContextLoaderListener, I just used to do this in spring2.5.6 and spring mvc controller,and it works well.
but here, since we use spring 3.0 + struts2, it still cause problem.
Problem Two:
严重: ********** FATAL ERROR STARTING UP STRUTS-SPRING INTEGRATION **********
Looks like the Spring listener was not configured for your web app!
Nothing will work until WebApplicationContextUtils returns a valid ApplicationContext.
You might need to add the following to web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2010-7-13 17:09:32 com.opensymphony.xwork2.util.logging.commons.CommonsLogger error
严重: Dispatcher initialization failed
java.lang.NullPointerException
at com.opensymphony.xwork2.spring.SpringObjectFactory.getClassInstance(SpringObjectFactory.java:209)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.verifyResultType(XmlConfigurationProvider.java:519)
it seems that the xwork2.spring.SpringObjectFactory just knows to find org.springframework.web.context.ContextLoaderListener,even my StartupListener is extending the ContextLoaderListener, it is really silly. So I just have to code a new java file org.springframework.web.context.ContextLoaderListener with the same name and same package.But I add the tiles codes there:
package org.springframework.web.context;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.tiles.ConfiguredServletContext;
import org.apache.struts2.tiles.StrutsTilesContainerFactory;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.TilesException;
import org.apache.tiles.access.TilesAccess;
import org.apache.tiles.factory.TilesContainerFactory;
@SuppressWarnings("unchecked")
public class ContextLoaderListener extends ContextLoader implements
ServletContextListener {
protected static final Log LOG = LogFactory
.getLog(ContextLoaderListener.class);
private ContextLoader contextLoader;
private static final Map INIT;
static {
INIT = new HashMap();
INIT.put(TilesContainerFactory.CONTAINER_FACTORY_INIT_PARAM,
StrutsTilesContainerFactory.class.getName());
}
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());
ServletContext servletContext = event.getServletContext();
try {
TilesContainer container = createContainer(servletContext);
TilesAccess.setContainer(servletContext, container);
} catch (TilesException e) {
throw new IllegalStateException("Unable to instantiate container.");
}
}
@Deprecated
protected ContextLoader createContextLoader() {
return null;
}
@Deprecated
public ContextLoader getContextLoader() {
return this.contextLoader;
}
public void contextDestroyed(ServletContextEvent event) {
ServletContext servletContext = event.getServletContext();
try {
TilesAccess.setContainer(servletContext, null);
} catch (TilesException e) {
LOG.warn("Unable to remove tiles container from service.");
}
if (this.contextLoader != null) {
this.contextLoader.closeWebApplicationContext(event
.getServletContext());
}
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
protected TilesContainer createContainer(ServletContext context)
throws TilesException {
if (context
.getInitParameter(TilesContainerFactory.CONTEXT_FACTORY_INIT_PARAM) == null) {
context = decorate(context);
} else {
LOG
.warn("Tiles container factory is explicitly set. Not injecting struts configuration.");
}
TilesContainerFactory factory = TilesContainerFactory
.getFactory(context);
return factory.createContainer(context);
}
protected ServletContext decorate(ServletContext context) {
return new ConfiguredServletContext(context, INIT);
}
}
then it works fine.
相关阅读 更多 +