Do you want to override Liferay’s Struts actions or add a new Struts action to Liferay? You can do both using Struts action hooks.
First, consider the interfaces used for Struts actions:
The StrutsAction
interface is used with portal Struts actions, like
/c/portal/update_email_address
. The StrutsPortletAction
interface is used
with portlet Struts actions.
Struts actions are classes, and they’re specified in a struts-config.xml
file.
Liferay Portal’s
struts-config.xml
file resides in its WEB-INF
folder. It links actions to JSPs or tiles. Each
action performs a task and then returns a forward, an object containing a name
and path. The forward defines the page the portal sends the user to after the
action completes. When a user submits a form that maps to a Struts action, the
portal loads and executes the action class’ method, which returns a forward.
You can use a Struts action hook plugin to override/wrap existing Struts actions or to create a new Struts action and path; you’ll do both in this tutorial. You’ll override a Struts action to use your own class. Then you’ll create a new Struts action path and navigate to it. It’s time to begin!
Overriding Struts Actions
For the first part of this tutorial, you’ll override a portlet’s existing Struts action using a hook plugin project.
You can view the current actions in your portal’s struts-config.xml
file. For example, here’s the default login Struts action:
<action path="/login/login"
type="com.liferay.portlet.login.action.LoginAction">
<forward
name="portlet.login.login"
path="portlet.login.login"
/>
<forward
name="portlet.login.login_redirect"
path="portlet.login.login_redirect"
/>
</action>
You can override a portlet’s Struts action like the one above by following these steps:
-
Open the
liferay-hook.xml
file from your hook plugin’sdocroot/WEB-INF
folder. -
Add a
struts-action
element within thehook
element. -
Add to the
struts-action
element, astruts-action-path
element with a value that specifies the action path you’re overriding and add astruts-action-impl
element with a value that specifies your custom action class.The following Struts action from example hook plugin example-hook specifies a custom Struts portlet action class called
ExampleStrutsPortletAction
. This action class is invoked for the Struts action path/login/login
. The example hook’sstruts-action
element looks like this:<struts-action> <struts-action-path>/login/login</struts-action-path> <struts-action-impl> com.liferay.sample.hook.action.ExampleStrutsPortletAction </struts-action-impl> </struts-action>
The DTD for
liferay-hook.xml
is here. -
In your hook plugin’s
docroot/WEB-INF/src
folder, create a Struts portlet action class and its package folders.Here’s an example Struts portlet action class:
package com.liferay.sample.hook.action; import com.liferay.portal.kernel.struts.BaseStrutsPortletAction; import com.liferay.portal.kernel.struts.StrutsPortletAction; import com.liferay.portal.theme.ThemeDisplay; import com.liferay.portal.kernel.util.WebKeys; import javax.portlet.ActionRequest; import javax.portlet.ActionResponse; import javax.portlet.PortletConfig; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; public class ExampleStrutsPortletAction extends BaseStrutsPortletAction { public void processAction( StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig, ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY); Long currentuser = themeDisplay.getUserId(); if (currentuser != null) { System.out.println("Custom Struts Action 2"); } originalStrutsPortletAction.processAction( originalStrutsPortletAction, portletConfig, actionRequest, actionResponse); } public String render( StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig, RenderRequest renderRequest, RenderResponse renderResponse) throws Exception { System.out.println("Custom Struts Action"); return originalStrutsPortletAction.render( null, portletConfig, renderRequest, renderResponse); } public void serveResource( StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig, ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws Exception { originalStrutsPortletAction.serveResource( originalStrutsPortletAction, portletConfig, resourceRequest, resourceResponse); } }
Notice that the class extends the base class BaseStrutsPortletAction
.
The render
method of class above prints to the console the message Custom
Struts Action every time a user logs in.
As a best practice in extending Struts actions, consider invoking the base class methods that you override.
That’s it for overriding Struts actions! The next section of this tutorial demonstrates how to add a new Struts action.
Adding Struts Actions
Now that you know how to override a Struts action, you might also be interested in adding a new Struts action. Here’s how you do it:
-
If you like, create a folder for the new action’s JSP. The example hook plugin example-hook2-hook on GitHub, stores its custom JSP in a folder
docroot/META-INF/custom_jsps/html/portal
. -
Add a JSP for your new Struts action. For example, the following code from the example-hook2-hook plugin’s JSP greets the user:
<% String name = (String)request.getAttribute("name"); %> Hello <%= name %>!
-
Create a new Struts action class. Consider extending
BaseStrutsAction
. As an example, here’s the code from the example-hook2-hook plugin’s Struts action classExampleStrutsAction
:package com.liferay.sample.hook.action; import com.liferay.portal.kernel.struts.BaseStrutsAction; import com.liferay.portal.kernel.util.ParamUtil; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ExampleStrutsAction extends BaseStrutsAction { public String execute( HttpServletRequest request, HttpServletResponse response) throws Exception { String name = ParamUtil.get(request, "name", "World"); request.setAttribute("name", name); return "/portal/sample.jsp"; } }
Notice that the
ExampleStrutsAction
class’sexecute
method sets the request attributename
to the current user’s name, or to World if the user’s name isn’t accessible.This class overrides
BaseStrutsAction
’sexecute(HttpServletRequest, HttpServletResponse)
method, but not itsexecute(StrutsAction, HttpServletRequest, HttpServletResponse)
method. You’d typically override both methods. It’s fine to ignore overriding that method in this example hook. -
Open the
liferay-hook.xml
file from the hook plugin’sdocroot/WEB-INF
folder. -
If you’re using a custom JSP folder, add within the
hook
element acustom-jsp-dir
element that specifies the JSP folder path as its value. Within thehook
element, just after thecustom-jsp-dir
element (if you added one), add astruts-action
element. Within thestruts-action
element, add astruts-action-path
element with a value that specifies the action path you’re overriding and add astruts-action-impl
element with a value that specifies your custom action class.The following example Struts action from the example-hook2-hook plugin specifies Struts action path
/custom/path
for invoking the custom Struts portlet action classExampleStrutsPortletAction
.<custom-jsp-dir>/META-INF/custom_jsps</custom-jsp-dir> <struts-action> <struts-action-path>/custom/path</struts-action-path> <struts-action-impl> com.liferay.sample.hook.action.ExampleStrutsAction </struts-action-impl> </struts-action>
-
If you’d like your Struts action path to be public, add it to your portal’s list of paths that don’t require authentication. Do this by copying your existing
auth.public.paths
property assignment from your portal’sportal.properties
into yourportal-ext.properties
file. Then add your Struts action path to the end of the value list. It looks similar to the assignment below, where you’d replace/custom/path
with your custom Struts action path:auth.public.paths=\ /asset/get_categories,\ ... /wiki/rss,\ /custom/path
-
Restart the portal server and try your new Struts path.
-
Open your custom Struts action’s JSP in your browser. The JSP for example hook plugin example-hook2-hook can be accessed from a browser at the path you specified:
http://localhost:8080/c/portal/sample
.
Figure 1: The example-hook2-hook example hook plugin's new Struts action JSP displays *Hello World!*.
Great! Now you know about the interfaces used for Struts actions. You also learned how to override an existing action and create a new action using a hook. You’re ready to strut your stuff!