Skip to main content

Digital Transformation

Leveraging Spring MVC Annotations and JSR 286 Resource Serving

If you are looking for ways to improve your portal user experience via web 2.0 capabilities, you will be happy to know how simple it can be to use the JSR 286 Resource Serving feature with Spring MVC and Annotations to provide these capabilities.  JSR 286 Resource Serving works like a servlet, but runs in the portal context (has the same access to portal session and properties that portlets do) and is used extensively for web 2.0 capabilities like:  Increasing perceived page load time by allowing the portlets to render then asynchronously loading the data within the portlet page, performing asynchronous callbacks in your application for dynamic selection lists, dynamically showing detail data based on user input or selection without a full page refresh, letting the user know that you are processing their request, etc.

There are many steps to set up the needed configuration for Spring (I will outline below), however, once configuration is complete you will only need to annotate your method in the controller and call the resource.  The annotation for a method in your controller that will be called asynchrously will be annotated with the @ResourceMapping annotation and calling the resource by using the tag <portlet:resourceURL></portlet:resourceURL> in your jsp.

This article will provide a sample portlet and outline the key configuration needed to create a simple Spring MVC portlet that leverages JSR 286 Resource Serving via annotations.  It will be important to download and walk through the code with this article as it is very difficult to cover every aspect in a short concise way.  Many times the code is more helpful than words, however, I hope that my descriptions and diagrams will help in adopting Spring MVC.

Additional details on the Spring MVC framework can be found here:  http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/portlet.html

Prerequisites

This project was built using the following technologies:

  • Java version:  1.6
  • IDE:  Eclipse with Web Tools Platform 3.1.1
  • Portal Server:  Liferay 5.2.3 on Tomcat 6.0
  • Portlet:  Spring (version 3.0.2) MVC JSR 286 using Annotations

After you install the Java JDK and set your JAVA_HOME variable, follow these instructions to make Liferay use the 1.6 version:

  1. Download liferay-portal-tomcat-6.0-5.2.3.zip and extract the contents.
  2. By default Liferay for Windows includes the Java 1.5 JRE and you must make the following changes for it to use the JDK installed above.
  3. Go to the Liferay extract directory/tomcat-6.0.18/bin and edit the file named setenv.bat.  Change the contents of setenv.bat to:
    set JAVA_OPTS=%JAVA_OPTS% -Xmx1024m -XX:MaxPermSize=256m -Dfile.encoding=UTF8 -Duser.timezone=GMT -Djava.security.auth.login.config=”%CATALINA_HOME%/conf/jaas.config” -Dorg.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false

Start Tomcat by double clicking on the startup.bat file in the Liferay extract directory/tomcat-6.0.18/bin directory.

Make sure that Eclipse is set to use the JDK installed above and compiling to 1.6:

Eclipse Preferences

Eclipse Preferences

Eclipse Java Preferences

Eclipse Java Preferences

 

In order to provide the Liferay libraries to your application you need to add the Tomcat server provided in the Liferay extract above to your Eclipse environment (this will be added into your libraries in the next step):

Eclipse New Server

Eclipse New Server

Eclipse Server Definition 1

Eclipse Server Definition

Eclipse Server Definition 2

Eclipse Server Definition

Eclipse Server Definition Browse

Eclipse Server Definition Browse

Eclipse Server Definition Final

Eclipse Server Definition Final

When you create the new Dynamic Web Project be sure to select this server as the Target Runtime so that the libraries will be available to your application:

Eclipse New Dynamic Web Project

Eclipse New Dynamic Web Project

Eclipse DWP Target Runtime

Eclipse Dynamic Web Project Target Runtime

Application Overview

Please download the provided sample before continuing from here.  The sample provided is a war file that has been renamed to a zip file due to restrictions by the blog software.  Just download and rename to a .war extension before deploying to the Liferay extract directory/deploy directory.  After deployed, the portlets can be added to a page by clicking Welcome/Add Application:

Liferay Context Menu

Liferay Context Menu

The portlets will show under Perficient Blog Samples in the Add Application menu:

Liferay Add Application

Liferay Add Application

The sample application contains two portlets:

  • Request List – Does not use the JSR 286 Resource Serving feature.  Requests data before displaying the portlet which causes a page load delay and when the Display Status is changed the user must wait for the page reload without an indication that the page is loading.
  • Request List Resource Serving – Uses the JSR Resource Serving feature.  Performs an asynchronous call to retrieve data and allows the page to load immediately.  The portlet indicates that it is loading while requesting the data.

    Sample Loading English

    Sample Loading English

