Developing a Spring Portlet MVC Framework application for use inside IBM WebSphere Portal: Introduction to Spring Portlet MVC Framework

This article shows you how to build a simple HelloWorld portlet application using Spring Portlet MVC Framework for deployment in IBM WebSphere Portal. It is intended for portlet developers and architects who want to use the open source MVC Framework for developing their portlets.

Sunil Patil (spatil@atech.com), Senior Consultant, Ascendant Technology LLC

Sunil Patil is a Senior Consultant working at Ascendant Technology, LLC. He is the author of several IBM developerWorks articles and a book, Java Portlets 101.



20 February 2008 (First published 05 February 2008)

Also available in Russian

This article is the first in a three-part article series, "Developing a Spring Portlet MVC Framework application for use inside IBM WebSphere Portal." This is an advanced article; you should be familiar with the basics of developing JSR-168 portlets and have a basic understanding of Spring Framework although no advanced knowledge is required.

In the last couple of years, Spring Framework has gained in popularity among J2EE developers. It provides infrastructure code to make J2EE development easy so that you can concentrate on implementing business logic of applications instead of worrying about things such as implementing your own MVC Framework or object-relational mapping framework.

Version 1.0 of Spring Framework has Web MVC Framework, which can be used for developing servlet-based applications. Starting with version 2.0, Spring Framework ships with Portlet MVC Framework, which is a replica of its Web MVC Framework. It can be used for developing JSR-168-compliant portlet applications.

These are some of the advantages of Spring Portlet MVC Framework:

  1. You can deploy portlets developed using Portlet MVC Framework in any JSR-168-compliant portlet container without making any changes. On the other hand, portlets developed using IBM Struts Portlet Framework or IBM JSF Framework have a dependency on IBM WebSphere Portal runtime.
  2. Most other portlet MVC Frameworks try to encapsulate the portlet's action and render phases of request processing into one phase. This is not the case with Spring Portlet MVC Framework; it understands that the portlet's two-phase request processing is better than the servlet's one-phase request processing, and it tries to take advantage of that. The Controller.java class that defines the basic interface for handling requests in Portlet MVC Framework (the equivalent of action in the Struts Framework) defines handleActionRequest() and handleRenderRequest() methods. This approach gives you much more flexibility while building your application.
  3. Spring Portlet MVC Framework provides easy integration with popular view-rendering technologies such as JSTL, Apache Tiles, Apache Velocity, and FreeMarker.
  4. The Portlet MVC Framework provides a mock testing framework that you can use for test-driven development of your portlet.

This article is a step-by-step tutorial on Spring Portlet MVC Framework. We assume that you are already familiar with the basics of Spring Framework as well as JSR-168-compliant portlet development though no advanced knowledge is required.

In this article, we talk about how to set up your development environment for Spring Portlet MVC Framework, and then we discuss how to develop a simple HelloWorld application in Spring Portlet MVC Framework. We also look at how the render request is handled. We finish by showing how you can add support for Help and Edit mode in your portlet.

Setting up the development environment

First, you should set up your development environment using IBM Rational Application Developer for WebSphere Software. Note that the sample code in this article ships with Maven build script, so you can use a development environment of your choice or you can even use a text editor such as Microsoft Notepad for developing code.

The sample code has quite a few dependencies such as Spring Web MVC, Spring Core, Apache Commons Logging, Apache Log4j, Apache Commons File Upload, and Apache Tiles. Downloading those JAR files individually and adding them to your class path could be a problem, so in this article, we use Apache Maven 2.0 as a build tool, which downloads all the necessary dependencies. Follow these steps to set up your development environment:

  1. Create a dynamic Web project named HelloSpringPortletMVC in Rational Application Developer.
  2. Because Maven 2.0 recommends that you use a standard directory structure for your project, create the HelloSpringPortletMVC project on the Configure web module settings page. Enter:
    • Content Directory equal to /src/main/webapp
    • Java Source Directory as /src/main/java
  3. Download the sample code for this article from the link provided in the Download section. Expand the sample code ZIP file in the c:/temp directory.
  4. Copy the build script (pom.xml) from the SpringHelloPortletMVC sample code into the root folder of your project directory.
  5. If you don't have Maven 2.0 already installed on your machine, go to the Apache Maven Web site and download the 2.x version of the Maven binaries. Refer to the Apache Maven download page for installation instructions.
  6. Open a command line and go to the root of the HelloSpringPortletMVC project. You can build your code by running the mvn package command. This command downloads all the required dependencies for your project. If you are running the Maven build script for first time, it may take a few minutes to download all the dependencies.
  7. Run the mvn eclipse:eclipse command so that Maven updates the .classpath and .project files of your project to reflect all the dependencies. Go back to the HelloSpringPortletMVC project in Rational Application Developer, right-click, and choose Refresh. You see that several JAR files are added in your project's class path.
  8. If you receive missing M2_REPO variable errors, choose Windows - Preferences - Java - Build Path, and then add an M2_REPO class path variable pointing to the Maven 2.0 repository on your machine. In Microsoft Windows, it is:

    c:\Documents and Settings\<loginname>\.m2\repository.

    In Linux, it is:

    ~/.m2/repository

