tiles2的布局管理(一)spring+struts2+tiles2

本文介绍如何在Struts2框架中集成Tiles2实现页面布局管理,包括配置文件详解及常见问题解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值