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.

https://jesuslc.com/2013/05/07/utilizando-spring-para-desarrollar-un-portlet-para-liferay-con-base-de-datos-service-builde

https://jesuslc.com/2013/05/14/service-builder-para-desarrollar-un-portlet-con-gestion-de-base-de-datos-parte-23

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'}">
                                        &or;
                                  </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'}">
                                        &or;
                                  </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'}">
                                        &or;
                                  </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>              &nbsp;        </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>                   &nbsp;&nbsp;&nbsp;&nbsp;              <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>              &nbsp;        </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>                          &nbsp;&nbsp;&nbsp;&nbsp;              <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.

14 respuestas a «Service Builder para desarrollar un portlet con gestión de base de datos Parte 3/3»

  1. Avatar de Daniel

    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 gusta

    1. Avatar de jesuslc

      Quizás no me expliqué bien, los jsp están pegados en el post.

      Me gusta

      1. Avatar de Daniel

        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 gusta

  2. Avatar de danika

    Hola sigues hay todavía seguimos esperando de tus instrucciones.. que gracias

    Me gusta

    1. Avatar de jesuslc

      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 gusta

      1. Avatar de David
        David

        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 gusta

  3. Avatar de Daniel

    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 gusta

    1. Avatar de jesuslc

      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 gusta

      1. Avatar de Daniel Camilo Correa

        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 gusta

  4. Avatar de Daniel Camilo Correa

    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 gusta

    1. Avatar de Mauro
      Mauro

      Hola Daniel quisiera pedirte un favor y es saber que librerías utilizaste… muchas gracias

      Me gusta

      1. Avatar de Daniel Camilo
        Daniel Camilo

        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 gusta

  5. Avatar de Pau

    Muchas gracias por el post, me ha servido mucho! 🙂

    Me tomo el lujo de cojer ideas de tu GitHub! 😛

    Me gusta

  6. Avatar de juanky
    juanky

    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 gusta

Replica a Daniel Camilo Correa Cancelar la respuesta

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.

Jesús López

Soy un Ingeniero en Informática y apasionado de la programación. Me gusta disfrutar de mi familia, viajar y perdernos paseando.  Me mola programar, hacer tests y refactorizar código . Practico Test Driven Development (TDD) y me lo paso bien con el legacy codeLeer más

Sígueme en: