Ya estamos terminando nuestro portlet para Liferay que nos ayudará a aprender y gestionar tareas Por si no recordáis o acabáis de llegar a este post aquí os dejo un par de links a la parte 1 y a la parte 2 respectivamente.
Vamos a poner de nuevo como quedará el portlet porque hoy viene una de las partes más importantes, la vista:
Llegados aquí ya tenemos el Service Builder montado, si recordáis con solo definir un par de entidades con sus columnas correspondientes en el archivo services.xml y pulsar sobre la tarea (ant) “build Services” creamos un montón de código que nos sirve para mapear la base de datos. En el anterior post vimos cómo crear los controladores, en este ya tenemos el final. Vamos a definir 5 archivos JSP donde programaremos todos los elementos gráficos.
Creando el init
Así que lo primero para tener bien organizado el código será crear una carpeta llamada “JSP” (imaginación al poder) en docroot.
En Este nuevo directorio “/docroot/jsp” creamos el primer archivo llamado init.jsp Este primer archivo no tiene nada de vista, solo todas las importaciones de taglib, lo hacemos así para no repetir el mismo código de importaciones en todas las clases. También hemos definido 3 variables que nos ayudaran a no repetir código.
Brown-tsk-portlet/docroot/jsp/init.jsp
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x" %>
<%@ page import="com.liferay.portal.kernel.util.StringUtil" %>
<%@ page import="com.liferay.portal.security.permission.PermissionChecker" %>
<portlet:defineObjects />
<liferay-theme:defineObjects />
<%
long groupId = themeDisplay.getPortletGroupId();
String name = themeDisplay.getPortletDisplay().getRootPortletId();
String primKey = themeDisplay.getPortletDisplay().getResourcePK();
%>
Vamos a por el archivo principal, llamado view.jsp
La vista general
Si nos fijamos en la figura de arriba tenemos botones (addlist y additem), justo debajo la barra de pestañas (tabs) con cada una de las listas con una señalada por defecto SIEMPRE y debajo las tareas de esa lista. Pues todo ello puede resumirse en este archivo:
<%@ include file="init.jsp" %> <portlet:renderURL var='urlAddList'><portlet:param name='action' value='addList'/><portlet:param name='order' value='${order}'/><portlet:param name='list' value='${list}'/></portlet:renderURL> <portlet:renderURL var='urlEditList'><portlet:param name='action' value='addList'/><portlet:param name='order' value='${order}'/><portlet:param name='list' value='${list}'/><portlet:param name='id' value='${list}'/></portlet:renderURL> <portlet:renderURL var='urlAddItem'><portlet:param name='action' value='addItem'/><portlet:param name='order' value='${order}'/><portlet:param name='list' value='${list}'/></portlet:renderURL> <portlet:renderURL var='def'><portlet:param name='action' value='view'/></portlet:renderURL> <p> <aui:button name='addList' value='add-list' onclick='<%=renderResponse.getNamespace()+"toAddList()" %>' /> <c:if test="${list!=null}"> <aui:button name='addItem' value='add-item' onclick='<%=renderResponse.getNamespace()+"toAddItem()" %>' /> </c:if> </p> <liferay-ui:tabs names="${formNames}" value="${formTab}" url='<%=def %>' refresh="<%= true %>" /> <p style='text-align: right;'> <c:if test="${list!=null}"> <liferay-ui:icon cssClass="top-link" image="edit" label="<%= true %>" message="editlist" url='${urlEditList}' /> </c:if> </p> <aui:script> function <%=renderResponse.getNamespace() %>toAddList() { window.location.href='<%=urlAddList %>'; } function <%=renderResponse.getNamespace() %>toAddItem() { window.location.href='<%=urlAddItem %>'; } </aui:script> <table style='width: 100%;'> <tr class="portlet-section-header results-header"> <td> <b> <a style='text-decoration: none;' href='<portlet:renderURL> <portlet:param name='action' value='view'/> <portlet:param name='list' value='${list}'/> <portlet:param name='order' value='label'/> </portlet:renderURL>'> <liferay-ui:message key="label" /> <c:if test="${order=='label'}"> ∨ </c:if> </a> </b> </td> <td> <b> <a style='text-decoration: none;' href='<portlet:renderURL> <portlet:param name='action' value='view'/> <portlet:param name='list' value='${list}'/> <portlet:param name='order' value='weight'/> </portlet:renderURL>'> <liferay-ui:message key="weight" /> <c:if test="${order=='weight'}"> ∨ </c:if> </a> </b> </td> <td> <b> <a style='text-decoration: none;' href='<portlet:renderURL> <portlet:param name='action' value='view'/> <portlet:param name='list' value='${list}'/> <portlet:param name='order' value='status'/> </portlet:renderURL>'> <liferay-ui:message key="status" /> <c:if test="${order=='status'}"> ∨ </c:if> </a> </b> </td> </tr> <c:forEach var="item" items="${itemList}"> <portlet:renderURL var='urlViewItem'> <portlet:param name='list' value='${list}'/> <portlet:param name='itemid' value='${item.id}'/> <portlet:param name='order' value='${order}'/> </portlet:renderURL> <tr> <td> <aui:a href='${urlViewItem}'> ${item.label} </aui:a> </td> <td> <c:choose> <c:when test="${item.weight>=16}"> <spanclass='weight_highest'> </c:when> <c:when test="${item.weight>=4}"> <spanclass='weight_high'> </c:when> <c:when test="${item.weight>=-4}"> <spanclass='weight_normal'> </c:when> <c:when test="${item.weight>=-14}"> <spanclass='weight_low'> </c:when> <c:otherwise> <spanclass='weight_lowest'> </c:otherwise> </c:choose> ${item.weight}</span> </td> <td> <c:choose> <c:when test="${item.status==0}"> <span class='status_normal'><liferay-ui:message key="normal" /></span> </c:when> <c:when test="${item.status==1}"> <span class='status_waiting'><liferay-ui:message key="waiting" /></span> </c:when> <c:when test="${item.status==2}"> <span class='status_cancelled'><liferay-ui:message key="cancelled" /></span> </c:when> <c:when test="${item.status==3}"> <span class='status_finished'><liferay-ui:message key="finished" /></span> </c:when> <c:otherwise> ${item.status} </c:otherwise> </c:choose> </td> </tr> </c:forEach> </table>
Si veis al principio del archivo tenemos un include para evitar realizar allí todas las importaciones que realizamos en init.jsp
Viendo solo un ítem
SI hacemos clic encima de una tarea podemos ver con más detalle dicha tarea, más o menos veremos algo así:
El código que genera esta vista es algo así:
<%@ include file="init.jsp" %> <portlet:renderURL var='urlCancel'><portlet:param name='action' value='view'/><portlet:param name='order' value='${order}'/><portlet:param name='list' value='${list}'/></portlet:renderURL> <liferay-ui:header title="${listObj.description} - ${item.label}" backURL="${urlCancel}" />4px;" > 'urlEditItem'> 'action' value='addItem'/> 'list' value='${list}'/> 'itemid' value='${item.id}'/> 'order' value='${order}'/> "top-link" image="edit" label="" message="edit" url='${urlEditItem}' /><aui:field-wrapper label="description"> <% pageContext.setAttribute("newLineChar", "\n"); %> ${fn:replace(item.description,newLineChar,"<br/>")} </aui:field-wrapper>left; margin-right: 4px;" > "label"> '${item.label}' />left; margin-right: 4px;" > "status"> "${statuses[ item.status ]=='Normal'}"> 'status_normal'>"normal" /> "${statuses[ item.status ]=='Waiting for'}"> 'status_waiting'>"waiting" /> "${statuses[ item.status ]=='Cancelled'}"> 'status_cancelled'>"cancelled" /> "${statuses[ item.status ]=='Finished'}"> 'status_finished'>"finished" />both; overflow: hidden; height: 1px;" >
Añadiendo una lista de tareas
Cuando pulsamos desde la pantalla principal de nuestro portlet de gestión de tareas el botón de añadir una lista de tareas no aparece algo como esto:
Como veis tenemos una caja donde añadir el nombre de la lista de tarea y un peso que nos servirá para ordenar las listas en la barra de pestañas.
<%@ include file="init.jsp" %> <portlet:actionURL var='actionAddList'><portlet:param name='action' value='addList'/><portlet:param name='order' value='${order}'/></portlet:actionURL> <portlet:renderURL var='urlCancel'><portlet:param name='action' value='view'/><portlet:param name='order' value='${order}'/><portlet:param name='list' value='${list}'/></portlet:renderURL> <portlet:actionURL var='actionDeleteList'> <portlet:param name='action' value='addList'/> <portlet:param name='delete' value='1'/> <portlet:param name='id' value='${item.id}'/> <portlet:param name='order' value='${order}'/> </portlet:actionURL> <liferay-ui:header title="list-title" backURL="${urlCancel}" /> <form method="post" action="<%= actionAddList %>" onSubmit = "<%= "javascript: return "+renderResponse.getNamespace()+"validate(this);" %>" >left; margin-right: 4px; height: 43px;" > 'text' name='description' label="list-name" value='${item.description}' />left; margin-right: 4px; height: 43px;" > "weight" name="weight"> "${item.weight}" var="sval"/> "${item.id==null}"> "0" var="sval"/> "i" begin="0" end="10"> "${i-5}" selected="${sval==i-5}">${i-5}both; overflow: hidden; height: 1px;" ><p> </p> <p> <c:if test="${item.id!=null}"> <aui:input type='hidden' name='id' value='${item.id}' /> <input type='submit' value='<liferay-ui:message key="save" />'/> <input type='button' onclick='<%=renderResponse.getNamespace()+"toDelete();" %>' value='<liferay-ui:message key="action.DELETE" />'/> </c:if> <c:if test="${item.id==null}"> <aui:input type='hidden' name='id' value='-1' /> <input type='submit' value='<liferay-ui:message key="add" />'/> </c:if> <input type='button' onclick="javascript: window.location.href='${urlCancel}';" value='<liferay-ui:message key="cancel" />'/> </p> </form> <aui:script use="aui-node"> <portlet:namespace />validate=function() { if ( AUI().one("#<portlet:namespace />description").val().trim()=="" ) { alert( '<liferay-ui:message key="this-field-is-mandatory" />' ); AUI().one("#<portlet:namespace />description").focus(); return false; } return true; } <portlet:namespace />toDelete=function() { if ( confirm("<liferay-ui:message key="attention-delete" />") ) window.location.href='${actionDeleteList}'; } </aui:script>
Añadiendo una nueva tarea
Cuando queremos añadir una nueva tarea tenemos algo como esto:
El código lo tenemos aquí:
<%@ include file="init.jsp" %> <portlet:actionURL var='actionAddItem'> <portlet:param name='order' value='${order}'/> <portlet:param name='action' value='addItem'/> </portlet:actionURL> <portlet:actionURL var='actionDeleteItem'> <portlet:param name='action' value='addItem'/> <portlet:param name='delete' value='1'/> <portlet:param name='id' value='${item.id}'/> <portlet:param name='list' value='${list}'/> <portlet:param name='order' value='${order}'/> </portlet:actionURL> <portlet:renderURL var='urlCancel'> <portlet:param name='order' value='${order}'/> <portlet:param name='action' value='view'/> <portlet:param name='list' value='${list}'/> </portlet:renderURL> <liferay-ui:header title="item-title" backURL="${urlCancel}" /> <form method="post" action="<%= actionAddItem %>" onSubmit = "<%= "javascript: return "+renderResponse.getNamespace()+"validate(this);" %>" > <aui:input type='hidden' name='list' value='${list}' />left; margin-right: 4px;" > 'text' name='label' label="label" value='${item.label}' />left; margin-right: 4px;" > "weight" name="weight" style="float: left;"> "${item.weight}" var="sval"/> "${item.id==null}"> "0" var="sval"/> "i" begin="0" end="10"> "${i-5}" selected="${sval==i-5}">${i-5}left; margin-right: 4px;" > "status" name="status" style="float: left;"> "0" label="normal" selected="${item.status==0}" /> "1" label="waiting" selected="${item.status==1}" /> "2" label="cancelled" selected="${item.status==2}" /> "3" label="finished" selected="${item.status==3}" />both; overflow: hidden; height: 1px;" ><aui:input type='textarea' name='description' label="item-description" value='${item.description}' style="width: 100%;" /> <p> </p> <p> <c:if test="${item.id!=null}"> <aui:input type='hidden' name='id' value='${item.id}' /> <input type='submit' value="<liferay-ui:message key='save' />"/> <input type='button' onclick='<%=renderResponse.getNamespace()+"toDelete();" %>' value='<liferay-ui:message key="action.DELETE" />'/> </c:if> <c:if test="${item.id==null}"> <aui:input type='hidden' name='id' value='-1' /> <input type='submit' value='<liferay-ui:message key="add" />'/> </c:if> <input type='button' onclick="javascript: window.location.href='${urlCancel}';" value='<liferay-ui:message key="cancel" />'/> </p> </form> <aui:script> <portlet:namespace />validate=function() { if ( AUI().one("#<portlet:namespace />label").val().trim()=="" ) { alert( '<liferay-ui:message key="this-field-is-mandatory" />' ); AUI().one("#<portlet:namespace />label").focus(); return false; } return true; } <portlet:namespace />toDelete=function() { if ( confirm("<liferay-ui:message key="attention-delete" />") ) window.location.href='<%=actionDeleteItem %>'; } </aui:script>
Ya hemos como crear la vista, para tener un portlet totalmente funcional deberemos poder probarlo y para ello es necesario configurarlo.
Configurando el portlet
Por ultimo solo nos queda configurar un poco los parámetros del portlet para que eche a andar.
Modificamos la categoría
Para que a la hora de añadir el portlet podamos encontrarlo fácilmente vamos a definirle una categoría propia de la siguiente manera.
Abrimos el archivo Liferay-display.xml y modificamos la categoría, yo le he puesto como categoría “Demos JesusLC SB”
Modificando el Controller
Para que el portlet de gestión de tareas funcione, debemos indicarle cual es nuestra clase controladora, la que implementa a MVCPortlet, si os acordáis del post anterior creamos una clase llamada BalancerController, pues en el archivo portlet.xml debemos poner la ruta de esa clase, además de indicar que tenemos un archivo llamado Language.properties donde está definido el idioma del portlet.
Debe quedar todo como esta figura:
Finalmente ya hemos terminado con este Portet, solo tenemos pulsar sobre build.xml y correr la tarea ant para que se añada al servidor y empezar a utilizarlo.
oye amigo tengo un problema nos has dicho a vosotros que la vista es lo mas importante y os hemos quedado esperando por los nombres de los archivos jsp que se deben utilizar te agradezco nos dichas con mas detalle como construir la vista thanks
Me gustaMe gusta
Quizás no me expliqué bien, los jsp están pegados en el post.
Me gustaMe gusta
Hola de nuevo jesuslc lo que sucede es que no se bien que nombre colocar a los jsp solo he visto que existe un ini.jsp con los taglib y un view.jsp que me crea el porlet pero los demas jsp donde van puestos y con que nombre gracias
Me gustaMe gusta
Hola sigues hay todavía seguimos esperando de tus instrucciones.. que gracias
Me gustaMe gusta
Danika siento el retraso, he estado muy liado con temas personales.
Si te sirve de ayuda, en mi cuenta de github están subidos los ejemplos del blog.
https://github.com/jeslopcru/PortletsDemos
Un saludo.
Me gustaMe gusta
Es un ejemplo muy ilustrativo para trabajar con los servicios y BD en liferay.
Sólo una cosa, faltan los css en la aplicación brown-tasks.
Un saludo.
Me gustaMe gusta
Gracias jesuslc los voy a estudiar bien yo te quería pedir un consejo.. lo que sucede es que yo soy nuevo en liferay y en java sigo siendo novato llevo como dos años desarrollando pequeñas aplicaciones pero me gusta esto y me gustaría saber cual es la mejor manera de aprender a desarrollar en liferay ya que tengo un sin fin de manuales de administración y desarrollo de portales en liferay pero estos se encargan de explicarte lo que liferay puede hacer hacer pero hay muy poco ejemplos al respecto te agradezco la comprensión y esperare tu mejor consejo gracias.
Me gustaMe gusta
Yo para empezar a desarrollar te recomendaría alguno de los libros que hay para desarrollar Liferay. Si entras en la sección libros recomiendo un par de ellos.
Y lo importantes no desesperes, porque hay veces que un fallo tonto te hace perder toda una tarde, pero después cuando ves la aplicación terminada te alegras y se te olvidan esos inconvenientes.
Me gustaMe gusta
Muchas gracias he empezado el libro portlets en acción esta re bien 🙂 quería hacerte una pregunta Jesus respecto a los jsp que usas, muchos tienen etiquetas un poco diferentes como:
, , si no estoy mal estas etiquetas son las utilizadas en la especificación java server faces sin embargo tienen la extension .jsp me podrias explicar un poco esta modalidad muchas gracias
Me gustaMe gusta
Hola jesus exelente tutorial he aprendido muchas cosas para crear service builder, al principio tuve muchos inconvenientes con algunas librerías pero ahora tengo mi portlet funcionando muchas gracias por compartir tu conocimiento…
ahora voy a empezar a construir service builder personalizados con funcionalidades diferentes gracias
Me gustaMe gusta
Hola Daniel quisiera pedirte un favor y es saber que librerías utilizaste… muchas gracias
Me gustaMe gusta
Mauro disculpa deje de trabajr cone sta tecnologia es por esto que deje de eprender liferay, las librerias que usen para crear este portlet son las misma que viene integradas con liferay
Me gustaMe gusta
Muchas gracias por el post, me ha servido mucho! 🙂
Me tomo el lujo de cojer ideas de tu GitHub! 😛
Me gustaMe gusta
Hola Jesus, una pregunta estoy modificando un portlet pero deseo agregar unos atributos extras en una tabla desde el service.xml, pero no consigo como actualizar las clases del service builder sin generar todo el codigo nuevo con «Build Services», al realizar esto pierdo varios metodos que hizo la persona que construyo el portlet
Me gustaMe gusta