How to create a Blog in Portofino 4 - part 4
In this fourth tutorial we are going to customize the comment page.
If you haven't, read tutorial part 1, part 2, part 3.
The aim is to join the "create" and "search"page", this offers the possibility to read and create comments in the same page.
The goal is show in the following picture.
Step 1. Create a single page to list and create comments
Let's edit the "Groovy" action of the "comment" page for fowarding to a custom jsp. This jsp will show the list and a form for creating comments.
@SupportsPermissions([ CrudAction.PERMISSION_CREATE, CrudAction.PERMISSION_EDIT, CrudAction.PERMISSION_DELETE ]) @RequiresPermissions(level = AccessLevel.VIEW) class MyCrudAction extends CrudAction { //********************************************* // List objects //********************************************* @DefaultHandler public Resolution execute() { if (object == null) { return doList(); } else { return read(); } } public Resolution doList(){ loadObjects(); String jsp = "/apps/default/web/listComments.jsp"; return new ForwardResolution(jsp); }
The custom jsp page displays a list of comments and allows you to add new ones as shown in the following code.
<%@ page import="java.util.List" %> <%@ page import="com.manydesigns.elements.xml.XhtmlBuffer" %> <%@ page import="java.util.HashMap" %> <%@ page import="java.text.SimpleDateFormat" %> <%@ page import="javax.xml.crypto.Data" %> <%@ page import="java.util.Date" %> <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes-dynattr.tld"%> <%@taglib prefix="mde" uri="/manydesigns-elements"%> <%@ taglib tagdir="/WEB-INF/tags" prefix="portofino" %> <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <stripes:layout-render name="/skins/${skin}/portlet.jsp"> <jsp:useBean id="actionBean" scope="request" type="com.manydesigns.portofino.pageactions.crud.CrudAction"/> <stripes:layout-component name="portletTitle"> <c:out value="${actionBean.crudConfiguration.searchTitle}"/> </stripes:layout-component> <stripes:layout-component name="portletBody"> <% SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy"); XhtmlBuffer buffer = new XhtmlBuffer(); for (HashMap object : (List<HashMap>)actionBean.objects){ buffer.openElement("strong"); buffer.write((String) object.get("author")); buffer.writeBr(); buffer.write(df.format((Date)object.get("date"))); buffer.closeElement("strong"); buffer.writeParagraph((String)object.get("comment")); buffer.writeBr(); buffer.writeHr(); } out.println(buffer.toString()); %> <h1>Add a new comment</h1> <form enctype="multipart/form-data" action="<%= ((HashMap)actionBean .getOgnlContext().get("post")).get("id")%>/comment" method="post"> <fieldset class="mde-form-fieldset mde-no-legend"> <table class="mde-form-table"> <tbody> <tr> <th>* Comment</th> <td><textarea id="comment" type="text" name="comment" class="mde-text-field" maxlength="2147483647" cols="45" rows=5> </textarea> </td> </tr> <tr> <th><label for="author" class="mde-field-label"> <span class="required">*</span> Author:</label> </th> <td> <input id="author" type="text" name="author" class="mde-text-field" maxlength="100" size="45"> </td> </tr> </tbody> </table> </fieldset> <input type="hidden" name="cancelReturnUrl" value="/post/<%= ((HashMap)actionBean.getOgnlContext() .get("post")).get("id")%>"/> <input type="hidden" name="post" value="<%= ((HashMap)actionBean.getOgnlContext() .get("post")).get("id")%>"/> <input type="submit" value="Add comment" name="save" class="ui-button ui-widget ui-state-default ui-corner-all portletButton ui-button-text-only" role="button" aria-disabled="false"/> </form> </stripes:layout-component> </stripes:layout-render>
The section for creating a new comment is of particular interest. The form builds the action link with the id of the post and the String "comment". This is done to address the crud action of comments and not the one of post (the one where form is placed).
The fields have the properties names to be mapped to the Crud object. The submit tag has "save" for the property "name", this bind the submit to the method "save" in the CrudAction.
We can test our application, but we soon notice that we have the comments listed in the post page, but, after we save a comment, we are directed to the detail page of the comment.
We can change this behavour. Let's ovveride the "save" method to forward to the parent page (the post to which the comment is linked). In the following code I'll use the parent path through the pageInstance object.
//Save redirects to blog post @Button(list = "crud-create", key = "commons.save", order = 1d) @RequiresPermissions(permissions = AbstractCrudAction.PERMISSION_CREATE) public Resolution save() { super.save(); if(!form.validate()){ SessionMessages .addErrorMessage("Please insert the Comment and the Author fields"); } return new RedirectResolution(pageInstance.parent.path); }
We note also that we manually run the validation to print an error message on the parent "post" page.
With this last step we achieved the desired goal. And, finally, we have a fully functional blog with an attractive layout.
In the next tutorial we will conclude the series, we will create an rss feeds for our blog.