`

Liferay 5.2.3: custom URLs formats

阅读更多


Liferay SEO capabilities seems to be surprisingly weak when it comes to URL management. Consider an example: you’re trying to build a webapp that will be doing some abstract searches over some search data sources, and present the results on one page.

You want page to have URL like http://<host>[:<port>]/section/subsection/search/<keyword>[?someParam=<value>]
Particular goals: URL can be generated by other website that knows nothing of our Liferay-based portal internals, and it (URL) should be nice and bookmarkable.

On the page you want to have some portlets, provided by different development teams/vendors, that would get the keyword and present results. The portlets should be independent since new ones can be added over time, and you want to be able to order development of several new portlets in parallel via several independent vendors. Thus every portlet on page should be able to obtain <keyword> and <value> passed in URL to page.

So, what does Liferay provide?
1. URL patterns are /web/<organization>/<page> by default. There are a couple of tricks to handle “/web/<organization>” part (configuring virtual hosts etc), yet they’re not very intuitive.
2. Friendly URL mapper (Liferay 6 and Liferay 5 differ here BTW) that at best will allow you to have URLs like /web/guest/search/-/searchportlet_A/keyword/<keyword> – if your portlet with ID “searchportlet_A” is non-instanceable, this and only this particular portlet will get “keyword” parameter value from this URL.

I didn’t spend too much time digging in details of these solutions (and thus it might be I’m wrong about some details), but it’s obvious we’re not going to get far with this. So what can we do?

It turns out that Liferay has Tucky URL Rewriter filter in it, disabled by default. Using this filter we could map URLs that we want to a page that we want (doing it with forward of-course, no redirects from nice URL to ugly URLs or anything like this).
It will be a task for our portlet(s) to render proper custom URLs, but that’s not a big problem, it’s just nothing will facilitate us to do it. But well, this is the price of having absolutely custom format of URLs. Thus we can get our page by any URL we want.

But next question is – how to obtain outer URL and it’s parameters from portlets on a page?
Digging in Liferay 5 API revealed the somewhat obscure com.liferay.portal.util.PortalUtil class that provides static methods like getCurrentURL(PortletRequest) and PortalUtil.getHttpServletRequest(PortletRequest) + PortalUtil.getOriginalHttpServletRequest(ServletRequest).

Seems like we’ve got what we need, right? Not yet.
PortalUtil methods work Ok… until you enable forwarding via Tucky URL Rewrite filter. Once you enable it, URLs like “/c/layout/” will be returned instead of expected original URL that user typed into his browser’s address bar.
Obviously, author of the code didn’t expect that original request could already be a forwarded request. Well, not good – you did included Tucky URL Rewriter, didn’t you, so why using it is should come as something unexpected? (-;

Fortunately, sources of all the stuff are available, so I could quickly identify a problem and make a fix. Cheers to open-source!
We want our solution to be deployable to any Liferay 5 instance customers might already have, thus I didn’t put fixed into Liferay sources, but make a small “wrapper” for PortalUtil instead.

package com.mykola.makhin.liferay.portal.util;

import javax.portlet.PortletRequest;
import javax.servlet.http.HttpServletRequest;

import com.liferay.portal.util.PortalUtil;

public class LiferayUtil {

	public static String getOuterRequestUrl(PortletRequest portletRequest) {
		String result;

		HttpServletRequest servletRequest = PortalUtil.getHttpServletRequest(portletRequest);
		String forwardedRequestUri = (String) servletRequest.getAttribute("javax.servlet.forward.request_uri");
		String forwardedRequestQueryString = (String) servletRequest.getAttribute("javax.servlet.forward.query_string");
		if (forwardedRequestUri != null) {
			result = forwardedRequestUri;
			if (forwardedRequestQueryString != null) {
				result += "?" + forwardedRequestQueryString;
			}
		} else {
			result = PortalUtil.getCurrentURL(portletRequest);
		}

		return result;
	}

	public static String getOuterRequestParameter(PortletRequest portletRequest, String paramName) {
		HttpServletRequest servletRequest = PortalUtil.getHttpServletRequest(portletRequest);

		return PortalUtil.getOriginalServletRequest(servletRequest).getParameter(paramName);
	}
}

Ok, so we can obtain external URL and URL parameters with this utility, how do we put it all together?
Here’s the plan:
1. Enable and configure Tucky URL rewriter.
How to do this? We use Tomcat-bundled distribution of Liferay 5, so direct way would be to edit web.xml and urlrewrite.xml in “tomcat-6.0.18/webapps/ROOT/WEB-INF” folder, but more smart would be to deploy it using Liferay EXT environment .
In EXT go to “ext-web/docroot/WEB-INF”, edit web.xml and create+edit urlrewrite.xml files (note: don’t append -ext to file names).
Contents of web.xml will be merged with other contents that are in Liferay already, so what we put in web.xml file in EXT is just this:

<?xml version="1.0"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
        <filter>
                <filter-name>URL Rewrite Filter</filter-name>
                <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
                <init-param>
                        <param-name>logLevel</param-name>
                        <param-value>ERROR</param-value>
                </init-param>
                <init-param>
                        <param-name>statusEnabled</param-name>
                        <param-value>true</param-value>
                </init-param>
        </filter>
        <filter-mapping>
                <filter-name>URL Rewrite Filter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>
</web-app>

Contents of urlrewrite.xml for our example will be something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 2.6//EN" "http://tuckey.org/res/dtds/urlrewrite2.6.dtd">

<urlrewrite>
	<rule>
		<from>/section/subsection/search/([^\?]+)\?(.*)</from>
		<to type="forward">/web/myorganization/search?keyword=$1&amp;$2</to>
	</rule>
	<rule>
		<from>/section/subsection/search/([^\?]+)$</from>
		<to type="forward">/web/myorganization/search?keyword=$1</to>
	</rule>
</urlrewrite>

2. Now we can use LiferayUtil.getOuterRequestParameter(PortletRequest, “keyword”) and LiferayUtil.getOuterRequestParameter(PortletRequest, “anyParameter”) in our portlet to obtain parameters we need (note that in original URL “keyword” is not a parameter, but in rewritten it is, and thus getting it from forwarded request works just allright).

3. The only this left to us is to render URLs with proper format in our Portlets.
Since we can put any parameter in rewritten url (i.e. make something like <to type=”forward”>/web/myorganization/search?urlRewritten=true&amp;keyword=$1</to>) we can be aware whether portlet is on page accessed by nice SEO friendly URL or not, and correspondingly render either custom format SEO friendly URLs, or just do usual portlet render/action URLs.

That’s it.
I want to point out that resulting solution is quite easy to deploy to production environments that already have Liferay running.
Though EXT environment it a bit heavy, we can always ship only our two files. They can be written to clean distribution of EXT, downloaded straight from official site, and then ext can be deployed the usual way. And next time on same environment we don’t even need to do this again of course, we’ll only have to deploy our new/updated portlets.

Conclustion: I’ve spent a couple of days (partially, not the entire days he-he (-:) thinking and digging until I came up with 100% working solution (and relatively easily deployable too). I’m a bit surprised I could not google-up a solution like this, and especially surprised with what’s offered officially from Liferay (because rest of my experience with Liferay was rather positive so far). And curse Portlet APIs (d-:) for not even thinking about things like this.

Hopefully this post will save somebody time and effort of figuring out how to accomplish this task. After all, having a custom URL format for your webapp must be simple in year 2010, right? (-;
And once again, open source approach (as well as usage of standard tools – Tucky URL Rewriter in this case) saved time and effort, and actually made some things possible that otherwise would not be (or seem to be) so.

分享到:
评论

相关推荐

    Liferay5.2.3 样例Portlet

    Liferay5.2.3的样例,通过war.bat打包后发布到相应的liferay环境即可。 另外,需要配置context,tomcat中的代码如下: &lt;/Context&gt;

    Liferay 5.2.3 二次开发环境搭建

    本篇文章将详细讲解如何在基于Myeclipse 6和Tomcat 6.0.24的环境中搭建Liferay 5.2.3的二次开发环境。 **一、环境准备** 在开始Liferay的开发工作之前,我们需要准备好以下软件: 1. **Myeclipse 6**: 这是一个...

    liferay5.2.3 tomcat6 eclipse ide 开发文档

    ### Liferay 5.2.3 Tomcat6 Eclipse IDE 开发文档详解 #### 一、前言 **1.1 编写说明** 本开发文档旨在为初学者和经验丰富的开发者提供全面指南,涵盖Liferay 5.2.3与Tomcat6在Eclipse IDE中的集成、配置和开发...

    Liferay5.2.3和CAS配置成SSO

    本案例中,我们将探讨如何将Liferay 5.2.3与CAS(Central Authentication Service)配置为SSO系统。 Liferay是一款开源的企业级门户平台,它提供了一个灵活的框架来构建和管理Web应用程序。而CAS则是一个开源的身份...

    Liferay_5.2.3_开发环境环境搭建

    - **下载Liferay 5.2.3**:首先,你需要从Liferay的官方仓库或互联网存档中下载Liferay Portal 5.2.3 GA4的版本。确保选择适合你的操作系统的版本,通常有Windows、Linux和Mac OS X可供选择。 - **开发工具**:...

    liferay 5.2.3 可實際用於建構 jbpm workflow portlet的 jbpm及mule war檔

    liferay 5.2.3 可實際用於建構 jbpm workflow portlet的 jbpm檔。 用這個檔案加上mule再參考網路上的設定文件,即可輕易的在5.2.3上完成workflow portlet的建置... mule檔太大,請在liferay網路上下載即可

    构建统一门户Liferay 最新产品 5.2.3二次开发环境

    本教程将聚焦于Liferay 5.2.3版本的二次开发环境搭建,这将为开发者提供一个深入理解Liferay工作原理并进行自定义扩展的基础。 首先,我们需要下载Liferay 5.2.3的源码。Liferay的源代码可以从其官方网站的历史版本...

    liferay plugins sdk 5.2.3

    Liferay Plugins SDK 5.2.3 是一个专门用于开发Liferay Portal的portlet和其他插件的应用开发工具包。Liferay Portal是一款开源的企业级内容管理平台,它提供了丰富的功能,包括网站构建、社交网络、协作工具等。这...

    LIferay 自带标签介绍

    在本文中,我们将深入探讨Liferay门户框架中的自带标签,这些标签为开发者提供了便捷的方式来构建用户界面和处理页面逻辑。Liferay是一个开源的企业级内容管理系统,其强大的功能和自定义能力使得它在企业级应用中...

    liferay-tomcat:使用 Docker.io 设置 Liferay 环境

    #Liferay 在码头工人Liferay版本:liferay-portal-tomcat-6.2-ce-ga2-20140319114139101 busybox 上的基础图像以获得更小的图像(~600M) 将 tomcat 日志文件移动到 $LIFERAY_HOME/logs/tomcat 暴露端口 8080 #卷/...

    Liferay相关资料

    2. **Liferay5.2.3环境搭建**: 这个文档详细指导如何设置Liferay 5.2.3的运行环境,包括JDK、数据库、应用服务器的配置,以及portlet部署等步骤。理解环境搭建对于开发者来说至关重要,能快速开始开发工作。 3. *...

    Liferay-Portlet-SDK5.2.3.rar_liferay_liferay sdk_portlet

    **Liferay Portlet SDK 5.2.3详解** Liferay Portlet SDK 是 Liferay Portal 平台的一个重要组成部分,它为开发者提供了构建、部署和管理portlet所需的所有工具和技术支持。Liferay Portlet SDK 5.2.3是该系列的一...

    vagrant-liferay7:Liferay 7 vagrant 环境 Ubuntu64

    Liferay 7 开发环境 基于: : 概述 这是一个示例项目,用于展示 Liferay 开发/测试环境的自动安装。 它使用 VirtualBox 和 Vagrant 进行 VM 管理,使用 Puppet 进行配置。 设置 克隆这个项目。 安装 VirtualBox: ...

    liferay标签

    **Liferay标签**是Liferay门户框架中用于构建动态用户界面的重要组成部分。Liferay是一个开源的企业级内容管理系统,提供了一套强大的工具来创建、管理和展示Web内容。在Liferay中,标签(Taglib)是一组预定义的JSP...

    liferay挑战:Liferay实习挑战!

    git clone https://github.com/nananananate/liferay-challengecd liferay-challenge要运行CLI应用程序( .jar文件),请使用以下命令: 视窗: java -jar .\out\artifacts\challenge_jar\challenge.jarLinux / ...

    liferay portal搭建资料1223

    本篇将详细介绍如何搭建Liferay 5.2.3的开发环境。 1. 关于 Liferay Liferay Portal提供了丰富的功能,如内容管理、文档共享、论坛、博客、工作流等,并支持多语言、多主题、自定义portlet等特性。5.2.3是Liferay的...

    liferay-ide-eclipse-updatesite-1.6.2

    《Liferay IDE Eclipse 更新站点详解》 在软件开发领域,集成开发环境(IDE)是程序员不可或缺的工具,而Liferay IDE则是专为Liferay Portal定制的一款强大的Eclipse插件。本文将详细介绍“liferay-ide-eclipse-...

Global site tag (gtag.js) - Google Analytics