Translations of this page:

MVC Portlet Development

This section will show you how to develop a MVC (Model View Controller) based portlet that will let you search and edit User details.

Install Eclipse and the Liferay Plugin Development Environment. You will notice some new icons in Eclipse.

Click on “Create New Liferay Portal”. Give it a name such as <my-project>-portal. This will create the following directory structure in your liferay-plugins-sdk directory:

build.xml
docroot/
  css/
  js/
  META-INF/
  WEB-INF/
    classes/
    lib/
    src/
    tld/
    liferay-display.xml
    liferay-plugin-package.properties
    liferay-portlet.xml
    portlet.xml
    web.xml
  icon.png
  view.jsp

This should be reasonably familiar to anyone with experience of developing Java Web Applications. We'll deal with the liferay configuration files in turn.

liferay-display.xml

Used to specify the display name and category under which the Portlet is listed. We will probably want to change the category.

liferay-plugin-package.properties

Some general information about the portlet such as the author and license.

liferay-portlet.xml

Configure various liferay specific portlet global attributes. If you want to configure additional portlets in the same web application duplicate the <portlet> section.

portlet.xml

Generic portlet configuration. Here we will configure the Portlet MVC class (EmployeeDetailsPortlet) and the default view (html/view.jsp) to be displayed as well as the property file to be used for message variables (see i18n

...
  <portlet>
...
    <portlet-class>com.abcseo.portlet.EmployeeDetailsPortlet</portlet-class>
    <init-param>
      <name>view-jsp</name>
      <value>/html/view.jsp</value>
    </init-param>
...
    <resource-bundle>content.Language</resource-bundle>
...
  </portlet>

Again if we want to configure multiple portlets in the same war then duplicate the portlet section. This lets us share resources, such as JSPs, between portlets.

web.xml

Standard Web Application xml file, nothing to touch here for the moment.

docroot/init.jsp

Add the file init.jsp in the docroot directory. This will hold our global initialization for each jsp.

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
 
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
<%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %>
<%@ taglib uri="http://liferay.com/tld/security" prefix="liferay-security" %>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%@ taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
 
<!--  for search -->
<%@ page import="java.util.List" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.util.LinkedHashMap" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="com.liferay.portal.service.UserLocalServiceUtil" %>
<%@ page import="com.liferay.portal.service.PhoneServiceUtil" %>
<%@ page import="com.liferay.portal.kernel.search.Hits" %>
<%@ page import="com.liferay.portlet.expando.model.ExpandoBridge" %>
<%@ page import="com.liferay.portal.model.User" %>
<%@ page import="com.liferay.portal.model.Contact" %>
<%@ page import="com.liferay.portal.model.Phone" %>
<%@ page import="com.liferay.portal.model.ListType" %>
 
<portlet:defineObjects />
<liferay-theme:defineObjects />

docroot/html/view.jsp

This is our default view and will present the search results. First thing to notice is that as Portlets are run inside the Liferay Portal they are not directly accessible via a URL. We edit results in the html/edit.jsp page. View.jsp will forward directly to this page without passing through the EmployeeDetailsPortlet class configured above. This is pretty typical for liferay but it does mean there is more code at the JSP level. The portlet:renderURL tag generates an internal liferay URL from the real path /html/edit.jsp, it assignes this to the editURL variable.

Note the include to init.jsp with our global imports etc.

<jsp:useBean id="keyWords" class="java.lang.String" scope="request" />
 
<%@include file="/init.jsp"%>
 
<portlet:renderURL var="editURL">
	<portlet:param name="jspPage" value="/html/edit.jsp" />
</portlet:renderURL>

We next have a very simple form that uses the AlloyUI Forms Taglibs. Again we

<portlet:actionURL name="search" var="searchURL" />
<aui:form action="<%= searchURL.toString() %>" method="post">
  <div class="portlet-toolbar search-form">
    <span class="aui-search-bar">
      <aui:input inlineField="<%= true %>" label="" name="keywords" size="30" value="<%=keyWords%>" title="search-entries" type="text" />
    </span>
  </div>
</aui:form>
 
<%
	if (!"".equals(keyWords)) {
%>
<liferay-ui:search-container delta="10"
	emptyResultsMessage="no-users-were-found">
	<liferay-ui:search-container-results>
		<%
			results = UserLocalServiceUtil.search(
								company.getCompanyId(), keyWords, true,
								userParams, searchContainer.getStart(),
								searchContainer.getEnd(),
								searchContainer.getOrderByComparator());
						total = UserLocalServiceUtil.searchCount(
								company.getCompanyId(), keyWords, true,
								userParams);
 
						pageContext.setAttribute("results", results);
						pageContext.setAttribute("total", total);
		%>
	</liferay-ui:search-container-results>
 
	<liferay-ui:search-container-row
		className="com.liferay.portal.model.User" keyProperty="userId"
		modelVar="user">
		<%
			System.out.println("userid " + user.getUserId());
						String mobileNo = "";
						String phoneNo = "";
						ExpandoBridge eb = user.getExpandoBridge();
						List<Phone> phones = PhoneServiceUtil.getPhones(
								Contact.class.getName(), user.getContactId());
						System.out.println("phones " + phones + " contact id "
								+ user.getContactId());
 
						for (Phone phone : phones) {
							String phoneType = phone.getType().getName();
 
							if ("Business".equals(phoneType)) {
								phoneNo = phone.getNumber();
							} else if ("Mobile".equals(phoneType)) {
								mobileNo = phone.getNumber();
							}
 
						}
 
		%>
		<portlet:actionURL name="readUser" var="employeeDetailsURL">
			<portlet:param name="userId" value='<%= ""+user.getUserId() %>' />
		</portlet:actionURL>
 
		<liferay-ui:search-container-column-text name="first-name"
			property="firstName" href="<%= employeeDetailsURL %>" />
 
		<liferay-ui:search-container-column-text name="Surname"
			property="lastName" href="<%= employeeDetailsURL %>" />
 
		<liferay-ui:search-container-column-text name="Department"
			value='<%= eb.getAttribute("Department").toString() %>' />
 
		<liferay-ui:search-container-column-text name="Team"
			value='<%= eb.getAttribute("Team").toString() %>' />
 
		<liferay-ui:search-container-column-text name="Nick Name - from LDAP"
			value='<%= eb.getAttribute("nickName").toString() %>' />
 
		<liferay-ui:search-container-column-text name="title"
			property="jobTitle" />
 
		<liferay-ui:search-container-column-text name="E-Mail"
			property="emailAddress"  href='<%= "mailto:" + user.getEmailAddress() %>'/>
 
		<liferay-ui:search-container-column-text name="Phone"
			value='<%= phoneNo %>' />
 
		<liferay-ui:search-container-column-text name="Mobile"
			value='<%= mobileNo %>' />
	</liferay-ui:search-container-row>
 
 
	<!--  this is what iterates through and displays the list -->
	<liferay-ui:search-iterator />
</liferay-ui:search-container>
<%
	}
%>
...
 
 
public class EmployeeDetailsPortlet extends MVCPortlet {
	String editJSP = "/html/edit.jsp";
 
	public void addProduct(ActionRequest request, ActionResponse response)
			throws Exception {
		ThemeDisplay themeDisplay = (ThemeDisplay) request
				.getAttribute(WebKeys.THEME_DISPLAY);
 
		long companyId = 0;
		if (request.getRemoteUser() != null) {
			// this seems to call Solr:core0
			User user = UserServiceUtil.getUserById(Long.parseLong(request
					.getRemoteUser()));
 
			companyId = user.getCompanyId();
 
		}
 
		System.out.println("company id " + companyId);
 
		String keywords = request.getParameter("keywords");
		themeDisplay.getUserId();
		SessionMessages.add(request, "product-saved-successfully");
 
		request.setAttribute("keyWords", keywords);
		request.setAttribute("cid", companyId);
	}
 
	public void readUser(ActionRequest request, ActionResponse response)
			throws Exception {
		String userId = (String) request.getParameter("userId");
 
		long id = Long.parseLong(userId);
		System.out.println(">>>userId = " + id);
 
		User user = UserServiceUtil.getUserById(id);
 
		request.setAttribute("addax.user", user);
		request.setAttribute("addax.contact", user.getContact());
 
		response.setRenderParameter("jspPage", editJSP);
	}
 
	public void updateUser(ActionRequest request, ActionResponse response) {
		System.out.println("UPATE" + request.getParameter("emailAddress"));
		System.out.println(request.getParameter("userId"));
 
	}
}

html/view.jsp

<jsp:useBean id="keyWords" class="java.lang.String" scope="request" />
 
<%@include file="/init.jsp"%>
 
<portlet:renderURL var="editURL">
	<portlet:param name="jspPage" value="/html/edit.jsp" />
</portlet:renderURL>
 
<portlet:actionURL name="addProduct" var="addProductURL" />
<aui:form action="<%= addProductURL.toString() %>" method="post">
	<div class="portlet-toolbar search-form">
		<span class="aui-search-bar"> <aui:input
				inlineField="<%= true %>" label="" name="keywords" size="30"
				value="<%=keyWords%>" title="search-entries" type="text" /> <aui:select
				name="searchType" label="">
				<aui:option value="employee">
		Employee</aui:option>
			</aui:select> <aui:button type="submit" value="search" /> <br />Name, surname,
			department... </span>
 
	</div>
</aui:form>
 
<%
	LinkedHashMap userParams = new LinkedHashMap();
	//long[] organizationIds = user.getOrganizationIds();
	//if (organizationIds.length > 0) {
		//userParams.put("usersOrgs", new Long(organizationIds[0]));
		//userParams.put("Team", "SWAT");
		System.out.println("org id " + organizationIds[0]);
	//}
 
	//userParams.put("Team", "SWAT");
 
	//String cid = (String) actionRequest.getAttribute("cid");
%>
 
<liferay-ui:search-container delta="10"
	emptyResultsMessage="no-users-were-found">
	<liferay-ui:search-container-results>
		<%
			results = UserLocalServiceUtil.search(
							company.getCompanyId(), keyWords, true, userParams,
							searchContainer.getStart(),
							searchContainer.getEnd(),
							searchContainer.getOrderByComparator());
					total = UserLocalServiceUtil.searchCount(
							company.getCompanyId(), keyWords, true, userParams);
 
					pageContext.setAttribute("results", results);
					pageContext.setAttribute("total", total);
		%>
	</liferay-ui:search-container-results>
	<liferay-ui:search-container-row
		className="com.liferay.portal.model.User" keyProperty="userId"
		modelVar="user">
		<%
			ExpandoBridge eb = user.getExpandoBridge();
					List<Phone> phones = PhoneServiceUtil.getPhones(
							Contact.class.getName(), user.getContactId());
					System.out.println("phones " + phones + " contact id "
							+ user.getContactId());
					String mobileNo = "";
					String phoneNo = "";
					for (Phone phone : phones) {
						String phoneType = phone.getType().getName();
 
						if ("Business".equals(phoneType)) {
							phoneNo = phone.getNumber();
						} else if ("Mobile".equals(phoneType)) {
							mobileNo = phone.getNumber();
						}
 
					}
					String userId = "" + user.getUserId();
		%>
		<portlet:actionURL name="readUser" var="employeeDetailsURL">
			<portlet:param name="userId" value="<%= userId %>" />
		</portlet:actionURL>
 
		<liferay-ui:search-container-column-text name="first-name"
			property="firstName" href="<%= employeeDetailsURL %>" />
 
		<liferay-ui:search-container-column-text name="Surname"
			property="lastName" />
 
		<liferay-ui:search-container-column-text name="Department"
			value='<%= eb.getAttribute("Department").toString() %>' />
 
		<liferay-ui:search-container-column-text name="Team"
			value='<%= eb.getAttribute("Team").toString() %>' />
 
		<liferay-ui:search-container-column-text name="Nick Name - from LDAP"
			value='<%= eb.getAttribute("nickName").toString() %>' />
 
		<liferay-ui:search-container-column-text name="title"
			property="jobTitle" />
 
		<liferay-ui:search-container-column-text name="E-Mail"
			property="emailAddress" />
 
		<liferay-ui:search-container-column-text name="Phone"
			value='<%= phoneNo %>' />
 
		<liferay-ui:search-container-column-text name="Mobile"
			value='<%= mobileNo %>' />
 
		<!--   liferay-ui:search-container-column-jsp path="/html/edit.jsp"
			align="right" / -->
	</liferay-ui:search-container-row>
 
 
	<!--  this is what iterates through and displays the list -->
	<liferay-ui:search-iterator />
</liferay-ui:search-container>

WEB-INF/liferay-display.xml

<?xml version="1.0"?>
<!DOCTYPE display PUBLIC "-//Liferay//DTD Display 6.0.0//EN" "http://www.liferay.com/dtd/liferay-display_6_0_0.dtd">
 
<display>
	<category name="Addax">
		<portlet id="Employee Directory" />
	</category>
</display>

WEB-INF/portlet.xml

<?xml version="1.0"?>
 
<portlet-app
	version="2.0"
	xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
>
	<portlet>
		<portlet-name>Employee Directory</portlet-name>
		<display-name>Employee Directory</display-name>
		<portlet-class>ch.ap.ci.portlet.EmployeeDetailsPortlet</portlet-class>
		<init-param>
			<name>view-jsp</name>
			<value>/html/view.jsp</value>
		</init-param>
		<expiration-cache>0</expiration-cache>
		<supports>
			<mime-type>text/html</mime-type>
		</supports>
		<portlet-info>
			<title>Employee Directory</title>
			<short-title>Employee Directory</short-title>
			<keywords>Employee Directory</keywords>
		</portlet-info>
		<security-role-ref>
			<role-name>administrator</role-name>
		</security-role-ref>
		<security-role-ref>
			<role-name>guest</role-name>
		</security-role-ref>
		<security-role-ref>
			<role-name>power-user</role-name>
		</security-role-ref>
		<security-role-ref>
			<role-name>user</role-name>
		</security-role-ref>
	</portlet>
</portlet-app>

html/edit.jsp

<%@include file="/init.jsp"%>
<portlet:actionURL name="updateUser" var="updateUserURL" />
 
<%
	User addaxUser = (User) request.getAttribute("addax.user");
	Contact addaxContact = (Contact) request
			.getAttribute("addax.contact");
 
	ExpandoBridge eb = addaxUser.getExpandoBridge();
	List<Phone> phones = PhoneServiceUtil.getPhones(
			Contact.class.getName(), addaxUser.getContactId());
 
	String mobileNo = "";
	String phoneNo = "";
	for (Phone phone : phones) {
		String phoneType = phone.getType().getName();
 
		System.out.println(">> " + phone.getNumber());
		if ("Business".equals(phoneType)) {
			phoneNo = phone.getNumber();
		} else if ("Mobile".equals(phoneType)) {
			mobileNo = phone.getNumber();
		}
 
	}
	System.out.println("phone " + eb.getAttribute("Department"));
%>
<aui:model-context bean="<%= addaxUser %>" model="<%= User.class %>" />
 
<aui:form action="<%= updateUserURL %>" method="post" name="fm">
	<aui:input name="userId" type="hidden" />
	<aui:fieldset label="Identity">
		<aui:layout>
			<aui:column columnWidth="14">
				<br />
				<img
					src="<%=themeDisplay.getPathImage()%>/user_<%=addaxUser.isFemale() ? "female" : "male"%>_portrait?img_id=<%=addaxUser.getPortraitId()%>" />
			</aui:column>
 
			<aui:column columnWidth="30">
				<aui:input name="firstName" inlineLabel="true" disabled="true"
					size="20" />
				<aui:input name="lastName" inlineLabel="true" size="20" />
				<aui:input name="emailAddress" inlineLabel="true" label="E-Mail :" />
				<aui:input name="phone" type="text" inlineLabel="true"
					value="<%= phoneNo %>" />
				<aui:input name="mobile" type="text" inlineLabel="true"
					value="<%= mobileNo %>" />
			</aui:column>
 
			<aui:column>
				<aui:input name="birthday" bean="<%= addaxContact %>"
					model="<%= Contact.class %>" />
			</aui:column>
		</aui:layout>
	</aui:fieldset>
 
	<aui:fieldset label="Job">
		<aui:layout>
			<aui:column>
				<aui:input name="department" type="text" label="Department :"
					inlineLabel="true" value='<%= eb.getAttribute("Department") %>' />
			</aui:column>
 
			<aui:column>
				<!--  aui:input name="floor" label="Floor :" inlineLabel="true"
					 />  -->
			</aui:column>
		</aui:layout>
 
	</aui:fieldset>
 
 
	<aui:fieldset label="Personal Information">
 
		<aui:column>
		Interests
		</aui:column>
		<aui:column>I love:</aui:column>
		<aui:column>I hate:</aui:column>
 
	</aui:fieldset>
	<aui:button-row>
		<aui:input name="toc" type="radio" inlineLabel="true"
			label="I am responsible for all the contents..." checked="false" />
 
		<aui:button name="saveButton" type="submit" value="Save Modifications" />
		<aui:button name="cancelButton" type="button" value="Cancel"
			last="true" />
	</aui:button-row>
</aui:form>
tech/liferay/portlet-development.txt · Last modified: 2011/07/13 15:19 by davidof
Recent changes RSS feed