MVC Action Command

Liferay’s MVC framework lets you split your portlet’s action methods into separate classes. This can be very helpful in portlets that have many actions. Each action URL in your portlet’s JSPs then calls the appropriate action class when necessary.

First, configure your view layer and use the <portlet:actionURL> tag to create the action URL in your JSP. For example, the Blogs app’s edit_entry.jsp file defines the following action URL for editing blog entries:

<portlet:actionURL name="/blogs/edit_entry" var="editEntryURL" />

The name attribute declares a variable to hold the portlet action URL object. Assign that variable to a UI component, such as a button or icon. When the user triggers the UI component, the *MVCActionCommand class that matches the action URL processes the action request and response. Create an action class by implementing the MVCActionCommand interface, or extending the BaseMVCActionCommand class. The latter may save you time, since it already implements MVCActionCommand.

Naming your *MVCActionCommand class after the action it performs is a good convention. For example, if your action class edits some kind of entry, you could name its class EditEntryMVCActionCommand. If your application has several MVC command classes, naming them this way helps differentiate them.

Your *MVCActionCommand class must also have an @Component annotation like the following example. Set the property javax.portlet.name to your portlet’s internal ID. Set the property mvc.command.name to the value of the name property in your JSP’s matching actionURL. To register the component in the OSGi container as an MVCActionCommand service, set the service property to MVCActionCommand.class:

@Component(
    immediate = true,
    property = {
        "javax.portlet.name=your_portlet_name_YourPortlet",
        "mvc.command.name=/your/jsp/action/url"
    },
    service = MVCActionCommand.class
)

public class YourMVCActionCommand extends BaseMVCActionCommand {
    // implement your action
}

The Blogs app’s EditEntryMVCActionCommand class is a real world example of a *MVCActionCommand class:

@Component(
    immediate = true,
    property = {
        "javax.portlet.name=" + BlogsPortletKeys.BLOGS,
        "javax.portlet.name=" + BlogsPortletKeys.BLOGS_ADMIN,
        "javax.portlet.name=" + BlogsPortletKeys.BLOGS_AGGREGATOR,
        "mvc.command.name=/blogs/edit_entry"
    },
    service = MVCActionCommand.class
)
public class EditEntryMVCActionCommand extends BaseMVCActionCommand {

    	@Override
    	protected void doProcessAction(
    			ActionRequest actionRequest, ActionResponse actionResponse)
    		throws Exception {

    		String cmd = ParamUtil.getString(actionRequest, Constants.CMD);

    		try {
    			BlogsEntry entry = null;

    			UploadException uploadException =
    				(UploadException)actionRequest.getAttribute(
    					WebKeys.UPLOAD_EXCEPTION);

    			if (uploadException != null) {
    				Throwable cause = uploadException.getCause();

    				if (uploadException.isExceededFileSizeLimit()) {
    					throw new FileSizeException(cause);
    				}

    				if (uploadException.isExceededLiferayFileItemSizeLimit()) {
    					throw new LiferayFileItemException(cause);
    				}

    				if (uploadException.isExceededUploadRequestSizeLimit()) {
    					throw new UploadRequestSizeException(cause);
    				}

    				throw new PortalException(cause);
    			}
    			else if (cmd.equals(Constants.ADD) ||
    					 cmd.equals(Constants.UPDATE)) {

    				Callable<BlogsEntry> updateEntryCallable =
    					new UpdateEntryCallable(actionRequest);

    				entry = TransactionInvokerUtil.invoke(
    					_transactionConfig, updateEntryCallable);
    			}
    			else if (cmd.equals(Constants.DELETE)) {
    				deleteEntries(actionRequest, false);
    			}
    			else if (cmd.equals(Constants.MOVE_TO_TRASH)) {
    				deleteEntries(actionRequest, true);
    			}
    			else if (cmd.equals(Constants.RESTORE)) {
    				restoreTrashEntries(actionRequest);
    			}
    			else if (cmd.equals(Constants.SUBSCRIBE)) {
    				subscribe(actionRequest);
    			}
    			else if (cmd.equals(Constants.UNSUBSCRIBE)) {
    				unsubscribe(actionRequest);
    			}

                ... do more action processing
            }

            ... handle exceptions
    }
}

The @Component’s multiple javax.portlet.name property values make this *MVCActionCommand class available to those portlets as a Service Component. The mvc.command.name property setting /blogs/edit_entry matches the actionURL’s name attribute shown earlier, and the service property set to MVCActionCommand.class makes the class an MVCActionCommand Service Component.

The EditEntryMVCActionCommand class extends BaseMVCActionCommand and overrides the doProcessAction method. Similarly, *MVCActionCommand classes that implement MVCActionCommand directly must implement the processAction method. Both methods process resource requests and responses via their javax.portlet.ActionRequest and javax.portlet.ActionResponse parameters, respectively.

EditEntryMVCActionCommand’s doProcessAction method gets the value of a command parameter named by constant Constants.CMD from the ActionRequest.

String cmd = ParamUtil.getString(actionRequest, Constants.CMD);

Then the doProcessAction method checks whether an entry-related upload occurred or handles any exceptions the upload throws. Based on the command (stored in cmd) accessed from the action request, one of the following actions is performed:

  • add or update an entry
  • delete an entry
  • move an entry to the Recycle Bin
  • restore an entry from the Recycle Bin
  • subscribe a user to a blog
  • unsubscribe a user from a blog

EditEntryMVCActionCommand’s doProcessAction method continues with some more processing and prepares to redirect the portlet to an appropriate view. This shows you can do as much as you need for processing your portlet’s actions.

Now you can create your own action URLs and *MVCActionCommand classes in your applications that use Liferay’s MVC framework. Your *MVCActionCommands can do whatever you need them to do.

Creating an MVC Portlet

MVC Render Command

MVC Resource Command

MVC Command Overrides

« Beyond the Basics for PortletsMVC Render Command »
Was this article helpful?
0 out of 0 found this helpful