Apache Struts 2 Documentation > Home > Tutorials > Portlet Tutorial (WebWork 2.2) |
Check out the new updated Struts 2 Portlet Tutorial |
The Portlet support is experimental. Feedback is appreciated! |
This tutorial walks you through the process of building a simple portlet application, using Eclipse, JBoss Portal 2.2 and the WebWork Portlet framework.
In the tutorial, we will be using Eclipse 3.1.1 which can be downloaded from http://www.eclipse.org
JBoss Portal 2.2 can be found at http://www.jboss.com/products/jbossportal/downloads.
A Portlet application is basically packaged as a regular web application, but with an additional descriptor; portlet.xml. The first step of the tutorial is to create the project structure in eclipse. First, let's create the Java project itself using the new project wizard. We call the project 'MyPortlet'. Make sure to select the "Create separate source and output folders" radio button, and hit "next". In the next wizard step, set the output folder for the 'src' source folder to 'MyPortlet/webapp/WEB-INF/classes'. This makes sure it will be easy for us to export the application as a WAR file when we're done.
New project wizard
New project wizard, cont
Before buliding the application itself, we need to add some required jar files to the build classpath and the WEB-INF/lib folder. Firstly, create the WEB-INF/lib folder and download the WebWork 2.2.1 distribution and unzip it to your local harddrive. Locate the jar files shown in the screenshot and and put them in the newly created WEB-INF/lib folder. Select all the jar files, and right click and select "Build Path -> Add to Build Path". Now your local project should look similar to the screenshot.
If there are jar files here that aren't included in the webwork distribution you have downloaded, you can safely assume that they are not needed. |
Next thing we do is create a portlet.xml file in the WEB-INF folder. In this file, write the following:
<portlet-app version="1.0" xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"> <portlet> <description xml:lang="EN">My very first WebWork Portlet</description> <portlet-name>MyPortlet</portlet-name> <display-name xml:lang="EN">My first WebWork Portlet</display-name> <portlet-class>com.opensymphony.webwork.portlet.dispatcher.Jsr168Dispatcher</portlet-class> <init-param> <!-- The view mode namespace. Maps to a namespace in the xwork config file --> <name>viewNamespace</name> <value>/view</value> </init-param> <init-param> <!-- The default action to invoke in view mode --> <name>defaultViewAction</name> <value>index</value> </init-param> <expiration-cache>0</expiration-cache> <supports> <mime-type>text/html</mime-type> </supports> <supported-locale>en</supported-locale> <portlet-info> <title>My very own WebWork Portlet</title> <short-title>WWPortlet</short-title> <keywords>webwork,portlet</keywords> </portlet-info> </portlet> </portlet-app>
This portlet.xml file sets up the portlet using the com.opensymphony.webwork.portlet.dispatcher.Jsr168Dispatcher Portlet implementation. It also tells the Portlet that it will map the view portlet mode to a /view namespace in the XWork configuration, which we must remember when building our XWork actions. In addition, it tells the portlet that if it does not find an action parameter in the portlet request, the default action to invoke is the "index" action, which
should reside in the /view namespace in our xwork configuration.
The WebWork Portlet support also requires you to include a web.xml descriptor that sets up some special servlets and filters needed to enable support for the WebWork tag libraries and template languages, since it relies on some of the interfaces and classes in the Servlet API. So create a web.xml file in the WEB-INF folder, and add the following:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <filter> <filter-name>webwork</filter-name> <filter-class> com.opensymphony.webwork.dispatcher.FilterDispatcher </filter-class> </filter> <filter-mapping> <filter-name>webwork</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class> com.opensymphony.webwork.portlet.context.ServletContextHolderListener </listener-class> </listener> <servlet> <servlet-name>preparator</servlet-name> <servlet-class> com.opensymphony.webwork.portlet.context.PreparatorServlet </servlet-class> </servlet> <taglib> <taglib-uri>/webwork</taglib-uri> <taglib-location>/WEB-INF/lib/webwork-2.2.1.jar</taglib-location> </taglib> </web-app>
The FilterDispatcher makes sure that URLs to stylesheets and js files within the webwork jar file resolve correctly. The ServletContextHolderListener is a Servlet context listener that stores a reference to the servlet context of the web application. This is needed by some of the initialization procedures used in the WebWork Portlet. The 'preparator' servlet is a special servlet that, before dispatching to a view (like JSP/ftl or velocity) initializes the HttpServletRequest/Response, and other Servlet API classes in the ServletActionContext that is used in many of the JSPs and templates.
With these basic project structure, portlet.xml and web.xml in place, it's time to do the mandatory "Hello World" example, so let's create a place to store our JSP files. Create a WEB-INF/pages/view folder, and within this folder, create the file "helloWorld.jsp". In this file, we simply put:
<H2>Hello world!</H2>
At this point, it's time to prepare the xwork configuration file, xwork.xml. Create an empty file named xwork.xml in the root of the 'src' folder. In this file we put:
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd"> <xwork> <include file="webwork-portlet-default.xml" /> <package name="view" extends="webwork-portlet-default" namespace="/view"> <action name="index" class="com.opensymphony.xwork.ActionSupport"> <result name="success">/WEB-INF/pages/view/helloWorld.jsp</result> </action> </package> </xwork>
If you're using version 2.2.1 of WebWork, include the file webwork-default.xml instead. |
Some important things to notice are that we create a package with namespace view, and our package extends the webwork-portlet-default package. The webwork-portlet-default package contains some special result types needed to run WebWork/XWork in a portlet container.
In addition to the regular portlet.xml and web.xml descriptors, JBoss Portal 2.2 requires us to add a couple of JBoss specific descriptor files. On of these descriptor files is named according to the name of the context root of our application, which in this case is the name of the exported war file itself. We will later create a war file named MyPortlet.war, so the name of the JBoss descriptor becomes 'MyPortlet-object.xml'. So we create this file in the WEB-INF folder, and insert the following text:
<?xml version="1.0" encoding="UTF-8"?> <deployments> <deployment> <if-exists>overwrite</if-exists> <parent-ref>default</parent-ref> <properties /> <page> <page-name>MyPortlet Tutorial</page-name> <properties /> <window> <window-name>MyPortletWindow</window-name> <instance-ref>MyPortletInstance</instance-ref> <region>center</region> <height>0</height> </window> </page> </deployment> <deployment> <if-exists>overwrite</if-exists> <instance> <instance-name>MyPortletInstance</instance-name> <component-ref>MyPortlet.MyPortlet</component-ref> </instance> </deployment> </deployments>
In addition, we need two other files, jboss-app.xml and jboss-portlet.xml which looks like this:
<jboss-app> <app-name>MyPortlet</app-name> </jboss-app>
<portlet-app> <portlet> <portlet-name>MyPortlet</portlet-name> <security> </security> </portlet> </portlet-app>
Now we have a project structure that looks like this:
Project structure
Now it's time to try our incredible HelloWorld portlet. In a Windows Explorer session, we select the WEB-INF folder and zip it up and name the file 'MyPortlet.war'. Drop this war file in the server/default/deploy folder of JBoss Portal, and start the server. By default, the URL for JBoss portal is http://localhost:8080/portal, so point your browser to this address, and you will get to the front page of the portal, where you should get a "MyPortlet Tutorial" menu entry, as shown in the screenshot below. When pressing this menu link, you will get to our fantastic "Hello World" page!
JBoss Portal front page
MyPortlet portlet page
Next, let's do something a bit more interesting, namely create a simple form and display a result page. Let's start by creating our JSP that displays our form. Create a new file, 'helloForm.jsp' in the WEB-INF/pages/view/ folder. We will use the WebWork tag library to build the form on our page. The form itself will ask the user for a first name and last name, something like this:
<%@ taglib uri="/webwork" prefix="ww" %> <H2>Hi there! Please enter your name</H2> <ww:form action="helloWorld" method="POST"> <ww:textfield label="First name" name="firstName" value="%{firstName}"/> <ww:textfield label="Last name" name="lastName" value="%{lastName}"/> <ww:submit value="Say hello!"/> </ww:form>
Now we're ready to code some Java, not much, but at least a little bit. We create a new package in our src folder, let's name it com.opensymphony.webwork.portlet.tutorial. In this package, create a HelloWorldAction class. In usual WebWork manners, this class extends the ActionSupport class from the XWork framework, and we'll add a couple of properties that maps to our form in the JSP we just created:
package com.opensymphony.webwork.portlet.tutorial; import com.opensymphony.xwork.ActionSupport; public class HelloWorldAction extends ActionSupport { private String firstName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
We also need a JSP to display the processed input. We'll just use the old helloWorld.jsp and modify it a bit. As with helloForm.jsp, we import the WebWork tag library, and we use the ww:property tags to display the input from the form:
<%@ taglib prefix="ww" uri="/webwork" %> <H2>Hello <ww:property value="firstName"/> <ww:property value="lastName"/></H2> <p/> <a xhref="<ww:url action="helloWorldInput"/>">Back to form</a>
Now we're ready to do a re-deployment of our application, so zip up a new war and drop it in the server/default/deploy folder. The "MyPortlet Tutorial" page will now display:
Hello World form
Enter some data, and press the "Say hello!" button, and you will get a nice little personalized "hello" message:
Personalized Hello World