Friday, June 13, 2014

Liferay Friendly URL

Introduction:

Friendly URL is way to shorten request URLs so that it’s very continent to use and remember.
If the request URL is very long then it’s not easy to remember or it’s not easy to share it in somewhere else.

In liferay generally we can create any Portlet URL and portlet URL consist of many request parameters and its values apart from those we will add some more request parameters so that finally URL seems to very long.

When we request the URL in browser address bar it seems to very long and have many parameters.

Some time we might not need all parameters and its values and some of parameters always same, some parameters may be default and some parameters may be constants for every time. We consider all above in mind we can shorten the request URLs.

Liferay Friendly URL is the one of the mechanism to shorten liferay portlet URL so that it’s very continent to manage the URL and make others to understand very easy.

Generally in the Portlet Request URL its look like always query string so we can also change the pattern of Portlet URLs from query string pattern to other pattern so that is very convent to remember and understand by others.

General Portlet URL in Liferay



The following are the General Parameters and its values in Portlet URL

p_p_id: current portlet id
p_p_state: window sate
p_p_mode: portlet mode either view/edit
p_p_lifecycle: this is life cycle of portlet  0/1/2
0: render phase or render URL
1: action phase or action URL
2: server resource URL
mvcPath: this is another parameter which we passed from <portlet:param/>  tag


We have different Portlet URLs in Liferay we can create ACTION URL, RENDER URL AND RESOURCE URL.

Follow the below Article for More about Portlet URLs


When we observe about portlet URL it consists of more parameter and values and it’s too long.

Friendly URL Implementation
  1. Configure URL routes in xml file
  2. Friendly URL Implementation Java class
  3. Configure the Friendly URL information in liferay-portlet.xml file.

Configure URL routes in xml file

First we need configure the URL routes in xml configuration file and this configuration based on liferay-friendly-url-routes_6_X_X.dtd

We will decide different pattern for the Portlet URLs and its parameters and values we will configure in the.

We have different xml tags in the DTD so should use predefined tags bases on our need.

The following are the important tags


routes
route
pattern
generated-parameter
ignored-parameter
implicit-parameter
overridden-parameter


Routes

The routes element is the root of the deployment descriptor for a set of Liferay
Friendly URL mapper routes.

Route:

The route element contains information on a single route.

Pattern

The pattern element specifies the pattern of the mapped friendly URL and this will apper in the address bar.

Example:


<routes>
<route>
<pattern>/page/{jspPageName}</pattern>
<generated-parameter name="mvcPath">/html/jsps/{jspPageName}.jsp</generated-parameter>
</route>
</routes>

Note:

Each route we will represented by route tag and all routes enclose by <routes/> tag

generated-parameter

The generated-parameter element specifies the pattern of a parameter that will be generated from other parameters when a URL is recognized. When a URL is built, these virtual parameters will be parsed from the generated parameter and made available in the route pattern for constructing the URL.

It have the name attribute specifies the name of the parameter to be ignored.


<routes>
<route>
<pattern>/page/{jspPageName}</pattern>
<generated-parameter name="mvcPath">/html/jsps/{jspPageName}.jsp</generated-parameter>
</route>
</routes>

ignored-parameter

The ignored-parameter element specifies a parameter that should be ignored and not included in generated URLs. Ignored parameters do not effect URL recognition. It have the name attribute specifies the name of the parameter to be ignored.

It have the name attribute specifies the name of the parameter to be ignored.

<routes>
<route>
<pattern>/action/{actionName}</pattern>
<generated-parameter name="javax.portlet.action">{actionName}</generated-parameter>
<ignored-parameter name="p_auth"/>
<ignored-parameter name="p_p_id"/>
<implicit-parameter name="p_p_lifecycle">1</implicit-parameter>
<implicit-parameter name="p_p_state">normal</implicit-parameter>
<implicit-parameter name="p_p_mode">view</implicit-parameter>
</route>
</routes>

implicit-parameter

The implicit-parameter element specifies a parameter that is not present in the route pattern.

It have the name attribute specifies the name of the parameter to be ignored.

<routes>
<route>
<pattern>/action/{actionName}</pattern>
<generated-parameter name="javax.portlet.action">{actionName}</generated-parameter>
<ignored-parameter name="p_auth"/>
<ignored-parameter name="p_p_id"/>
<implicit-parameter name="p_p_lifecycle">1</implicit-parameter>
<implicit-parameter name="p_p_state">normal</implicit-parameter>
<implicit-parameter name="p_p_mode">view</implicit-parameter>
</route>
</routes>

