In MVC, your controller receives requests from the front-end, and it pulls data from the back-end. It’s a traffic director: it provides data to the right front-end view for display to the user, and it takes data the user entered in the front-end and passes it to the right back-end service. For this reason, the controller must process requests from the front-end, and it must determine the right front-end view to pass data back to the user.
If you have a small application that’s not heavy on controller logic (maybe just
a couple of action methods), you can put all your controller code in the
-Portlet
class. If you have more complex needs (lots of actions, complex
render logic to implement, or maybe even some resource serving code), consider
breaking the controller into MVC Render Command classes,
MVC Action Command classes,
and MVC Resource Command classes.
This tutorial demonstrates implementing controller logic for small applications.
In this tutorial you’ll learn to implement a Liferay MVC portlet with all the
controller code in the -Portlet
class. It involves these things:
- Action methods
- Render logic
- Setting and retrieving request parameters and attributes
Start with creating action methods.
Action Methods
If you have a small application, you can implement all your controller logic in the portlet class you created in the last step. It can act as your controller by itself. Use action methods to process requests. Here’s a sample action method:
public void addGuestbook(ActionRequest request, ActionResponse response)
throws PortalException, SystemException {
ServiceContext serviceContext = ServiceContextFactory.getInstance(
Guestbook.class.getName(), request);
String name = ParamUtil.getString(request, "name");
try {
_guestbookService.addGuestbook(serviceContext.getUserId(),
name, serviceContext);
SessionMessages.add(request, "guestbookAdded");
} catch (Exception e) {
SessionErrors.add(request, e.getClass().getName());
response.setRenderParameter("mvcPath",
"/html/guestbook/edit_guestbook.jsp");
}
}
This action has one job: call a service to add a Guestbook. If this call
succeeds, the message "guestbookAdded"
is associated with the request and
added to the
SessionMessages
object.
If an exception is thrown, it’s caught, and the class name is associated with
the request and added to the SessionErrors
object
and the response is set to render edit_guestbook.jsp
. Setting the mvcPath
render parameter is a Liferay MVCPortlet
framework convention that denotes the
next view to render to the user.
While action methods respond to user actions, render logic determines the view to display to the user. Render logic is next.
Render Logic
Here’s how MVC Portlet determines which view to render. Note the init-param
properties you set in your component:
"javax.portlet.init-param.template-path=/",
"javax.portlet.init-param.view-template=/view.jsp",
The template-path
property tells the MVC framework where your JSP files live.
In the above example, /
means that the JSP files are in your project’s root
resources
folder. That’s why it’s important to follow Liferay’s standard
folder structure. The view-template
property directs the default rendering to
view.jsp
.
Here’s the path of a hypothetical Web module’s resource folder:
docs.liferaymvc.web/src/main/resources/META-INF/resources
Based on that resource folder, the view.jsp
file is found at
docs.liferaymvc.web/src/main/resources/META-INF/resources/view.jsp
and that’s the default view of the application. When the portlet’s init
method
(e.g., your portlet’s override of MVCPortlet.init()
) is called, the
initialization parameters you specify are read and used to direct rendering to
the default JSP. Throughout the controller, you can render different views (JSP
files) by setting the render parameter mvcPath
like this:
actionResponse.setRenderParameter("mvcPath", "/error.jsp");
It’s possible to avoid render logic by using initialization parameters and
render parameters, but most of the time you’ll override the portlet’s render
method. Here’s an example:
@Override
public void render(RenderRequest renderRequest,
RenderResponse renderResponse) throws PortletException, IOException {
try {
ServiceContext serviceContext = ServiceContextFactory.getInstance(
Guestbook.class.getName(), renderRequest);
long groupId = serviceContext.getScopeGroupId();
long guestbookId = ParamUtil.getLong(renderRequest, "guestbookId");
List<Guestbook> guestbooks = _guestbookService
.getGuestbooks(groupId);
if (guestbooks.size() == 0) {
Guestbook guestbook = _guestbookService.addGuestbook(
serviceContext.getUserId(), "Main", serviceContext);
guestbookId = guestbook.getGuestbookId();
}
if (!(guestbookId > 0)) {
guestbookId = guestbooks.get(0).getGuestbookId();
}
renderRequest.setAttribute("guestbookId", guestbookId);
} catch (Exception e) {
throw new PortletException(e);
}
super.render(renderRequest, renderResponse);
}
This render logic provides the view layer with data to display to the user. The
render
method above sets the render request attribute guestbookId
with the
ID of a guestbook to display. If guestbooks exist, it chooses the first.
Otherwise, it creates a guestbook and sets it to display. Lastly the method
passes the render request and render response objects to the base class via its
render
method.
Before venturing into the view layer, the next section demonstrates ways to pass information between the controller and view layers.
Setting and Retrieving Request and Response Parameters and Attributes
You can use a handy utility class called
ParamUtil
to retrieve parameters from an ActionRequest
or a RenderRequest
.
For example, a JSP could pass a parameter named guestbookId
in an action
URL.
<portlet:actionURL name="doSomething" var="doSomethingURL">
<portlet:param name="guestbookId"
value="<%= String.valueOf(entry.getGuestbookId()) %>" />
</portlet:actionURL>
The <portlet:actionURL>
tag’s name
attribute maps the action URL to a
controller action method named doSomething
. Triggering an action URL invokes
the corresponding method in the controller.
The controller’s doSomething
method referenced in this example can then get
the guestbookId
parameter value from the ActionRequest
.
long guestbookId = ParamUtil.getLong(actionRequest, "guestbookId");
To pass information back to the view layer, the controller code can set render parameters on response objects.
actionResponse.setRenderParameter("mvcPath", "/error.jsp");
The code above sets a parameter called mvcPath
to JSP path /error.jsp
.
This causes the controller’s render method to redirect the user to the JSP
/error.jsp
.
Your controller class can also set attributes into response objects using the
setAttribute
method.
renderRequest.setAttribute("guestbookId", guestbookId);
JSPs can use Java code in scriptlets to interact with the request object.
<%
long guestbookId = Long.valueOf((Long) renderRequest
.getAttribute("guestbookId"));
%>
Passing information back and forth from your view and controller is important, but there’s more to the view layer than that. The view layer is up next.