SlowerBuffer

Programming and Technology Related Stuff

AJAX in Liferay

Lately at my company we’ve been working on a number of portlets for use in a Liferay Portal installation. I’ve had little previous experience with Liferay, or with portals and portlets in general so it’s been educational working my way through our requirements.

Several of our portlets have fairly simple functional demands and thus early on we decided that Liferay’s simple MVC would be sufficient (though we are using JSF for a few of the more complicated ones).

One issue came up that required some AJAX in one of these simpler portlets, so I started looking into how it could be done.

So, let’s say you need some asynchronously loaded data in one of your portlets using this simple framework. Well, Liferay’s MVC (com.liferay.util.bridges.mvc.MVCPortlet) has a method, serveResource(ResourceRequest request, ResourceResponse response), defined in the JSR 286 specification that allows data to be passed back without causing the portlet to re-render. If your portlet class is extending the MVC, you can implement this function to provide your data in JSON form.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import com.liferay.util.bridges.mvc.MVCPortlet;
import com.liferay.util.json.JSONFactoryUtil;

import java.util.List;
import java.io.IOException;

public class MyPortletActions extends MVCPortlet {
   /**
   * Returns JSON array of my data.
   */
   public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) {
      List dataList = null;
      //Do whatever to get your list of data
      String jsonString = JSONFactoryUtil.serialize(dataList);
      try {
         resourceResponse.getPortletOutputStream().write(jsonString.getBytes());
      } catch (IOException e) {
         //logging or whatever
      }
   }
}

Pretty simple. Get your data in whatever form in a list, serialize it, pass it back.

On the JSP side things are equally straightforward. You can easily generate a url for the resource using the resourceURL tag in Liferay’s taglibs. The actual call is made in the usual ways. Here I use jQuery.

So your jsp should contain:

1
2
3
4
5
6
7
8
9
   function getMyData() {
      jQuery.get('<%=resourceUrl%>;',
         function(data) {
            var parsedJSONObject = jQuery.parseJSON(data);
            var dataList = parsedJSONObject.list;
            //And do whatever needs to be done with it
         }
      );
   }

And there you have it.

Now, what if you need a couple different AJAX calls for different data in a single portlet? Well, at this point I would definitely recommend looking at a more fully featured MVC like Spring or JSF in your portlet, but let’s say that this was a late requirement, or that you’re dealing with some legacy code, etc..

So, I don’t know if it is the best solution (please let me know if you have a better one), but you could always pass some sort of action name to serveResource() and return different data based on that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) {
   String myAction = resourceRequest.getParameter("myAction");
   if ( "action1".equals(myAction)) {
      action1(resourceRequest, resourceResponse);
   } else if ( "action2".equals(myAction) ) {
      action2(resourceRequest, resourceResponse);
   } else {
      log.warn("Unknown action has been called: " + myAction);
   }
}

//Your code from before
public void action1(ResourceRequest resourceRequest, ResourceResponse resourceResponse) {
   List dataList = null;
   //Do whatever to get your list of data
   String jsonString = JSONFactoryUtil.serialize(dataList);
   try {
      resourceResponse.getPortletOutputStream().write(jsonString.getBytes());
   } catch (IOException e) {
      //logging or whatever
   }
}

//Your other data
public void action2(ResourceRequest resourceRequest, ResourceResponse resourceResponse) {
   List dataList = null;
   //Do whatever to get your list of data
   String jsonString = JSONFactoryUtil.serialize(dataList);
   try {
      resourceResponse.getPortletOutputStream().write(jsonString.getBytes());
   } catch (IOException e) {
      //logging or whatever
   }
}

And then the calls:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   function getMyData() {
      jQuery.get('<%=resourceUrl%>', {myAction: "action1" },
         function(data) {
            var parsedJSONObject = jQuery.parseJSON(data);
            var dataList = parsedJSONObject.list;
            //And do whatever needs to be done with it
         }
      );
   }
   function getMyOtherData() {
      jQuery.get('<%=resourceUrl%>', {myAction: "action2" },
         function(data) {
            var parsedJSONObject = jQuery.parseJSON(data);
            var dataList = parsedJSONObject.list;
            //And do the other thing that needs to be done
         }
      );
   }

And that would be about it.

Comments