Both portlets support English and Spanish via traditional resource bundles:

Sample Loading Spanish

Sample Loading Spanish

Each portlet has a separate jsp and controller, however, both portlets share the same service to retrieve a list of data (a list of Requests).  The following diagram depicts the development framework used:

Development Framework Overview

Development Framework Overview

The view controller will wire in the appropriate service in the spring configuration file.  AnyAjaxcalls to retrieve additional information will call the controller via the JSR 286 Resource Serving feature.

All services will implement the appropriate service interface to allow for polymorphism in the controller.  All service methods will take a contract object and return a result object to reduce coupling and allow for caching.  Caching can be configured and enabled later if necessary on the services to improve performance.

Project Structure

The sample provided is a well structured application that provides many common features including: multiple portlets within one web application, localization (supports English and Spanish), IoC polymorphism for injecting an appropriate service implementation, a tag library, and a couple of helpful utility classes.

Please spend some time inspecting the following project structure:

  • com.perficient.resourceservingsample.contract – will contain contract transfer objects that are Serializable
  • com.perficient.resourceservingsample.domain – will contain business object classes that are Serializable
  • com.perficient.resourceservingsample.portlet – will contain view controller classes
  • com.perficient.resourceservingsample.resources – will contain resource bundle files
  • com.perficient.resourceservingsample.result – will contain result transfer objects that are Serializable
  • com.perficient.resourceservingsample.service.api – will contain interfaces used by mock and real service implementations
  • com.perficient.resourceservingsample.service.impl.mock – will contain mock implementation classes
  • com.perficient.resourceservingsample.service.util – will contain utility classes needed for the project

Under the WEB-INF folder you will find the following files:

  • context – contains key Spring configuration files
    • portlet – contains portlet specific Spring configuration files that defines the controller for the portlet and other spring configuration.
      • requestList.xml
      • requestListResourceServing.xml
  • applicationContext.xml – main spring configuration file (will be covered more later)
  • jsp – contains view resources for the portlets
    • requestList.jsp
    • requestListResourceServing.jsp
    • lib – contains the dependent jar libraries of the application.
    • tags – contains a helpful tag for image handling
      • html
        • imagesPath.tag
        • tld – contains Liferay tags used by jsp files within the application
          • liferay-portlet.tld
          • liferay-ui.tld
          • liferay-display.xml – Liferay deployment descriptor that allows for categorization of portlets
          • liferay-portlet.xml – Liferay deployment descriptor that defines portlets and the Liferay settings for the portlets
          • portlet.xml – Portal deployment descriptor that defines the portlets.
          • web.xml – defines the application and directs it to use Spring.

Technical Details

Spring and Spring Beans

Spring is a full-stack Java/JEE application framework that is lightweight and was born out of frustration with EJB.  The core focus is on Inversion of Control (IoC), also known as Dependency Injection, using techniques to externalize the creation and management of component dependencies.

Spring Framework

Spring Framework

The key part of the Spring IoC container is the applicationContext that is responsible for managing components and their dependencies.   In Spring the term “Bean” is used to refer to any component managed by the container.

<beans xmlns=”http://www.springframework.org/schema/beans”…>
<bean id=”messageSource” class=”org.springframework.context.support.ReloadableResourceBundleMessageSource”>
<property name=”basenames”>
<list>
<value>classpath:com/perficient/resourceservingsample/resources/messages</value> <!– (localized “messages_xx.properties” files) –>
</list>
</property>
<property name=”defaultEncoding” value=”UTF-8″/>
</bean>

<bean id=”requestService” class=”com.perficient.resourceservingsample.service.impl.mock.RequestServiceImpl” />
</beans>

 

Spring MVC

The Spring MVC framework is a flexible and lightweight request-oriented framework that implements the classic MVC pattern.  Spring MVC takes care of infrastructure needs and allows you to quickly create clean code that meets your unique functionality.

Spring MVC

Spring MVC

When a request comes in Spring will determine which controller to call based on the handler mapping (which in our case is defined in the context/portlet files).  The controller will get the necessary model data and return the viewName to display.  The dispatcher will resolve the jsp to render and return the information in the response.

Configuring Spring Portlet MVC