After you follow these instructions, your HelloSpringPortletMVC project should look like the one shown in figure 1 in the development environment.

Figure 1. Rational Application Developer setup
Rational Application Developer setup

With your development environment ready, you can move to the next task: developing the HelloWorld Spring Portlet MVC application.


Developing the HelloWorld Spring Portlet MVC Framework application

The best way to learn any new framework is to develop a HelloWorld application using it. In this section, we develop a HelloWorld portlet using Spring Portlet MVC Framework. To keep things simple, our HelloWorld portlet supports only View mode. Whenever a user tries to access the HelloWorld portlet, we display markup generated by View.jsp to the user.

Developing portlet.xml

Let's start the HelloWorld sample development by creating the portlet.xml file in the /src/main/webapp/WEB-INF/ folder as shown in listing 1.

Listing 1. Code listing for portlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<portlet-app
	xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
	version="1.0" 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>HelloWorld Portlet using Spring MVC</description>
	<portlet-name>HelloSpringPortletMVC</portlet-name>
<display-name>Hello World Spring Portlet MVC Framework Portlet</display-name>
	<portlet-class>		org.springframework.web.portlet.DispatcherPortlet
</portlet-class>
	<supports>
		<mime-type>text/html</mime-type>
		<portlet-mode>VIEW</portlet-mode>
	</supports>

	<supported-locale>en</supported-locale>
	<portlet-info>
<title>
Hello World Spring Portlet MVC Framework Portlet
</title>
		<short-title>
HelloWorldSpringPortletMVC 
 		</short-title>
		<keywords>
spring portlet
</keywords>
	</portlet-info>	
</portlet>
</portlet-app>

DispatcherPortlet is responsible for handling every client request. When it receives a request, it finds out which Controller class should be used for handling this request, and then it calls its handleActionRequest() or handleRenderRequest() method based on the request processing phase. The Controller class executes business logic and returns a View name that should be used for rendering markup to the user. The DispatcherPortlet then forwards control to that View for actual markup generation.

As you can see, DispatcherPortlet is the central dispatcher for use within Spring Portlet MVC Framework. Note that your portlet application can define more than one DispatcherPortlet. If it does so, then each of these portlets operates its own namespace, loading its application context and handler mapping.

The DispatcherPortlet is also responsible for loading application context (Spring configuration file) for this portlet. First, it tries to check the value of the configLocation portlet initialization parameter. If that parameter is not specified, it takes the portlet name (that is, the value of the <portlet-name> element), appends-portlet.xml to it, and tries to load that file from the /WEB-INF folder. In the portlet.xml file, we did not specify the configLocation initialization parameter, so let's create HelloWorldPortletMVC-portlet.xml file in the next section.

Developing HelloSpringPortletMVC-portlet.xml

Create the HelloSpringPortletMVC-portlet.xml file in the /src/main/webapp/WEB-INF folder of your application as shown in listing 2.

Listing 2. Code listing for HelloSpringPortletMVC-portlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
\"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="viewController" 
class="com.ibm.developerworks.springmvc.ViewController"></bean>
	<bean id="portletModeHandlerMapping" class=
"org.springframework.web.portlet.handler.PortletModeHandlerMapping">
            <property name="portletModeMap">
                <map>
                    <entry key="view">
                      	<ref bean="viewController"/>
                    </entry>
                </map>
            </property>
     </bean>
</beans>

