Developing a PortletMVC4Spring Portlet
PortletMVC4Spring compliments the Spring Web framework and MVC design pattern by providing annotations that map portlet requests to Controller classes and methods. This sample portlet application uses PortletMVC4Spring, Spring, and JSP/JSPX templates to show you how it works.

Follow these steps to create and deploy your portlet application:
-
Create a PortletMVC4Spring project in your Liferay Workspace:
blade create B7F9Portlet -t spring-mvc-portlet --framework portletmvc4spring --view-type jsp -
Create your Model class(es) in a package for models (e.g.,
java/[my-package-path]/dto). The sample Model class isUser:public class User implements Serializable { public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public void setFirstName(String firstName) { this.firstName = firstName; } public void setLastName(String lastName) { this.lastName = lastName; } private static final long serialVersionUID = 1113488483222411111L; @NotBlank private String firstName; @NotBlank private String lastName; } -
Create your View using a Spring Web-supported template type. If you didn’t generate your project with Blade, specify a View resolver for template type in your
spring-context/portlet-application-context.xmlportlet application context. (See PortletMVC4Spring Configuration Files for details).The sample
user.jspxtemplate renders a form for submitting a user’s first and last name.<?xml version="1.0" encoding="UTF-8"?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:portlet="http://xmlns.jcp.org/portlet_3_0" xmlns:spring="http://www.springframework.org/tags" xmlns:form="http://www.springframework.org/tags/form" version="2.1"> <jsp:directive.page contentType="text/html" pageEncoding="UTF-8" /> <portlet:defineObjects/> <link href="${contextPath}/resources/css/main.css" rel="stylesheet" type="text/css"/> <portlet:actionURL var="mainFormActionURL"/> <form:form id="${namespace}mainForm" action="${mainFormActionURL}" class="user-form" method="post" modelAttribute="user"> <p class="caption"> <spring:message code="personal-information" /> </p> <fieldset> <div class="form-group"> <form:label for="${namespace}firstName" path="firstName"> <spring:message code="first-name" /> </form:label> <form:input id="${namespace}firstName" cssClass="form-control" path="firstName"/> <form:errors path="firstName" cssClass="portlet-msg-error"/> </div> <div class="form-group"> <form:label for="${namespace}lastName" path="lastName"> <spring:message code="last-name" /> </form:label> <form:input id="${namespace}lastName" cssClass="form-control" path="lastName"/> <form:errors path="lastName" cssClass="portlet-msg-error"/> </div> </fieldset> <hr /> <spring:message code="submit" var="submit" /> <input class="btn btn-primary" value="${submit}" type="submit"/> </form:form> </jsp:root>To invoke actions in your Controller, associate action URLs with your templates. The sample template associates the action URL variable
mainFormActionURLwith its form element.<portlet:actionURL var="mainFormActionURL"/> <form:form id="${namespace}mainForm" action="${mainFormActionURL}" class="user-form" method="post" modelAttribute="user"> ...A
<form:form/>element’smodelAttributeattribute targets an application Model. The sample template targets the application’suserModel. -
Style your portlet by adding CSS to a stylesheet (e.g.,
webapp/css/main.scss) and linking your template to it.<link href="${contextPath}/resources/css/main.css" rel="stylesheet" type="text/css"/> -
Define your portlet’s messages in a properties file (e.g.,
src/main/resources/content/Language.properties). The sampleuser.jspxtemplate references some of these properties:first-name=First Name greetings=Greetings, {0} {1}! jakarta.portlet.display-name=B7F9Portlet jakarta.portlet.keywords=B7F9Portlet jakarta.portlet.short-title=B7F9Portlet jakarta.portlet.title=B7F9Portlet last-name=Last Name personal-information=Personal Information please-correct-the-following-errors=Please correct the following error(s) submit=Submit todays-date-is=Today''s date is {0} -
Create a Controller class to handle portlet requests. Here’s an example:
@Controller @RequestMapping("VIEW") public class UserController { ... }The
@Controllerannotation applies the Spring Controller component stereotype. The Spring Framework scans Controller classes for Controller annotations.The
@RequestMapping("VIEW")annotation marks the class’s public methods as request handler methods for the portlet’s VIEW mode. -
In your Controller, apply
@RenderMappingannotations to methods for handling portlet render requests. Import the annotationcom.liferay.portletmvc4spring.bind.annotation.RenderMappingand make sure each handler method returns a string that matches the name of a template to render. Here are the sample’s render request handler methods:@RenderMapping public String prepareView() { return "user"; } @RenderMapping(params = "jakarta.portlet.action=success") public String showGreeting(ModelMap modelMap) { DateFormat dateFormat = new SimpleDateFormat("EEEE, MMMM d, yyyy G"); Calendar todayCalendar = Calendar.getInstance(); modelMap.put("todaysDate", dateFormat.format(todayCalendar.getTime())); return "greeting"; }The
@RenderMappingannotation invokes theprepareViewmethod above if no other handler methods match the request.prepareViewrenders theusertemplate (i.e.,user.jspx).The
@RenderMapping(params = "jakarta.portlet.action=success")annotation invokes theshowGreetingmethod if the render request has the parameter settingjakarta.portlet.action=success.showGreetingrenders thegreetingtemplate (i.e.,greeting.jspx). -
In your Controller, apply
@ActionMappingannotations to your portlet action request handling methods. Import the annotationcom.liferay.portletmvc4spring.bind.annotation.ActionMapping.The sample Controller’s action handler method below is annotated with
@ActionMapping, making it the default action handler if no other action handlers match the request. Since this portlet only has one action handler, thesubmitApplicantmethod handles all of the portlet’s action requests.@ActionMapping public void submitApplicant( @ModelAttribute("user") User user, BindingResult bindingResult, ModelMap modelMap, Locale locale, ActionResponse actionResponse, SessionStatus sessionStatus) { _localValidatorFactoryBean.validate(user, bindingResult); if (!bindingResult.hasErrors()) { if (_logger.isDebugEnabled()) { _logger.debug("firstName=" + user.getFirstName()); _logger.debug("lastName=" + user.getLastName()); } MutableRenderParameters mutableRenderParameters = actionResponse.getRenderParameters(); mutableRenderParameters.setValue("jakarta.portlet.action", "success"); sessionStatus.setComplete(); } else { bindingResult.addError( new ObjectError( "user", _messageSource.getMessage( "please-correct-the-following-errors", null, locale))); } }The
@ModelAttributeannotation in method parameter@ModelAttribute("user") User userassociates the View’suserModel (comprising a first name and last name) to theUserobject passed to this method.Note, the
submitApplicantmethod sets thejakarta.portlet.actionrender parameter tosuccess. The previous render handler methodshowGreetingmatches this request parameter. -
Configure additional resources and beans in the project’s descriptors and Spring context files respectively. (See PortletMVC4Spring Configuration Files for details).
-
Build the project WAR using Gradle.
-
Deploy the WAR by copying it to your
[Liferay-Home]/deployfolder.
Liferay logs the deployment and the portlet appears in the Liferay UI. Find your portlet by selecting Add (
) and navigating to Widgets and the category you specified to the Liferay Bundle Generator (Sample is the default category).
Congratulations! You created and deployed a PortletMVC4Spring Portlet.
Related Topics
PortletMVC4Spring Project Anatomy