web.xml

  • Load the parent ApplicationContext with ContextLoaderListener in web.xml
  • Shared by all Portlets within the Web Application / Portlet Application
  • Set contextConfigLocation parameter to list bean definition file(s) for ContextLoaderListener
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  • Add the ViewRendererServlet to web.xml:
<servlet>
<servlet-name>ViewRendererServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ViewRendererServlet</servlet-name>
<url-pattern>/WEB-INF/servlet/view</url-pattern>
</servlet-mapping>
  • DispatcherPortlet uses this to dispatch the actual view rendering into a Servlet context
  • Acts as a bridge between a Portlet request and a Servlet request
  • Allows Portlet application to leverage the full capabilities of Spring MVC for creating, defining, resolving, and rendering views

portlet.xml


<portlet>
<portlet-name>RequestList</portlet-name>
<display-name>Request List</display-name>
<display-name xml:lang=”en”>Request List</display-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
     <init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/context/portlet/requestList.xml</value>
     </init-param>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<supported-locale>es</supported-locale>
<resource-bundle>com.perficient.resourceservingsample.resources.requestList</resource-bundle>
</portlet>

applicationContext.xml

  • View Resolver in ApplicationContext
    • Instead of building Views ourselves, refer to them by name and have them loaded for us:
<bean id=”viewResolver” class=”org.springframework.web.servlet.view.InternalResourceViewResolver”>
<property name=”cache” value=”false” />
<property name=”viewClass” value=”org.springframework.web.servlet.view.JstlView” />
<property name=”prefix” value=”/WEB-INF/jsp/” />
<property name=”suffix” value=”.jsp” />
</bean>
  • For internationalization, define a Spring message source:
<bean id=”messageSource” class=”org.springframework.context.support.ReloadableResourceBundleMessageSource”>
     <property name=”basenames”>
          <list>
               <value> classpath:com/perficient/resourceservingsample/resources/messages</value> <!– (localized “messages_xx.properties” files) –>
          </list>
     </property>
<property name=”defaultEncoding” value=”UTF-8″/>
</bean>
  • context/portlet/requestList.xml
    • This configuration file was referred to in the portlet.xml for the specific portlet.
    • Annotations and Controller configuration definition:

<context:annotation-config/>
<!– Controllers –>
<bean id=”requestListController” class=”com.perficient.resourceservingsample.portlet.RequestListController”/><!– Handler Mappings –>
<bean class=”org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping”>
<property name=”order” value=”10″/>
</bean>

 

Configuration Summary

Now that configuration is complete you are ready to begin writing your portlet code.

 

Annotations

Annotations eliminate the need for complex HandlerMapping configuration to deal with navigation via Portlet Modes and Request Paramters and allows related logic to be combined into a single Controller class:


@Controller
@RequestMapping(“VIEW”)
public class RequestListResourceServingController {
@Autowired
private RequestService requestService;               @RequestMapping
public String getRequestListPage(Model model, RenderRequest request, RenderResponse response) {
model.addAttribute(“currentStatus”, “All”);
return “requestListResourceServing”;
}                @ResourceMapping
public void retrieveRequestListData(ResourceRequest request, ResourceResponse response, Model model) throws Exception{
RequestListContract requestListContract = new RequestListContract();
String currentStatus = request.getParameter(“currentStatus”);
if (currentStatus == null || currentStatus.trim().equals(“”)){
currentStatus = “All”;
}
requestListContract.setRequestStatus(currentStatus);
RequestListResult requestListResult = requestService.retrieveRequestList(requestListContract);
StringBuffer outputBuffer = new StringBuffer();
outputBuffer.append(“<table border=’1′ cellpadding=’5′>”);
outputBuffer.append(“<tr>”);
outputBuffer.append(“<th width=’25%’>”+ LocalizedMessageUtil.getPropertyMessage(null, “requestList.label.requestDate”, request.getLocale()) +”</th>”);
outputBuffer.append(“<th width=’25%’>”+ LocalizedMessageUtil.getPropertyMessage(null, “requestList.label.requestStatus”, request.getLocale()) +”</th>”);
outputBuffer.append(“<th width=’50%’>”+ LocalizedMessageUtil.getPropertyMessage(null, “requestList.label.requestDescription”, request.getLocale()) +”</th>”);
outputBuffer.append(“</tr>”);
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd”);
for (int j = 0; j < requestListResult.getRequestList().size(); j++) {
Request requestLine = requestListResult.getRequestList().get(j);
outputBuffer.append(“<tr>”);
outputBuffer.append(“<td>”+sdf.format(requestLine.getRequestDate())+”</td>”);
outputBuffer.append(“<td>”+requestLine.getRequestStatus()+”</td>”);
outputBuffer.append(“<td>”+requestLine.getRequestDescription()+”</td>”);
outputBuffer.append(“</tr>”);
}
outputBuffer.append(“</table>”);                               PrintWriter out = response.getWriter();
response.setContentType(“text/xml”);
out.print(outputBuffer.toString());
out.flush();
out.close();
}
}

