PortletMVC4Spring compliments the Spring Web framework and MVC design pattern by providing annotations that map portlet requests to Controller classes and methods. Here you’ll develop and deploy a portlet application that uses PortletMVC4Spring, Spring, and JSP/JSPX templates.
Figure 1: The archetype's sample portlet prints a greeting (e.g., *Hello, Joe Bloggs*) on submitting a first and last name.
Follow these steps to create and deploy your portlet application:
-
Create a PortletMVC4Spring project. See PortletMVC4Spring Project Anatomy for the project structure and commands for generating PortletMVC4Spring projects. Here’s the Maven command for generating the JSP/JSPX project. This article lists sample code from the generated project.
mvn archetype:generate \ -DarchetypeGroupId=com.liferay.portletmvc4spring.archetype \ -DarchetypeArtifactId=com.liferay.portletmvc4spring.archetype.form.jsp.portlet \ -DarchetypeVersion=5.1.0 \ -DgroupId=com.mycompany \ -DartifactId=com.mycompany.my.form.jsp.portlet
-
In your project’s Gradle build file or Maven POM, add your app’s dependencies. Here are the PortletMVC4Spring development dependencies:
Gradle:
compile group: 'com.liferay.portletmvc4spring', name: 'com.liferay.portletmvc4spring.framework', version: '5.1.0' compile group: 'com.liferay.portletmvc4spring', name: 'com.liferay.portletmvc4spring.security', version: '5.1.0' providedCompile group: 'javax.portlet', name: 'portlet-api', version: '3.0.0'
Maven:
<dependency> <groupId>com.liferay.portletmvc4spring</groupId> <artifactId>com.liferay.portletmvc4spring.framework</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>com.liferay.portletmvc4spring</groupId> <artifactId>com.liferay.portletmvc4spring.security</artifactId> <version>5.1.0</version> </dependency> <dependency> <groupId>javax.portlet</groupId> <artifactId>portlet-api</artifactId> <version>3.0.0</version> <scope>provided</scope> </dependency>
At this point you can develop your Model, View, or Controller components, in any order.
-
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 { private static final long serialVersionUID = 1234273427623725552L; @NotBlank private String firstName; @NotBlank private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
-
Create your View using a Spring Web-supported template type. If you didn’t generate your project using the archetype mentioned above, specify a View resolver for template type in your
spring-context/portlet-application-context.xml
portlet application context. (See PortletMVC4Spring Configuration Files for details).The sample
user.jspx
template 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
mainFormActionURL
with 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’smodelAttribute
attribute targets an application Model. The sample template targets the application’suser
Model. -
Style your portlet by adding CSS to a stylesheet (e.g.,
webapp/resources/css/main.css
) 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/[portlet].properties
). The sampleuser.jspx
template references some of these properties:first-name=First Name greetings=Greetings, {0} {1}! javax.portlet.display-name=com.mycompany.my.form.jsp.portlet javax.portlet.keywords=com.mycompany.my.form.jsp.portlet javax.portlet.short-title=com.mycompany.my.form.jsp.portlet javax.portlet.title=com.mycompany.my.form.jsp.portlet last-name=Last Name personal-information=Personal Information 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 MyController { ... }
The
@Controller
annotation 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
@RenderMapping
annotations to methods for handling portlet render requests. Import the annotationcom.liferay.portletmvc4spring.bind.annotation.RenderMapping
and 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 = "javax.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
@RenderMapping
annotation causes theprepareView
method above to be invoked if no other handler methods match the request.prepareView
renders theuser
template (i.e.,user.jspx
).The
@RenderMapping(params = "javax.portlet.action=success")
annotation causes theshowGreeting
method to be invoked if the render request has the parameter settingjavax.portlet.action=success
.showGreeting
renders thegreeting
template (i.e.,greeting.jspx
). -
In your Controller, apply
@ActionMapping
annotations 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, thesubmitApplicant
method 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("javax.portlet.action", "success"); sessionStatus.setComplete(); } }
The
@ModelAttribute
annotation in method parameter@ModelAttribute("user") User user
associates the View’suser
Model (comprising a first name and last name) to theUser
object passed to this method.Note, the
submitApplicant
method sets thejavax.portlet.action
render parameter tosuccess
—the previous render handler methodshowGreeting
matches this request parameter. -
Configure any 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 or Maven.
-
Deploy the WAR by copying it to your
[Liferay-Home]/deploy
folder.
Liferay DXP logs the deployment and the portlet is now available in the Liferay DXP
UI. Find your portlet by selecting the Add icon
()
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