In MVC, your controller is 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, 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.
Here you’ll implement controller logic for small applications, where all the
controller code is 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
Your portlet class can act as your controller by itself and process requests using action methods. 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 method has one job: call a service to add a guestbook. If the 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 application’s default view. When the portlet’s init
method
(e.g., your portlet’s override of MVCPortlet.init()
) is called, Liferay reads the
initialization parameters you specify and directs 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");
You can 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
A handy utility class called
ParamUtil
facilitates retrieving parameters from an ActionRequest
or a
RenderRequest
.
For example, this JSP passes 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 gets 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 that JSP.
Your controller class can also set attributes into response objects using the
setAttribute
method.
renderResponse.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.