from : http://www.iteye.com/topic/220133
共有如下几个步骤:
1) 首先在web.xml文件中配置TilesServlet,并加入一个Tiles Filter的filter类,这个类用于跳转页面。
Xml代码
<
filter> <filter-name>Tiles Filter</filter-name> <filter-class>net.geo.web.TilesFilter</filter-class> <init-param> <param-name>definitions-config</param-name> <param-value>/WEB-INF/classes/META-INF/tiles/tiles-defs.xml</param-value> </init-param> </filter> <filter-mapping> <filter-name>Tiles Filter</filter-name> <url-pattern>*.tiles</url-pattern> </filter-mapping> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class> org.apache.myfaces.webapp.MyFacesServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <servlet> <servlet-name>Tiles Servelt</servlet-name> <servlet-class> org.apache.struts.tiles.TilesServlet </servlet-class> <init-param> <param-name>definitions-config</param-name> <param-value>/WEB-INF/classes/META-INF/tiles/tiles-defs.xml</param-value> </init-param> <init-param> <param-name>definitions-parser-validate</param-name> <param-value>true</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet>
注意:这里Tiles Servelt的启动顺序(即load-on-startup)必须在Faces Servlet的后面。
2)配置tiles文件
这里是一个配置实例:
Xml代码
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration//EN" "http://jakarta.apache.org/struts/dtds/tiles-config.dtd"> <tiles-definitions> <definition name="mainlayout" page="/tiles_layout/layout.jsp"> <put name="header" value="/tiles_layout/header.jsp"></put> <put name="footer" value="/tiles_layout/footer.jsp"></put> </definition> <definition name="/jsfpro/account/register" extends="mainlayout"> <put name="title" value="to_register" type="string"></put> <put name="content" value="/account/register.jsp"></put> </definition> <definition name="/jsfpro/account/userlist" extends="mainlayout"> <put name="title" value="userlist" type="string"></put> <put name="content" value="/account/userlist.jsp"></put> </definition> </tiles-definitions> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration//EN" "http://jakarta.apache.org/struts/dtds/tiles-config.dtd"> <tiles-definitions> <definition name="mainlayout" page="/tiles_layout/layout.jsp"> <put name="header" value="/tiles_layout/header.jsp"></put> <put name="footer" value="/tiles_layout/footer.jsp"></put> </definition> <definition name="/jsfpro/account/register" extends="mainlayout"> <put name="title" value="to_register" type="string"></put> <put name="content" value="/account/register.jsp"></put> </definition> <definition name="/jsfpro/account/userlist" extends="mainlayout"> <put name="title" value="userlist" type="string"></put> <put name="content" value="/account/userlist.jsp"></put> </definition> </tiles-definitions>
注意:这里的其中的一个name="content"的put元素的valuet就是实际的内容页面的相对地址。
header.jsp、footer.jsp这些页面都可以是jsf标签的页面,但是,不能每个都用上<f:view>的标签,建议是在layout.jsp使用此标签,里面的分页都使用<f:subview id="xxx">标签。因为整个模板页就是通过jsf的方式来访问的,每个jsf页面只能有一个f:view。
3)主要的JSP页面
(1) /tiles_layout/layout.jsp
这个是布局页面,即页面的整体模板。
Html代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title><tiles:insert name="title" /></title> </head> <f:view> <body> <tiles:insert attribute="header" flush="false"></tiles:insert> <tiles:insert attribute="content" flush="false"></tiles:insert> <tiles:insert attribute="footer" flush="false"></tiles:insert> </body> </f:view> </html> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title><tiles:insert name="title" /></title> </head> <f:view> <body> <tiles:insert attribute="header" flush="false"></tiles:insert> <tiles:insert attribute="content" flush="false"></tiles:insert> <tiles:insert attribute="footer" flush="false"></tiles:insert> </body> </f:view> </html>(2) /tiles_layout/pageloader.jsp
这个是用于实际加载layout页面的页面,这个就是用来代替所有的需要为jsf页面重新定义tiles页面。
Html代码
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles"%> <tiles:insert definition="<%=(String)request.getAttribute("tiles-definition-page") %>"></tiles:insert> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-tiles" prefix="tiles"%> <tiles:insert definition="<%=(String)request.getAttribute("tiles-definition-page") %>"></tiles:insert> <%=(String)request.getAttribute("tiles-definition-page") %>这里会在运行时传入实际需要的tiles页面
(3) /tiles_layout/header.jsp
Html代码
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <f:subview id="header"> <div><h1>This is a header.</h1></div> </f:subview> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <f:subview id="header"> <div><h1>This is a header.</h1></div> </f:subview>
(4) /tiles_layout/footer.jsp
Html代码
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <f:subview id="footer"> <div><h1>This is a footer.</h1></div> </f:subview> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <f:subview id="footer"> <div><h1>This is a footer.</h1></div> </f:subview>
(5)/jsfpro/account/register.jsp
这个是实际的内容页,这里是一个实例,注册页
Html代码
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <f:subview id="content"> 请填写用户名和密码:<br> <h:form id="form" onsubmit="this.action='/jsfpro/account/userlist.tiles';return true;"> <h:inputText id="username" value="#{account.username}" /> <h:inputSecret id="password" value="#{account.password}" /> <h:commandButton action="#{accountMB.register}" value="注册"/> </h:form> </f:subview> <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <f:subview id="content"> 请填写用户名和密码:<br> <h:form id="form" onsubmit="this.action='/jsfpro/account/userlist.tiles';return true;"> <h:inputText id="username" value="#{account.username}" /> <h:inputSecret id="password" value="#{account.password}" /> <h:commandButton action="#{accountMB.register}" value="注册"/> </h:form> </f:subview>这里有一个设置是很有趣的:<h:form id="form" onsubmit="this.action='/jsfpro/account/userlist.tiles';return true;">
(6) /jsfpro/account/userlist.jsp
用户列表页
Html代码
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"%> <style> .thead1 { color: red; text-align: center; } .thead2 { color: blue; text-align: center; } </style> <f:view> <h:dataTable width="100%" id="datalist" var="item" value="#{accountMB.list}" cellspacing="1" border="1" cellpadding="5" columnClasses="#{account.columnClasses}"> <h:column> <f:facet name="header"> <h:outputText value="用户名" /> </f:facet> <h:outputText value="#{item.username}" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="密码" /> </f:facet> <h:outputText value="#{item.password}" /> </h:column> </h:dataTable> </f:view>
4)faces-config.xml的配置
Xml代码
<?xml version="1.0" encoding="utf-8"?> <faces-config 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-facesconfig_1_2.xsd" version="1.2"> <managed-bean> <managed-bean-name>accountMB</managed-bean-name> <managed-bean-class> net.geo.mbean.AccountManagedBean </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>account</managed-bean-name> <managed-bean-class>net.geo.vo.Account</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> <navigation-rule> <from-view-id>/jsfpro/account/register.jsp</from-view-id> <navigation-case> <from-outcome>userlist</from-outcome> <to-view-id>/jsfpro/account/userlist.tiles</to-view-id> </navigation-case> </navigation-rule> </faces-config> <?xml version="1.0" encoding="utf-8"?> <faces-config 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-facesconfig_1_2.xsd" version="1.2"> <managed-bean> <managed-bean-name>accountMB</managed-bean-name> <managed-bean-class> net.geo.mbean.AccountManagedBean </managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <managed-bean> <managed-bean-name>account</managed-bean-name> <managed-bean-class>net.geo.vo.Account</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> <navigation-rule> <from-view-id>/jsfpro/account/register.jsp</from-view-id> <navigation-case> <from-outcome>userlist</from-outcome> <to-view-id>/jsfpro/account/userlist.tiles</to-view-id> </navigation-case> </navigation-rule> </faces-config><to-view-id>/jsfpro/account/userlist.tiles</to-view-id>
这里设置的是.tiles是从注册页跳转到用户列表页,而用户列表页也是使用了layout.jsp这个页面模板,所有是.tiles后缀(.tiles在web.xml里面设置了,是用于请求模板形式的jsf页面)。
上面有
<h:form id="form" onsubmit="this.action='/jsfpro/account/userlist.tiles';return true;">,这个是因为使用了动态的pageloader.jsp页面后jsf框架都会将url最终转向pageloader.jsf,这样的话就相当于<from-view-id>/jsfpro/account/register.jsp</from-view-id>要改成<from-view-id>/tiles_layout/pageloader.jsp</from-view-id>,也就是所有的入口都是这个页面,这样的局限性有些大,有的时候可能需要为某个入口页做单独的navigation设置,就如上面的一样,而为了要达到这个目的,最简单的方法就是直接修改提交的form的action,让url变成你需要的那个jsf入口页的url地址。
5)TilesFilter类
Java代码
package net.geo.web; import java.io.FileInputStream; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class TilesFilter implements Filter { private final static Log logger = LogFactory.getLog(TilesFilter.class); private final static Set<String> uriSet = new HashSet<String>(); @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { if (req instanceof HttpServletRequest) { HttpServletRequest hreq = (HttpServletRequest) req; String uri = hreq.getRequestURI().replace(".tiles", ""); // 如果请求的uri(去掉.tiles的后缀之后)是包含在set中, // 那么就转发到pageloader.jsp页面,必须以jsf的形式请求 if (uriSet.contains(uri)) { hreq.setAttribute("tiles-definition-page", uri); hreq.getRequestDispatcher().forward(hreq, res, "/tiles_layout/pageloader.jsf"); return; } } chain.doFilter(req, res); } /** * 初始化filter类,主要是解析定义了的tiles文件, * 将<definition name="/jsfpro/account/register" extends="mainlayout">中的name属性的值拿出来, * 作为跳转的判断,放入set中 */ @SuppressWarnings("unchecked") @Override public void init(FilterConfig config) throws ServletException { String[] files = null; try { files = config.getInitParameter("definitions-config") .split("\\s|,"); } catch (Exception e) { throw new ServletException( "the parameter definitions-config is not correct.", e); } SAXReader reader = new SAXReader(); Document doc = null; List<Element> elList = null; List<Attribute> attList = null; try { for (String path : files) { doc = reader.read(new FileInputStream(AppConfigUtil.WEBROOT + path)); elList = doc.getRootElement().elements(); if (elList != null) { for (Element el : elList) { attList = el.attributes(); if (attList != null) { for (Attribute att : attList) { if (att.getName().equals("name")) { uriSet.add(att.getValue()); } } } } } } logger.info("TilesFilter init finished...."); } catch (Exception e) { throw new ServletException( "Can not parse the tiles-defs.xml file.", e); } } }
6)Account业务类
Java代码
package net.geo.mbean; import java.util.Collection; import net.geo.vo.Account; public class AccountManagedBean extends BaseManagedBean { public String register() { Account user = super.findBean(Account.class); facade.save(user); super.setRequestAttribute("myaccount", user); // 这里的returnTo方法的第一个参数是返回给jsf进行跳转的字符串 // 第2个参数是将相应要跳转的页面放置到request中, // 因为跳转的pageloader.jsp是动态的获取实际访问页面的参数的, // 所以在跳转之前必须指定。 // 如果是返回当前页则不需设定。 return returnTo("userlist", "/jsfpro/account/userlist"); } public Collection<Account> getList() { return facade.queryList(-1, -1); } /* * 以下是用到的相关的父类方法,贴出来供查看 */ protected HttpServletRequest getRequest() { return (HttpServletRequest) FacesContext.getCurrentInstance() .getExternalContext().getRequest(); } protected void setRequestAttribute(String attrName, Object obj) { getRequest().setAttribute(attrName, obj); } protected String returnTo(String outcome, String turnToUrl) { // 这里的参数名tiles-defenition-page就是在pageloader.jsp页面中 // 指定要跳转的实际页面的参数名 setRequestAttribute("tiles-defenition-page", turnToUrl); return outcome; } }