Tuesday, 3. October 2006, 19:09:17
There was a discussion among us at work about JSR-168 Portlets. A colleague of mine believed that there is no way to stop users resubmitting a form several times (intentionally or not) by pressing F5 whereas in plain Web development this can be taken care of easily.
I told him that I have
read somewhere that this problem (reditect after post, or RAP for short) is taken care of well in the JSR-168 specification.
Unfortunately Subbu has not provided a sample showing how one can handle this situation. And the Portlets hosted in java.net's
Portlet repository have not taken care of this problem as well (they do not reditect after post.)
Here, I show a method to redirect the client browser after a post in a JSP-based Portlet. In a JSF-based portlet, the solution seems to be to use <redierect /> in the navigation cases in which there's a need to redirect (I have not tested this yet).
Click
here to download the ready-to-deploy WAR file (tested on Liferay 4.1.2)
The Portlet class:
/*
* Created by Behrang Saeedzadeh
* on Sep 29, 2006 @ 3:22:49 AM
*/
package org.behrang.practice.jsr168.rap;
import javax.portlet.*;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
/**
* This is a minimal Portlet, that shows how one can solve the
* <a href="http://www.subbu.org/weblogs/main/2006/06/is_the_portlet.html">reditect-after-post</a>
* problem in a JSR-168 Portlet container.
*
* First, it views a simplistic page (<code>index.jsp</code>) containing one link to a page that contains
* a simple form (<code>form.jsp</code>.)<p>Then, when the user enters an item in the form and submits it,
* the portlet stores the item in the <code>ITEMS</code> class side variable, and then redirects to the
* original index.jsp page.
*
* @author Behrang Saeedzadeh
*/
public class Portlet extends GenericPortlet {
public static List<String> ITEMS = new ArrayList<String>();
public void processAction(ActionRequest req, ActionResponse resp) throws PortletException, IOException {
String item = req.getParameter("item");
ITEMS.add(item);
resp.sendRedirect(req.getParameter("renderURL"));
}
protected void doView(RenderRequest req, RenderResponse resp) throws PortletException, IOException {
req.setAttribute("renderURL", resp.createRenderURL());
String page = req.getParameter("page");
page = page == null ? "/rap/index.jsp" : page;
PortletRequestDispatcher prd = getPortletContext().getRequestDispatcher(page);
prd.include(req, resp);
}
}
The index.jsp
<%@ page import="org.behrang.practice.jsr168.rap.Portlet"%>
<%@ taglib prefix="p" uri="http://java.sun.com/portlet" %>
<p:defineObjects />
<div>
<% for (String s : Portlet.ITEMS) { %>
<%= s %> <br>
<% } %>
<p:renderURL var="formURL">
<p:param name="page" value="/rap/form.jsp" />
</p:renderURL>
<a href="<%= formURL %>">To Form</a>
</div>
The form.jsp
<%@ taglib prefix="p" uri="http://java.sun.com/portlet" %>
<p:defineObjects />
<div>
<form action="<p:actionURL />" method="POST">
<input name="item" type="text" size="10" />
<input name="renderURL" type="hidden" value="<%= renderRequest.getAttribute("renderURL")%>" />
</form>
</div>
The portlet.xml descriptor file
<?xml version="1.0"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
<portlet>
<portlet-name>RedirectAfterPostPortlet</portlet-name>
<display-name>Redirect After Post Portlet</display-name>
<portlet-class>org.behrang.practice.jsr168.rap.Portlet</portlet-class>
<supports>
<mime-type>text/html</mime-type>
</supports>
<portlet-info>
<title>Redirect After Post</title>
<short-title>RAP</short-title>
</portlet-info>
</portlet>
</portlet-app>
The web.xml descriptor file (for Liferay!
) A long road to achieve WODA (write once, deploy anywhere!)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>RAP</display-name>
<taglib>
<taglib-uri>http://java.sun.com/portlet</taglib-uri>
<taglib-location>/WEB-INF/tld/liferay-portlet.tld</taglib-location>
</taglib>
</web-app>