@RequestMapping – defines the method that should be run when a view is requested for display.  This method must return the name of the jsp to display.

@ResourceMapping – defines the method that should be run when a resource on the portlet is requested.

Here is a sample call to the resource in the requestListResourceServing.jsp file:

<script type=“text/javascript”>
jQuery(document).ready(function(){
jQuery(“#listLoadedDisplay”).load(“<portlet:resourceURL></portlet:resourceURL>&currentStatus=”,function(response){
jQuery(“#listLoadingNotification”).hide();
jQuery(“#listLoadedDisplay”).show();
});
});

</script>

NOTE:  You can, and probably will, have multiple request and resource serving methods in your controller.

  • If you have multiple request methods, the default method that will be called on initial request will only have @RequestMapping annotation.  Other request methods could be annotated with @RequestMapping(params = “action=printRequests”) and would be called with something like this in your jsp:
    <portlet:renderURL>
    <portlet:param name=’action’ value=’ printRequests’ />
    </portlet:renderURL>
  • If you have multiple resource methods, the default method will only have @ResourceMapping annotation.  Other resource methods could be annotated with @ResourceMapping(“retrieveRequestList “) and would be called with something like this in your jsp:
    <portlet:resourceURL id=”retrieveRequestList”></portlet:resourceURL>

Conclusion

By using the provided sample in conjunction with the contents of this article, I hope that you are able to quickly implement the JSR 286 Resource Serving feature and provide web 2.0 features to your portal project.

Thoughts on “Leveraging Spring MVC Annotations and JSR 286 Resource Serving”

  1. I approved JB’s comment because of some decent documentation on a bunch of topics at the link……….even though it has what’s obviously a couple gratuitous portlets on the site.

  2. Hi Dan,

    The link to download the sample source code is not working. It takes me to this same page. Can you please provide the correct link? Thanks, MJ.

  3. Dan Wellborn Post author

    Hi MJ,

    This has been fixed, sorry for the inconvenience.

    Thank you,
    Dan Wellborn

  4. Hi Dan,

    Thanks for the immediate response. I downloaded the sample and renamed and put the war file in the deploy directory. Started Tomcat and logged in the portal. Can’t find ResourceServingSample portlet. I am using the latest community build suite from liferay (liferay-portal-6.1.1-ce-ga2). Tomcat 7 and Dynamic Module Version 3.0 is used. Anything needs to be changed in the source code? I would really appreciate your help. Thanks, MJ. I am seeing the following in the console:

    INFO: Initializing Spring root WebApplicationContext
    16:17:18,449 ERROR [pool-2-thread-1][PortletBagFactory:313] org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘requestListResourceServingController’: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.perficient.resourceservingsample.service.api.RequestService com.perficient.resourceservingsample.portlet.RequestListResourceServingController.requestService; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name ‘defaultExceptionHandler’ defined in PortletContext resource [/WEB-INF/context/portlet/requestListResourceServing.xml]: Could not resolve parent bean definition ‘defaultExceptionHandlerTemplate’; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘defaultExceptionHandlerTemplate’ is defined
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘requestListResourceServingController’: Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.perficient.resourceservingsample.service.api.RequestService com.perficient.resourceservingsample.portlet.RequestListResourceServingController.requestService; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name ‘defaultExceptionHandler’ defined in PortletContext resource [/WEB-INF/context/portlet/requestListResourceServing.xml]: Could not resolve parent bean definition ‘defaultExceptionHandlerTemplate’; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named ‘defaultExceptionHandlerTemplate’ is defined

  5. Hi Dan,

    It works fine now. I had to move the ContextLoaderListener before PluginContextListener in the web.xml file.

    org.springframework.web.context.ContextLoaderListener

    com.liferay.portal.kernel.servlet.PluginContextListener

    com.liferay.portal.kernel.servlet.SerializableSessionAttributeListener

    Thanks for your help.
    MJ

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Dan Wellborn

More from this Author

Follow Us