Вы находитесь на странице: 1из 12

Rapidly implementing portal look-and-feel using

Struts Tiles and the Portlet Framework in


WebSphere Application Server V6.1

Introduction
Beginning with Version 6.1, WebSphere Application Server provides an embedded JSR168 portlet container.
You can now deploy portlets, which could previously only be deployed to a portal server (such as IBM
WebSphere Portal, hereafter called WebSphere Portal), to Application Server V6.1.
This capability provides several major advantages:
1. You can write portlets as reusable components, use them first in Application Server, and later use them
in a JSR 168-compatible portal server (such as WebSphere Portal) to use more advanced features in the
portal server.
2. You can integrate standard portlets that are written by others, from open source or commercial portlet
catalogs (such as the WebSphere Portal catalog), in Application Server.
3. You can deploy a portlet along side a servlet to meet various business needs. For example, you might
want to use portlets to provide an aggregated view of various data, and use servlets to handle complex a
user interface with lots of page flows.
4. Your application is more portable to pervasive devices with various screen sizes because portlets, which
each occupy a small rectangle region on a page, can be easily rendered on a pervasive device. For
example, your application might specify a single portlet to occupy the entire screen in a cellular phone;
two portlets in a pocket PC side-by-side; and, multiple portlets to be rendered into a Web browser.
However, Application Server 6.1 does not provide the extended features and capabilities that are normally built
into a portal server (such as WebSphere Portal). A key feature for a portal is its customizable look-and-feel. In
a portal server, customization and personalization are usually handled dynamically through configuration. For
example, you can dynamically personalize page themes and skins based on user groups, and you can assign
specific user groups permissions to use portlets at runtime. If you want to use these features in Application
Server, you have to write them yourself. In addition, aggregation in Application Server is accomplished
programmatically using the aggregation tag library. If you want to display multiple portlets in a page, you need
to write code to do so using the aggregation tag library. (See the article series "Exploiting the WebSphere
Application Server V6.1 portlet container", listed in Resources).
The Tiles framework provides a mechanism to define common layouts for reuse as theme templates in a portal.
You combine tiles (as theme templates) and portlet aggregation (as page content) to quickly implement a portal
look-and-feel in Application Server. You define page layouts (themes) using the Tiles tag library, and assemble
portlets using the portlet aggregation tag library. Then, you link the aggregated portlets to the tiles in the page
layout. Both Tiles and portlet tags can take parameters, so you can create a customized look-and-feel, as well
as dynamic content.
This article introduces you to integrating Struts Tiles tags and portlet aggregation tags in Application Server to
create customized portal pages and a portal look-and-feel. You learn how to:
1. Create page, menu, and portlet layouts using Tiles tags and portlet aggregation tags.
2. Use the layouts to create customized pages.
3. Assemble the layouts into your portal.
The sample code is for demo purpose only. However, you can use the techniques provided in this article to
implement a more customer-oriented look-and-feel for your own application. Readers should have a basic
knowledge of Tiles, portlets, and portlet frameworks in Application Server V6.1, and know how to create and
use them. The portlets used in this article are from IBM and Sun sample JSR 168 portlet code (see Resources).
The sample portlets are re-packaged in the WebSphere Application Server Toolkit 6.1 so you can deploy them
to Application Server.
Back to top
Using Tiles and the Portlet Aggregation Framework together
As an example, let's examine a classic portal layout, which consists of header, menu, body, and footer regions
(Figure 1). You can think of each region as a tile whose content can be passed as a parameter (a page, page
segment, or a string). You can define the menu and body regions as templates in menu layout and body layout,
respectively, as shown in Figure 1. The menu layout consists of dynamic pages, each of which links to a
different set of portlets aggregated in a portlet layout. You can group sub-pages into a page, organized for a
specific purpose. The portlet layout in the body region consists of various numbers of portlets aggregated using
the portlet aggregation tags provided in Application Server.
You can create a unique portal look-and-feel in Application Server 6.1 in two ways.
1. By passing different parameters (page, page segment, strings, or portlets) to the tiles and sub-tiles in the
layouts, based on the user who makes a request to customize portal pages.
2. By changing the layouts, or by using multiple layouts. You can change page layout for a different
theme, change portlet layout for a different skin, and change menu layout to modify the placement of
the menu.
For example, you might want a top horizontal, rather than a top-down, tree-based page navigation menu. You
can always create multiple layouts for use in different pages and for different user groups. For example, you
might want administrative portal pages to use different page, menu, and portlet layouts to differentiate their
interface from the user interface.
Figure 1. A classic portal layout

Back to top
Creating the portal layout
The following sections show you how to create page, menu, and portlet layouts using Tiles and the portlet
aggregation tags, respectively.
Creating a page layout
Page layout provides a common theme for all pages in a portal. Each page in a portal invokes the page layout
and passes the parameters (pages or page segments) to the tiles defined in the page layout. Listing 1 shows a
classic page layout which inserts five tiles (title, header, menu, body and footer) using the <tiles:insert /> tag
in different regions of a table, as shown in Figure 1. The regions occupied by the tiles will be filled by
parameters passed in from a calling JSP page.
Listing 1. Classic page layout including tiles for each region
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<tiles:importAttribute />
<html>
<head>
<logic:present name="title">
<title><tiles:getAsString name="title" ignore="true"/></title>
</logic:present>
</head>
<body>
<table border="0" cellspacing="0" cellpadding="0" width="100%"
bgcolor="#F8FBFE">
<tr>
<td align="left" colspan="2">
<tiles:insert attribute="header" ignore="true">
<tiles:put name="title" beanName="title" beanScope="tile"/>
</tiles:insert>
</td>
</tr>
<tr><td>&nbsp;</td></tr>
<tr>
<td valign="top">
<ul>
<tiles:insert attribute="menu" />
</ul>
</td>
<td>
<div align="center">
<tiles:insert attribute="body" />
</div>
</td>
</tr>
</table>
<tiles:insert attribute="footer" ignore="true"/>
</body>
</html>
Creating page navigation
The portal menu displays a list of pages which the user who is currently logged in to the portal can view.
Listing 2 shows how to code a menu layout to display a list of page names and links. Each link refers to a set of
portlets aggregated in the portal body.
Listing 2. Portal page menu layout
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<tiles:useAttribute id="items" name="items" classname="java.util.List" />
<logic:iterate id="item" name="items"
type="org.apache.struts.tiles.beans.SimpleMenuItem">
<bean:define id="link" name="item" property="link" type="java.lang.String"/>
<logic:match name="link" location="start" value="/" >
<A href="<%=link%>" >
<bean:write name="item" property="value"/>
</A>
</logic:match>
<logic:notMatch name="link" location="start" value="/" >
<A href="<%=request.getContextPath()%>/<%=link%>">
<bean:write name="item" property="value"/>
</A>
</logic:notMatch>
<P/>
</logic:iterate>
The menu layout in Listing 2 uses the Struts logic tag to iteratively display page names and links. The pages
and their links are passed in a list (java.util.List) of beans (org.apache.struts.tiles.beans.SimpleMenuItem)
by the calling JSP page. If a link that is passed in the bean refers to an absolute URL (starting with "/"), it is
copied over and displayed. Otherwise, the link is appended to the page context obtained using
request.getContextPath(), and then displayed.
Creating a portlet layout
A portal body contains portlets in various columns and rows. The portlet layout defines a grid of cells, for each
portlet in the portal body region. Listing 3 shows the coding for a portlet layout that shows a tabular view of
portlet placements in the body region. In the layout, the number of columns in the portal body is passed from
calling JSP as a string. The portlet URLs, supported modes for each portlet, and the initial portlet mode are all
passed in a list of utility beans (com.jktelecom.PortletInfo) from a calling JSP page. Therefore, a calling JSP
page has total control over the number of portlets and the placement, initial mode, and supported modes of
each portlet in a page, so you don't have to modify the portlet layout for each portlet.
The portlet layout uses the number of columns and size of the portlet list (both of which are passed by the
calling JSP page) to determine the number of rows and cells in which portlets are rendered. The portlet layout
iterates through the list in the order originally inserted into the list. It places the supported portlet modes in the
<portlet:state> tag, and the portlet URI in the <portlet:insert> tag so that the modes and portlet content
can be dynamically rendered to the corresponding cell. The portlet modes, with proper links, will be displayed
along with the portlet title, which is retrieved from the portlet deployment descriptor (portlet.xml) by
<portlet:insert> tag.
Listing 3. Portlet layout
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="http://ibm.com/portlet/aggregation" prefix="portlet" %>
<%@ page import="java.util.*" %>
<%@ page import="com.jktelecom.*" %>
<%@ page isELIgnored ="false" %>
<%
String page_uri = (String)session.getAttribute("Current_Page");
String uri_prefix = PageInfo.getPageName(page_uri) +"/";
%>
<portlet:init portletURLPrefix="<%=uri_prefix%>" >
<tiles:importAttribute />
<table border="1">
<%-- Prepare the links list to be iterated --%>
<bean:define id="portlets" name="portlets" type="java.util.List" />
<bean:define id="numColumns" name="numColumns" type="java.lang.String" />
<%
int cols = Integer.parseInt(numColumns);
Iterator loop = portlets.iterator();
int portlet_count = 0;
while (loop.hasNext()) {
%>
<!-- create portal table with number columns defined by variable cols -->
<tr bgcolor="#e0eaf8">
<%
String[] portRefs = new String[cols];
for (int i=0; i < cols; i++) {
if (!loop.hasNext()) {
break;

}
PortletInfo portletInfo = (PortletInfo)loop.next();
portRefs[i] = portletInfo.getName();
String windowId = String.valueOf(portlet_count);
%>
<!-- insert portlet title bar -->
<td>
<table width="100%">
<tr>
<td>
<b><span id="title_<%=portlet_count%>">Portlet <%=
portlet_count%></span></b>
</td>
<td align="right">
<%
String portletName = portletInfo.getName();
String[] portletModes = portletInfo.getSupportedModes(portletName);
for (int j=0; j < portletModes.length; j++ ) {
%>
<a href="<portlet:state url='<%=portletName%>'
windowId='<%=windowId%>'
portletMode='<%=portletModes[j]%>' />">
<%=portletModes[j]%> </a>
<%
}
%>
&nbsp; &nbsp;
</td>
</tr>
</table>
</td>
<%
portlet_count++;
}
%>
</tr>
<tr>
<%
for (int k=0; k < cols; k++) {
int title_num = portlet_count-cols+k;
String windowId = String.valueOf(title_num);
%>
<td>
<!-- insert portlet -->
<portlet:insert url="<%=portRefs[k]%>" windowId="<%=windowId%>"
titleVar="title" />
</td>
<!-- insert portlet title -->
<script type="text/javascript">
document.getElementById("title_<%=title_num%>").firstChild.nodeValue = "${title}";
</script>
<%
}
%>
</tr>
<tr><td colspan="<%=cols%>">&nbsp;</td></tr>
<%
}
%>
</table>
</portlet:init>
You need to address the following issues in the portlet layout, as seen in Listing 3.
Setting the URL prefix
You need to specify a proper URL prefix for the portletUrlPrefix attribute in the init portlet aggregation
tag.
The prefix is used in portlet URLs created by the state and insert tags. It consists of two parts: aggregation
context and aggregator mapping. If you use a relative path for the URL, the portlet container will take care of
the aggregation context for you. However, if you use an absolute path for the URL (for example,
/jkTelecom/Tools/), when you deploy your portal application (WAR) to Application Server, you must
specify the same context root (jkTelecom) that you used in the aggregation context. You must configure the
aggregation mapping part in the URL in the Web application deployment descriptor (web.xml) to point to the
URL referenced by the current page, which displays the portlet aggregation (portlet layout).
For example, if the current portlet aggregation is invoked by the Tools page, which refers to tools.jsp, then
the portlet URL must map to tools.jsp You will learn the details about the mapping below in the Portal
configuration section.
To set proper aggregator mapping, you must track the page the user is currently reviewing and set the
aggregation mapping accordingly. The sample code handles the tracking as follows:
1. When a user clicks a page link from the menu, the code stores the page URL in the users session (for
example, tools.jsp):
2. <%
3. String current_page = "tools.jsp";
4. session.setAttribute("Current_Page", current_page);
%>
5. It retrieves the URL from the session in the portlet layout (portletLayout.jsp).
6. <%
7. String page_uri = (String)session.getAttribute("Current_Page");
8. String uri_prefix = PageInfo.getPageName(page_uri) +"/";
%>
9. It obtains the mapping for the URL from a map defined in the PageInfo.java class (Listing 4). The
utility class, PageInfo.java, contains all the mappings to URLs which correspond to the mapping in
web.xml.
Listing 4. Page mappings
static HashMap pages;
static {
pages = new HashMap();
pages.put("index.jsp", "Home");
pages.put("account.jsp", "Account");
pages.put("tools.jsp", "Tools");
pages.put("reports.jsp", "Report");
pages.put("services.jsp", "Services");
...
}
public static String getPageName(String uri) {
return (String)pages.get(uri);
}
10. Finally, the aggregator mapping is assigned to the portletURLprex attribute of the init tag of the portlet
aggregator.
<portlet:init portletURLPrefix="<%=uri_prefix%>"
Handling portlet mode
Each portlet normally supports different modes (such as view, edit, and help) whose icons are usually
displayed along with the portlet title in a portal. You must know what modes a portlet supports before
displaying the icons. Otherwise, either a supported mode is missing from your portlet (if you dont display the
icon for the mode), or an exception will be thrown (if the displayed mode is not supported by the portlet).
Portlet mode information is available in the <supports> section of the portlet deployment descriptor (Listing
5).
Listing 5. Portlet deployment descriptor (portlet.xml) fragment
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>config</portlet-mode>
<portlet-mode>edit</portlet-mode>
<portlet-mode>help</portlet-mode>
</supports>
Unlike portlet title, which can be retrieved using the portlet aggregation tag <portlet:insert>, no portlet
aggregation tag is available to help you retrieve the supported modes. You must view the portlet deployment
descriptors to retrieve them yourself. Supported modes for all the portlets used in the sample code are stored in
a hash map, so that they can be retrieved dynamically (Listing 6):
Listing 6 Supported portlet modes
static HashMap supportedModes;
static {
supportedModes = new HashMap();
supportedModes.put("IBMSamples/HelloWorld", new String[]{"view"});
supportedModes.put("IBMSamples/WorldClock", new String[]{"view", "edit",
"help"});
supportedModes.put("IBMSamples/SQLQuery", new String[]{"view"});
supportedModes.put("IBMSamples/HelloJSP", new String[]{"view"});
supportedModes.put("SunSamples/JSPPortlet", new String[]{"edit", "help"});
supportedModes.put("SunSamples/NotepadPortlet", new String[]{"edit", "help"});
supportedModes.put("SunSamples/BookmarkPortlet", new String[]{"edit", "help"});
}
public String[] getSupportedModes(String portletName) {
return (String[])supportedModes.get(portletName);
}
Back to top
Assembling the portal
In this part, you see how to write JSPs to use the page, menu, and portlet layouts to create tailored portal pages.
You also see how to configure the Web application descriptor (web.xml) to support portlet aggregation
mappings.
Using the page layout
The calling JSP page passes parameters to be inserted into the page layout. A parameter can be another JSP
page, a page segment, or a simple string, depending on the current user and the content to be displayed to the
user.
Listing 7 shows the coding for a default page layout definition that specifies default parameters passed to the
page layout. For example, the header.jsp file is passed to the header tile, and the footer.jsp file is passed to the
footer tile in the page layout.
Listing 7. Default page layout definition
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<logic:notPresent name="pageLayoutDef" scope="request" >
<tiles:definition id="pageLayoutDef" page="/pageLayout.jsp" scope="request" >
<tiles:put name="title" type="string" value="jkTelecom Portal" />
<tiles:put name="header" value="/header.jsp" />
<tiles:put name="footer" value="/footer.jsp" />
<tiles:put name="body" value="/default_body.jsp" />
<tiles:put name="menu" value="/default_menu.jsp" />
</tiles:definition>
</logic:notPresent>
A calling JSP page can also override the default behavior defined in the page layout definition by passing
different parameters. In Listing 8, a calling JSP page (tools.jsp) uses the page layout definition in Listing 7; it
overrides the default menu page (default_body.jsp) and body page (default_menu.jsp) using menu.jsp and
portlets.jsp.
Listing 8. A portal page (tools.jsp) which uses the page layout
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%
String current_page = "tools.jsp";
session.setAttribute("Current_Page", current_page);
%>
<jsp:include page="/pageLayoutDef.jsp" />
<tiles:insert beanName="pageLayoutDef" flush="true" beanScope="request">
<tiles:put name="body" value="/portlets.jsp" />
<tiles:put name="menu" value="/menu.jsp" />
</tiles:insert>
Using page navigation
Listing 9 shows a portal menu (menu.jsp) using the menu layout. The portal menu uses jsp:useBean to create
an instance of SimpleMenuItem. Then, it uses jsp:setProperty to set the link and value properties of the
SimpleMenuItem bean. Finally, it adds the bean to the list using tiles:add.
The menu is customized on a user group basis to create role-based pages without modifying the menu layout.
Therefore, a page is visible only if the user is in a specific role and has permission to the page. The user role is
determined by the isUserInRole method of the request object.
Listing 9. A portal page menu which uses the menu layout
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<tiles:importAttribute />
<tiles:insert page="/menuLayout.jsp" flush="false" >

<tiles:putList name="items" >
<jsp:useBean id="item_0" class="org.apache.struts.tiles.beans.SimpleMenuItem" />
<jsp:setProperty name="item_0" property="link" value="index.jsp" />
<jsp:setProperty name="item_0" property="value" value="Home" />
<tiles:add beanName="item_0" />
...
<%
if (request.isUserInRole("Managers")){
%>
<jsp:useBean id="item_4" class="org.apache.struts.tiles.beans.SimpleMenuItem" />
<jsp:setProperty name="item_4" property="link" value="tools.jsp" />
<jsp:setProperty name="item_4" property="value" value="Tools" />
<tiles:add beanName="item_4" />
...
<%

} else if (request.isUserInRole("Users")) {
%>
<jsp:useBean id="item_8" class="org.apache.struts.tiles.beans.SimpleMenuItem" />
<jsp:setProperty name="item_8" property="link" value="services.jsp" />
<jsp:setProperty name="item_8" property="value" value="Services" />
<tiles:add beanName="item_8" />
...
<%
}
%>
</tiles:putList>
</tiles:insert>
Using the portlet layout
Listing 10 shows a JSP page (menu.jsp) which uses the menu layout. The number of columns in which portlets
are rendered in the body, and a list of beans (com.jktelecom.PortletInfo) created by <jsp:useBean> are passed
to the portlet layout. The bean contains all the information (portlet URL, initial mode, and supported modes)
the portlet layout needs to render the portlets.
Listing 10. A JSP page which uses portlet layout
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<%@ page import="java.util.*" %>
<%@ page import="com.jktelecom.*" %>
<tiles:insert page="/portletLayout.jsp" flush="false" >
<!-- create portal table of two columns -->
<%
if (request.isUserInRole("Managers")) {
%>
<tiles:put name="numColumns" value="3" />
<%
} else {
%>
<tiles:put name="numColumns" value="2" />
<%
}
%>
<!-- pass portlet links -->
<tiles:putList name="portlets" >
<jsp:useBean id="portlet_0" class="com.jktelecom.PortletInfo" />
<jsp:setProperty name="portlet_0" property="name"
value="IBMSamples/HelloWorld" />
<jsp:setProperty name="portlet_0" property="initialMode"
value="<%=PortletInfo.VIEW%>" />
<tiles:add beanName="portlet_0" />
<%
if (request.isUserInRole("Managers")) {
%>
<jsp:useBean id="portlet_1" class="com.jktelecom.PortletInfo" />
<jsp:setProperty name="portlet_1" property="name"
value="SunSamples/JSPPortlet" />
<jsp:setProperty name="portlet_1" property="initialMode"
value="<%=PortletInfo.EDIT%>" />
<tiles:add beanName="portlet_1" />

<%
} else if (request.isUserInRole("Users")) {
%>
<jsp:useBean id="portlet_6" class="com.jktelecom.PortletInfo" />
<jsp:setProperty name="portlet_6" property="name"
value="IBMSamples/WorldClock" />
<jsp:setProperty name="portlet_6" property="initialMode"
value="<%=PortletInfo.VIEW%>" />
<tiles:add beanName="portlet_6" />

<%
}
%>
</tiles:putList>
</tiles:insert>
As shown in Listing 8, the number of columns and the list of portlets are set on a role basis. You can also
control permissions to the portlets from your calling JSP. You can implement these customizations in several
ways:
1. A portlet is visible to a user only if the user is in certain role and has permission to it; therefore, you can
selectively pass portlets to the portlet layout for a specific user or user group. Users without permissions
to the portlets will not see them in their portal.
2. You can further limit available supported modes of a portlet for certain users or groups for a finer-
grained control of privileges. For example, you might choose to block the anonymous users ability to
edit the portlet by only displaying the edit icon to authenticated users.
3. You can pass the number of portlets and the number of columns to the portlet layout without modifying
the portlet layout.
Back to top
Configuring the portal
When integrating multiple pages which contain portlets into a portal, you need to take special actions to handle
the portlet URL. When a user clicks on a different portlet mode, all other portlets as well as the entire page are
refreshed, and form data in the portlet is re-posted.
1. When you use the aggregation tag library, you must set the portletUrlPrefix attribute of the init tag
to the proper aggregator context and mapping. The aggregator context is the context root of the current
application. The aggregator mapping must reference the current page, as described in the portlet layout
section above.
2. You need to define mappings for all the portal pages in the application deployment descriptor
(web.xml) so that the aggregator mappings reference valid JSP pages (Listing 11). The mappings
defined in web.xml are available in the utility class PageInfo.java so the mappings can be retrieved
directly.
Listing 11. Portal application deployment descriptor (web.xml)

<servlet>
<servlet-name>Home</servlet-name>
<jsp-file>index.jsp</jsp-file>
</servlet>
<servlet>
<servlet-name>Tools</servlet-name>
<jsp-file>tools.jsp</jsp-file>
</servlet>

<servlet-mapping>
<servlet-name>Home</servlet-name>
<url-pattern>/Home/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Tools</servlet-name>
<url-pattern>/Tools/*</url-pattern>
</servlet-mapping>

In Listing 11, a JSP page (index.jsp) is defined as an implementation of an imaginary servlet Home. The
aggregation mapping pattern /Home/* is referred to the Home servlet. A URL with the pattern /Home/* will
dynamically resolve to the JSP page (index.jsp). This mapping relationship is shown in the Figure 2, which
illustrates how the mappings from web.xml are shown in the URLs for links to portlet mode icons.
For example, when a relative URL Home is specified to an aggregator mapping in the portletUrlPrefix
attribute of the init tag (jkTelecom is the context root), the aggregation pattern /Home/ will be resolved as
index.xml. When a user clicks any icon (view, edit, and help) for a portlet in the page, the form data in the
portlet mode requested is re-posted, and the entire page, including all other portlets, is refreshed as well. Figure
2 illustrates this mapping relationship.
Figure 2. Mapping relationship

Back to top
Deploying the portal
You package the application as a WAR file and deploy it as any Web application. Figures 3 and 4 show the
deployed portal for the example code. The context root is specified as jkTelecom. If you use a relative path for
the PortletUrlPrefix attribute in the init tag (as discussed in the portlet layout section), you can use any
string as the context root. Otherwise, you must specify the same context root as you used in the aggregation
context.
Figure 3. Deployed portal with user sara in the "Managers" role

Figure 4. Deployed portal with user fred in the "Users" role

Back to top
Conclusion
Now you know how to create common portal layouts (page, navigation, and portlet layouts) as reusable
templates using Struts Tile tags and portlet aggregation tags. You can use the layouts to create dynamic web
pages, and you can assemble the layouts into a portal. You have seen how to address various development and
deployment issues to ease the development effort. Now you can apply the information presented here to create
your own portal pages using the WebSphere Application Server portlet container and aggregation tags.

Вам также может понравиться