When any parameter has static values then we can make it as implicit-parameter

overridden-parameter

The overridden-parameter element specifies a parameter that should be set to a certain value when a URL is recognized. This override value will be set regardless of any preexisting value, including one from a implicit-parameter or one extracted from the URL.

It have the name attribute specifies the name of the parameter to be ignored.


<routes>
<route>
<pattern>/rss/{feedId}</pattern>
<ignored-parameter name="p_p_cacheability" />
<implicit-parameter name="p_p_lifecycle">2</implicit-parameter>
<implicit-parameter name="struts_action">/journal/rss</implicit-parameter>
<overridden-parameter name="p_p_cacheability">cacheLevelFull</overridden-parameter>
</route>
</routes>


Note:

Most of Tags description was took form liferay DTD file. Friendly URL starts with -/ and it will continue with route

Example




Note:

When we configure Friendly URL tags we need follow the order otherwise its show syntax error.

Order as follows


pattern
generated-parameter
ignored-parameter
implicit-parameter
overridden-parameter


Friendly URL Implementation Java class

We need one java implementation class to generate friendly URLs based on routes.

We have liferay implemented class i.e. DefaultFriendlyURLMapper so that we can use.

Apart from this we can also implement our own implementation class so that it should generate URLs as for our requirement.

Implementation class should implement the FriendlyURLMapper interface or it should extend the DefaultFriendlyURLMapper class.

Configure the Friendly URL information in liferay-portlet.xml file

Configure Friendly URL Configuration java class, routes configuration xml file and its main friendly mapper in liferay-portlet.xml

The tags configuration placed after <icon/> tag and before <instanceable>

Example:


<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>
<friendly-url-mapping>ems</friendly-url-mapping>
<friendly-url-routes>com/meera/liferaymvc/employee-management-friendly-url-routes.xml</friendly-url-routes>


Note:

We have DefaultFriendlyURLMapper as java class use this as default

Friendly URL implementation in Plugin Portlet Development

Assume we have Employee Management System (EMS) Application.

Scenario:1

In the Employ management System we have different jsp pages and when we access the JSP page, in the URL we just want see only page name instead of long URL.

When we navigate to each page we just need jsp page name in the URL


/-/ems/page/addEmpoyee

/-/ems/page/editEmpoyee

/-/ems/page/searchEmpoyee



Note:

ems is main Friendly URL root for Employee Management System and friendly always separated with /-/ path.

The following is implementation

Step: 1

Configure Friendly URL Configuration java class, routes configuration xml file and its main friendly mapper in liferay-portlet.xml .The tags configuration placed after <icon/> tag and before <instanceable>

Configuration in liferay-portlet.xml file


<portlet>
<portlet-name>Employee Liferay Mvc</portlet-name>
<icon>/icon.png</icon>
<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>
<friendly-url-mapping>ems</friendly-url-mapping>
<friendly-url-routes>com/meera/liferaymvc/employee-management-friendly-url-routes.xml</friendly-url-routes>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>
/js/main.js
</footer-portlet-javascript>
<css-class-wrapper>
employee liferay mvc-portlet
</css-class-wrapper>
</portlet>


Note:

We have DefaultFriendlyURLMapper  java class use this as default friendly url mapper class and it is already implemented by liferay.

Step: 2

Configure routes in configuration file and we need to defined pattern by using friendly URL xml tags.

The following is configuration in employee-management-friendly-url-routes.xml


<routes>
<route>
<pattern>/page/{jspPageName}</pattern>
<generated-parameter name="mvcPath">/html/jsps/{jspPageName}.jsp</generated-parameter>
</route>
</routes>


In the pattern tag we need specify the pattern how we want see the URL after generation in the browser address bar and we are using generated parameter for mvcPath so that each time mvcPath parameter value replaced in pattern path.

We need to create this xml file in src directory. Assume we create in the package called com/meera/liferaymvc/employee-management-friendly-url-routes.xml

We need provide fully qualified package name in the configuration when we do in liferay-portlet.xml file

 URL creation in JSP Page


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<portlet:renderURL  var="addEmployee" windowState="normal">
<portlet:param name="mvcPath" value="/html/jsps/addEmployee.jsp"/>
</portlet:renderURL>
<portlet:renderURL  var="editEmployee" windowState="normal">
<portlet:param name="mvcPath" value="/html/jsps/editEmployee.jsp"/>
</portlet:renderURL>
<portlet:renderURL  var="searchEmployee" windowState="normal">
<portlet:param name="mvcPath" value="/html/jsps/searchEmployee.jsp"/>
</portlet:renderURL>
<h1>Welcome to Liferay MVC Employee Portlet</h1>