The HelloSpringPortletMVC-portlet.xml file is an application context file for your HelloSpringPortletMVC portlet. It has a couple of bean definitions:

  • viewController. At this point, remember that the viewController bean definition points to the com.ibm.developerworks.springmvc.ViewController.java class.
  • portletModeHandlerMapping. As we discussed in the last section, whenever DispatcherPortlet gets a client request, it tries to find a suitable Controller class for handling that request. That is where PortletModeHandlerMapping comes into the picture. The PortletModeHandlerMapping class is a simple implementation of the HandlerMapping interface and is used by DispatcherPortlet to find a suitable Controller for every request. The PortletModeHandlerMapping class uses Portlet mode for the current request to find a suitable Controller class to use for handling the request. The portletModeMap property of portletModeHandlerMapping bean is the place where we map the Portlet mode name against the Controller class. In the sample code, we show that viewController is responsible for handling View mode requests.

Developing ViewController.java

In the preceding section, you learned that the viewController bean is responsible for handling all the View mode requests. Your next step is to create the ViewController.java class as shown in listing 3.

Create com.ibm.developerworks.springmvc.ViewController.java by following these steps:

  1. Right-click /src/main/java, and choose New - Java Class.
  2. For Package, enter com.ibm.developerworks.springmvc.
  3. For Name, enter ViewController.
  4. Click Finished.
  5. Replace the class contents with the code shown in listing 3.
Listing 3. Code list for ViewController.java
package com.ibm.developerworks.springmvc;

import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.springframework.web.portlet.ModelAndView;
import org.springframework.web.portlet.mvc.AbstractController;

public class ViewController extends AbstractController{
	protected ModelAndView handleRenderRequestInternal(RenderRequest request, 
	RenderResponse response) throws Exception {
		ModelAndView modelAndView = new ModelAndView("View");
		return modelAndView;
	}
}

NOTE: If you are familiar with Apache Struts Framework, then you can consider the Controller class similar to the Action class in Apache Struts Framework.

Every controller class in Spring Portlet MVC Framework must implement the org.springframework.web. portlet.mvc.Controller interface directly or indirectly. To make things easier, Spring Framework provides AbstractController class, which is the default implementation of the Controller interface. As a developer, you should always extend your controller from either AbstractController or one of its more specific subclasses. Any implementation of the Controller class should be reusable, thread-safe, and capable of handling multiple requests throughout the lifecycle of the portlet.

In the sample code, we create the ViewController class by extending it from AbstractController. Because we don't want to do any action processing in the HelloSpringPortletMVC portlet, we override only the handleRenderRequest() method of AbstractController. Now, the only thing that HelloWorldPortletMVC should do is render the markup of View.jsp to the user when it receives a user request to do so. To do that, return the object of ModelAndView with a value of view equal to View.

Developing web.xml

According to Portlet Specification 1.0, every portlet application is also a Servlet Specification 2.3-compliant Web application, and it needs a Web application deployment descriptor (that is, web.xml). Let’s create the web.xml file in the /WEB-INF/ folder as shown in listing 4. Follow these steps:

  1. Open the existing web.xml file located at /src/main/webapp/web.xml.
  2. Replace the contents of this file with the code in listing 4.
Listing 4. Code listing for web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation=
"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<display-name>
Hello Spring Portlet MVC Framework Application
</display-name>
	<servlet>
		<servlet-name>ViewRendererServlet</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.ViewRendererServlet
		</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ViewRendererServlet</servlet-name>
		<url-pattern>/WEB-INF/servlet/view</url-pattern>
	</servlet-mapping>
	<listener>
		<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
	</listener>
</web-app>

The web.xml file for the sample portlet declares two things:

  • ViewRendererServlet. The ViewRendererServlet is the bridge servlet for portlet support. During the render phase, DispatcherPortlet wraps PortletRequest into ServletRequest and forwards control to ViewRendererServlet for actual rendering. This process allows Spring Portlet MVC Framework to use the same View infrastructure as that of its servlet version, that is, Spring Web MVC Framework.
  • ContextLoaderListener. The ContextLoaderListener class takes care of loading Web application context at the time of the Web application startup. The Web application context is shared by all the portlets in the portlet application. In case of duplicate bean definition, the bean definition in the portlet application context takes precedence over the Web application context.

    The ContextLoader class tries to read the value of the contextConfigLocation Web context parameter to find out the location of the context file. If the contextConfigLocation parameter is not set, then it uses the default value, which is /WEB-INF/applicationContext.xml, to load the context file.

Developing applicationContext.xml

As mentioned in the last section, if the value of the contextConfigLocation context parameter is not set, then ViewRendererServlet tries to read the Web application context from the /WEB-INF/applicationContext.xml file. Let's create applicationContext.xml in the /WEB-INF/ folder as shown in listing 5.

Listing 5. Code listing for applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="viewResolver" class=
"org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.JstlView
</value>
</property>
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>