<a href="<%=addEmployee.toString()%>">Add Employee</a><br/>
<a href="<%=editEmployee.toString()%>">Edit Employee</a><br/>
<a href="<%=searchEmployee.toString()%>">Search Employee</a><br/>


URL Generated in Browser Address Bar as follows when we access JPS pages






Scenario: 2

In the Employ management System we have different action we will do like add Employee Action, Edit Employee and Search Employee Action.

Assume our URL pattern as follows


/ems/action/addEmployee

/ems/action/editEmployee

/ems/action/searchEmployee


Note:

ems is main Friendly URL root for Employee Management System

The following is implementation

Step: 1

Configure Friendly URL Configuration java class, routes configuration xml file and its main friendly mapper in liferay-portlet.xml .The tags configuration placed after <icon/> tag and before <instanceable>

Configuration in liferay-portlet.xml file

<portlet>
<portlet-name>Employee Liferay Mvc</portlet-name>
<icon>/icon.png</icon>
<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>
<friendly-url-mapping>ems</friendly-url-mapping>
<friendly-url-routes>com/meera/liferaymvc/employee-management-friendly-url-routes.xml</friendly-url-routes>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>
/js/main.js
</footer-portlet-javascript>
<css-class-wrapper>
employee liferay mvc-portlet
</css-class-wrapper>
</portlet>

Note:

We have DefaultFriendlyURLMapper as java class use this as default


Step: 2

Configure routes in configuration file and we need to defined pattern by using friendly URL xml tags

The following is configuration in employee-management-friendly-url-routes.xml


<routes>
<route>
<pattern>/action/{actionName}</pattern>
<generated-parameter name="javax.portlet.action">{actionName}</generated-parameter>
<ignored-parameter name="p_auth"/>
<ignored-parameter name="p_p_id"/>
<implicit-parameter name="p_p_lifecycle">1</implicit-parameter>
<implicit-parameter name="p_p_state">normal</implicit-parameter>
<implicit-parameter name="p_p_mode">view</implicit-parameter>
<overridden-parameter name="p_auth"></overridden-parameter>
</route>
</routes>


In the pattern tag we specified the actual pattern how we want see and we are using generated parameter for javax.portlet.action so that each time javax.portlet.action parameter value replaced in pattern path.We don’t need portlet id in the URL so we simply ignored p_p_id
Some of URL parameters we don’t want see in the URL so we simple make it as implicit parameters (p_p_lifecycle,p_p_stat,p_p_mode)

We already know we are performing action and we need portlet action URL .we already know action URL lifecycle always 1 so we can make it p_p_lifecycle as implicit parameters and same we can apply it based on our need and how you want see the generated URL.

URL creation in JSP Page for Actions

Add Employee Page


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<portlet:actionURL var="addEmployeeActionURL" windowState="normal" name="addEmployee">
</portlet:actionURL>
<h1> Add Employee</h1>
<form action="<%=addEmployeeActionURL%>" name="emplyeeForm"  method="POST">
Employee Name<br/>
<input  type="text" name="<portlet:namespace/>employeeName" id="<portlet:namespace/>employeeName"/><br/>
Employee Address<br/>
<input type="text" name="<portlet:namespace/>employeeAddress" id="<portlet:namespace/>employeeName"/><br/>
<input type="submit" name="addEmployee" id="addEmployee" value="Add Employee"/>
</form>


Edit Employee Page


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<portlet:actionURL var="addEmployeeActionURL" windowState="normal" name="editEmployee">
</portlet:actionURL>
<h1> Add Employee</h1>
<form action="<%=addEmployeeActionURL%>" name="emplyeeForm"  method="POST">
Employee Name<br/>
<input  type="text" name="<portlet:namespace/>employeeName" id="<portlet:namespace/>employeeName"/><br/>
Employee Address<br/>
<input type="text" name="<portlet:namespace/>employeeAddress" id="<portlet:namespace/>employeeName"/><br/>
<input type="submit" name="addEmployee" id="addEmployee" value="Edit Employee"/>
</form>


Search Employee Page