In the sample code, the applicationContext.xml file defines only one bean, the viewResolver bean. The viewResolver bean is used to find the location of the actual JSP file for a given view name. In the sample code, you want JSP files for final view rendering, so use InternalResourceViewResolver, which supports JSPs and Tiles views.

You may have noticed that we have set a couple of properties in the viewResolver bean:

  • Prefix with value equal to /WEB-INF/jsp/
  • Suffix with value equal to JSP

This tells viewResolver that whenever it gets the view name for view resolution it should add /WEB-INF/jsp as the prefix and JSP as the suffix. As a result, when we return ModelAndView with a value equal to View from ViewController.handleRenderRequestInternal(), it renders content of /WEB-INF/jsp/View.jsp to the user.

Now, the last step is to create a simple View.jsp page with the message, "Hello from Spring Portlet MVC Framework" in the /WEB-INF/jsp folder. Follow these steps:

  1. Right-click the WEB-INF folder, and choose New - Folder.
  2. Name the folder jsp.
  3. Right-click the new jsp folder, and choose New - File.
  4. Name the file View.jsp.
  5. In the editor for the JSP file, enter "Hello from Spring Portlet MVC Framework."

Now your sample application is ready. You can build your portlet by executing the mvn package command to build HelloSpringPortletMVC-1.0.war. After you have done that, deploy the HelloSpringPortletMVC-1.0 war file that you created in the target folder on WebSphere Portal. When you access HelloWorldPortletMVCPortlet, you should see the "Hello From Spring Portlet MVC Framework" message in View mode.


How rendering works

Let's take a look at what happens when the user tries to access the HelloSpringPortletMVC portlet.

Figure 2. Sequence of events that happen when DispatcherPortlet receives render request
Sequence of events that happen when DispatcherPortlet receives render request

As you know, when the user tries to access a page with HelloWorldPortletMVC portlet on it or when the user performs some action on any other portlet on that page or tries to refresh that page, a render request is sent to the HelloWorldPortletMVC portlet. In the sample code, because DispatcherPortlet is the main portlet class, WebSphere Portal calls its render() method and then the following sequence of events occurs:

  1. The render() method of DispatcherPortlet calls the doDispatch() method, which in turn calls the doRender() method.
  2. After the doRenderService() method gets control, first it tries to find out the locale of the request by calling the PortletRequest.getLocale() method. This locale is used while making all the locale-related decisions for choices such as which resource bundle should be loaded or which JSP should be displayed to the user based on the locale.
  3. After that, the doRenderService() method starts iterating through all the HandlerMapping classes configured for this portlet, calling their getHandler() method to identify the appropriate Controller for handling this request.
  4. In the sample code, we have configured only PortletModeHandlerMapping as a HandlerMapping class. The PortletModeHandlerMapping class reads the value of the current portlet mode, and based on that, it finds out, the Controller class that should be used to handle this request. In the sample code, ViewController is configured to handle the View mode request so that the PortletModeHandlerMapping class returns the object of ViewController.
  5. After the object of ViewController is returned, the doRenderService() method calls its handleRenderRequestInternal() method.
  6. Implementation of the handleRenderRequestInternal() method in ViewController.java is very simple. It logs a message saying that it got control, and then it creates an instance of ModelAndView with a value equal to View and returns it to DispatcherPortlet.
  7. After control returns to doRenderService(), the next task is to figure out how to render View. For that, DispatcherPortlet starts iterating through all the ViewResolvers configured in your portlet application, calling their resolveViewName() method.
  8. In the sample code we have configured only one ViewResolver, InternalResourceViewResolver. When its resolveViewName() method is called with viewName, it tries to add /WEB-INF/jsp as a prefix to the view name and to add JSP as a suffix. And it checks if /WEB-INF/jsp/View.jsp exists. If it does exist, it returns the object of JstlView wrapping View.jsp.
  9. After control is returned to the doRenderService() method, it creates the object PortletRequestDispatcher, which points to /WEB-INF/servlet/view – that is, ViewRendererServlet. Then it sets the object of JstlView in the request and dispatches the request to ViewRendererServlet.
  10. After ViewRendererServlet gets control, it reads the JstlView object from the request attribute and creates another RequestDispatcher pointing to the /WEB-INF/jsp/View.jsp URL and passes control to it for actual markup generation. The markup generated by View.jsp is returned to user.

At this point, you may question the need for ViewRendererServlet. Why can't DispatcherPortlet directly forward control to View.jsp? Adding ViewRendererServlet in between allows Spring Portlet MVC Framework to reuse the existing View infrastructure. You may appreciate this more when we discuss how easy it is to integrate Apache Tiles Framework with your Spring Portlet MVC Framework.


Adding support for Help and Edit modes

In this section, we change the HelloSpringPorteltMVC portlet to add support for Help and Edit modes. To keep things simple, we create three different JSP files. Each of these JSP files displays the name of the current portlet mode to the user, and then changes the HelloWorldPortletMVC framework to forward control to one of these JSPs based on the current mode of the portlet. Follow these steps:

Create two files, Help.jsp and Edit.jsp, in the /WEB-INF/jsp folder. The Help.jsp file looks like listing 6.

Listing 6. Code listing for HelpController.java for the Help file
<%@page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<portlet:defineObjects />
<p>Hello from Spring Portlet MVC Framework - Help Mode</p>

Similarly, create Edit.jsp. Now create HelpController.java in the com.ibm.developerworks.springmvc package as shown in listing 7.

Listing 7. Code listing for HelpController.java for the Edit file
public class HelpController extends AbstractController{
	private static Log log = LogFactory.getLog(HelpController.class);
	
	protected ModelAndView handleRenderRequestInternal(RenderRequest request, 
	RenderResponse response) throws Exception {
log.debug("Entering HelpController.handleRenderRequestInternal()");
		ModelAndView modelAndView = new ModelAndView("Help");
log.debug("Exiting HelpController.handleRenderRequestInternal() " + modelAndView);
		return modelAndView;
	}
}

As you can see, HelpController.java overrides only the handleRenderRequestInternal() method of AbstractController. The implementation of the handleRenderRequestInternal() method is similar to that of ViewController.java. That is, first it logs a message saying "Entering HelpController.handleRenderRequest Internal()," and after that it returns the object of ModelAndView with the value of view equal to Help. Similarly create the EditController class for Edit mode, changing the JSP file name to Edit.

Next, tell Spring Portlet MVC Framework that HelpController should be used for handling the Help mode request and EditController should be used for handling the Edit mode request. You can do that by changing the HelloSpringPortletMVC-portlet.xml file as shown in listing 8.

Listing 8. Code listing for HelloSpringPortletMVC-portlet.xml
<bean id="viewController" class="com.ibm.developerworks.springmvc.ViewController"/>
<bean id="editController" class="com.ibm.developerworks.springmvc.EditController"/>
<bean id="helpController" class="com.ibm.developerworks.springmvc.HelpController"/>
	
<bean id="portletModeHandlerMapping" 
class = "org.springframework.web.portlet.handler.PortletModeHandlerMapping">
     <property name="portletModeMap">
     <map>
      	     <entry key="view">
                   	<ref bean="viewController"/>
                 </entry>
                 <entry key="edit">
                      	<ref bean="editController"/>
                 </entry>
                 <entry key="help">
                      	<ref bean="helpController"/>
                 </entry> 
           </map>
    </property>
</bean>

We have to make a couple of changes in the HelloSpringPortletMVC-portlet.xml file. First, define beans of EditController and HelpController. Then modify the value of the portletModeMap property in portletModeHandlerMappingbean to map the Edit mode to the editController bean and the Help mode to helpController bean. This change tells Spring Portlet MVC Framework to pass control to the editController bean when it gets a request for Edit mode and to the helpController bean when it gets a request for Help mode.

Do not forget to change the portlet.xml file to add HELP and VIEW <portlet-mode> elements under support. WebSphere Portal does not generate Help and Edit buttons for the HelloSpringPortletMVC portlet, and you cannot change your request later.


Conclusion

In this article, we covered how you can set up the development environment by using Apache Maven 2.0 as your build tool. We discussed how you can develop a simple HelloWorld portlet using Spring Portlet MVC Framework. We also talked about how the render request is handled. By now you should have an understanding of Spring Portlet MVC Framework. You may have noticed one drawback of Spring Portlet MVC Framework: Even if you want to create a simple HelloWorld portlet, you need to create four different XML configuration files. But the ability to divide configuration into multiple files can be a big help when you are developing complex applications.

In part 2 of this series, we cover how you can handle simple form submission and generate dynamic content based on user requests.


Download

DescriptionNameSize
Code samplepart-1.zip8KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=287090
ArticleTitle=Developing a Spring Portlet MVC Framework application for use inside IBM WebSphere Portal: Introduction to Spring Portlet MVC Framework
publish-date=02202008