<%@page import="java.util.Map"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<portlet:actionURL var="searchEmployeeActionURL" windowState="normal" name="searchEmployee">
</portlet:actionURL>
<h1> Add Employee</h1>
<form action="<%=searchEmployeeActionURL%>" name="emplyeeForm"  method="POST">
Employee Name<br/>
<input  type="text" name="<portlet:namespace/>employeeName" id="<portlet:namespace/>employeeName"/><br/>
<input type="submit" name="searchEmployee" id="searchEmployee" value="Search Employee"/>
</form>
<br/>
<%
Map<String,String> employeeMap=(Map<String,String>)renderRequest.getAttribute("employeeMap");
if(employeeMap!=null){
%>
Emplyee Name: <%=employeeMap.get("employeeName")%>     <br/>
Emplyee Address: <%=employeeMap.get("employeeAddress")%><b/>
<%}%>


URL Generated in Browser Address Bar for above Actions






Scenario: 3

Assume we are deleting employee by Emplyee Id and the following is our pattern
/ems/action/deleteEmployee/employeeId

Same we can think get employee by employeeId

/ems/action/getEmployee/employeeId

When pass employee Id then particulate employee will be deleted same when we pass employee id then employee will be return these are based on action we used.

The following is configuration in employee-management-friendly-url-routes.xml


<routes>
<route>
<pattern>/action/{actionName}/employeeId/{empId:\d+}</pattern>
<generated-parameter name="javax.portlet.action">{actionName}</generated-parameter>
<generated-parameter name="empId">{empId}</generated-parameter>
<ignored-parameter name="p_auth"/>
<ignored-parameter name="p_p_id"/>
<implicit-parameter name="p_p_lifecycle">1</implicit-parameter>
<implicit-parameter name="p_p_state">normal</implicit-parameter>
<implicit-parameter name="p_p_mode">view</implicit-parameter>
</route>
</routes>


Note:

We will use regular expression for each parameter so that it will consider the value with given regular expression. Example employee should be digit.

Delete Employee JSP Page


<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<h1>Delete Employee</h1>
<%for(int i=1;i<10;i++){ %>
<portlet:actionURL var="deleteEmployeeActionURL" windowState="normal" name="deleteEmployee">
<portlet:param name="empId" value="<%=String.valueOf(i) %>"/>
</portlet:actionURL>
<a href="<%=deleteEmployeeActionURL.toString()%>">Delete Employee&nbsp;<%=i%></a><br/>
<%} %>


Get Employee JSP Page


<%@page import="java.util.Map"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<portlet:defineObjects />
<h1>Delete Employee</h1>
<%for(int i=1;i<10;i++){ %>
<portlet:actionURL var="getEmployeeActionURL" windowState="normal" name="getEmployee">
<portlet:param name="empId" value="<%=String.valueOf(i) %>"/>
</portlet:actionURL>
<a href="<%=getEmployeeActionURL.toString()%>">Get Employee&nbsp;<%=i%></a><br/>
<%} %>

<br/>
<%
Map<String,String> employeeMap=(Map<String,String>)renderRequest.getAttribute("employeeMap");
if(employeeMap!=null){
%>
Emplyee Name: <%=employeeMap.get("employeeName")%>     <br/>
Emplyee Address: <%=employeeMap.get("employeeAddress")%><b/>
<%}%>


URL Generated in Browser Address bar when we click on Delete/Get Employee Links





Insatiable Portlets

If the portlet is instanceable then we should always use instance id in the URL pattern when we configure routes otherwise it could not generate friendly URL.

Example:


<route>
<pattern>/{instanceId}/action/{actionName}</pattern>
<generated-parameter name="javax.portlet.action">{actionName}</generated-parameter>
<ignored-parameter name="p_auth"/>
<ignored-parameter name="p_p_id"/>
<implicit-parameter name="p_p_lifecycle">1</implicit-parameter>
<implicit-parameter name="p_p_state">normal</implicit-parameter>
<implicit-parameter name="p_p_mode">view</implicit-parameter>
</route>


Complete Friendly URL portlet Source Code

Portlet liferay-portlet.xml file (/WEB-INF/liferay-portlet.xml)


<portlet>
<portlet-name>Employee Liferay Mvc</portlet-name>
<icon>/icon.png</icon>
<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>
<friendly-url-mapping>ems</friendly-url-mapping>
<friendly-url-routes>com/meera/liferaymvc/employee-management-friendly-url-routes.xml</friendly-url-routes>
<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>
/js/main.js
</footer-portlet-javascript>
<css-class-wrapper>
employee liferay mvc-portlet
</css-class-wrapper>
</portlet>


Friendly URL routes configuration file (/WEB-INF/src/com/meera/liferaymvc/employee-management-friendly-url-routes.xml)


<routes>
<route>
<pattern>/page/{jspPageName}</pattern>
<generated-parameter name="mvcPath">/html/jsps/{jspPageName}.jsp</generated-parameter>
</route>
<route>
<pattern>/action/{actionName}/employeeId/{empId:\d+}</pattern>
<generated-parameter name="javax.portlet.action">{actionName}</generated-parameter>
<generated-parameter name="empId">{empId}</generated-parameter>
<ignored-parameter name="p_auth"/>
<ignored-parameter name="p_p_id"/>
<implicit-parameter name="p_p_lifecycle">1</implicit-parameter>
<implicit-parameter name="p_p_state">normal</implicit-parameter>
<implicit-parameter name="p_p_mode">view</implicit-parameter>
</route>
<route>
<pattern>/action/{actionName}</pattern>
<generated-parameter name="javax.portlet.action">{actionName}</generated-parameter>
<ignored-parameter name="p_auth"/>
<ignored-parameter name="p_p_id"/>
<implicit-parameter name="p_p_lifecycle">1</implicit-parameter>
<implicit-parameter name="p_p_state">normal</implicit-parameter>
<implicit-parameter name="p_p_mode">view</implicit-parameter>
</route>
</routes>


Portlet Action Class


public class EmployeeLiferayMVC extends MVCPortlet {
public void addEmployee(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
String employeeName = ParamUtil.getString(actionRequest, "employeeName");
String employeeAddress = ParamUtil.getString(actionRequest,
"employeeAddress");
Map<String, String> employeeMap = new HashMap<String, String>();
employeeMap.put("employeeName", employeeName);
employeeMap.put("employeeAddress", employeeAddress);
actionRequest.setAttribute("employeeMap", employeeMap);
actionResponse.setRenderParameter("mvcPath","/html/jsps/displayEmployee.jsp");
System.out.println("=========Employe was added===============");
}
public void editEmployee(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
String employeeName = ParamUtil.getString(actionRequest, "employeeName");
String employeeAddress = ParamUtil.getString(actionRequest,
"employeeAddress");
Map<String, String> employeeMap = new HashMap<String, String>();
employeeMap.put("employeeName", employeeName);
employeeMap.put("employeeAddress", employeeAddress);
actionRequest.setAttribute("employeeMap", employeeMap);
actionResponse.setRenderParameter("mvcPath","/html/jsps/editEmployee.jsp");
System.out.println("=========Employe was edited===============");
}

public void searchEmployee(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
Map<String, String> employeeMap = new HashMap<String, String>();
employeeMap.put("employeeName","meera prince");
employeeMap.put("employeeAddress","hyderabad");
actionRequest.setAttribute("employeeMap", employeeMap);
actionResponse.setRenderParameter("mvcPath","/html/jsps/searchEmployee.jsp");
System.out.println("=========Employe was searched===============");
}
public void deleteEmployee(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
long employeeId = ParamUtil.getLong(actionRequest,"employeeId");
//delete emplyee code here
System.out.println("Employee was delted"+employeeId);
actionResponse.setRenderParameter("mvcPath","/html/jsps/deleteEmployee.jsp");
System.out.println("=========Employe was delteted it by ID===========");
}

public void getEmployee(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
long employeeId = ParamUtil.getLong(actionRequest,"employeeId");
Map<String, String> employeeMap = new HashMap<String, String>();
employeeMap.put("employeeName","meera prince");
employeeMap.put("employeeAddress","hyderabad");
actionRequest.setAttribute("employeeMap", employeeMap);
actionResponse.setRenderParameter("mvcPath","/html/jsps/getEmployee.jsp");
System.out.println("=========Employe Object was Get it by  ID==========");
}
}


Note:

Portlet action class does not have real functionality it’s just for running the portlet.

Download Liferay Friendly URL Portlet





Environment:

Liferay IDE 2.x+Eclipse (Kepler) +Liferay Plugins SDK 6.2+Tomcat 7.x Liferay Portal Bundle

Deployment and its Working.

Download portlet you can source or war file to deploy into liferay portal as your convenient.

Once portlet successfully deployed drag the portlet in any desired page. Portlet is available in sample category name as Employee Liferay Mvc.

Now access jsp pages and perform the action then observe all URL in the browser address so that you can see very shorten URLs.

Portlet Screens:

Default Page


Friendly URL when we access JSP pages.




Friendly URL when Perform Actions


Friendly URL when we Perform Delete/Get Employee Action by Employee Id


Reference Links







Author

Popular Posts

Recent Posts

Recent Posts Widget