Programando contenidos en Liferay 6
<h1>¿Qué es un contenido?</h1>
<p>Un contenido será cualquier entidad que podemos <strong>etiquetar o categorizar</strong>. Liferay los identifica con el término <strong>asset</strong> y proporciona un <strong>framework</strong> para su gestión. Los <strong>tipos de contenido</strong> que Liferay maneja por defecto son:</p>
<ul>
<li>Contenidos web (Web Content).</li>
<li>Imágenes de la galería de Imágenes (Image Gallery Image).</li>
<li>Entradas de blog (Blog Entry).</li>
<li>Documentos de la biblioteca de documentos (Document Library Document).</li>
<li>Marcador (Bookmark).</li>
<li>Mensaje en un foro (Message Board message).</li>
<li>Página en una Wiki (Wiki page).</li>
<li>Evento de calendario (Calendar Event).</li>
</ul>
<h1>La API para manejar Assets</h1>
<p>Para trabajar con asset se debe manejar dos conceptos, su <strong>modelo</strong> y su <strong>servicio</strong> asociados.</p>
<p>La interface <strong>AssetEntry</strong> representa el concepto de asset y su tabla asociada en la base de datos de Liferay se llama <strong>assetentry</strong>. Sus campos más importantes son:</p>
<ul>
<li><strong>entryId</strong>: identificador único del asset.</li>
<li><strong>userId</strong>: identificador del usuario que crea el contenido.</li>
<li><strong>groupId</strong>: identifica el alcance en el que ha sido creado.</li>
<li><strong>classNameId</strong>: identifica el tipo de contenido. Es el identificador de la clase asociado al contenido, se encuentra representado mediante la entidad <strong>ClassName</strong> y la tabla <strong>classna</strong><strong>me_</strong>.</li>
</ul>
<ul>
<li><strong>classPK</strong>: identifica el contenido específico asociado al asset. Suele ser la <strong>clave primaria</strong> de la tabla donde se almacena el contenido.</li>
</ul>
<p>El concepto <strong>asset</strong> se encuentra estrechamente relacionado con el concepto de <strong>categoría</strong> y <strong>etiqueta</strong>. Efectivamente, en la base de datos de Liferay se encuentran dos tablas que definen esa relación:</p>
<ul>
<li>assetentries_assetcategories.</li>
<li>assetentries_assettags.</li>
</ul>
<p>La clase <strong>AssetEntryLocalServiceUtil</strong> proporciona los métodos que nos permitirán manejar estos contenidos, recuperándolos, editándolos, etc.</p>
<p>El ejemplo que se muestra a continuación ilustra lo anteriormente comentado:</p>
<pre>
int total =
AssetEntryLocalServiceUtil.<strong>getAssetEntriesCount</strong>();
List <AssetEntry> contenidos = AssetEntryLocalServiceUtil.<strong>getAssetEntries</strong>(0,total);
for(int i=0;i<contenidos.size();i++){
<strong>AssetEntry</strong> c = contenidos.get(i);
...
}
</pre>
<p>Una vez definidos <strong>AssetEntry y de AssetEntryLocalServiceUtil</strong>, se pasa a describir uno de los tipos de contenidos más utilizados, los <strong>contenidos web</strong>.</p>
<h1>Contenidos web</h1>
<h2>Introducción</h2>
<p>Los <strong>contenidos web</strong> en Liferay son manejados mediante un conjunto de servicios y modelos y son almacenados en la base de datos en la tabla <strong>journalarticle</strong>. Sus campos más significativos son:</p>
<ul>
<li>Identificador del contenido: <strong>articleId</strong>.</li>
<li>Título: <strong>title</strong>.</li>
<li>Descripción: <strong>description</strong>.</li>
<li>Identificador de la estructura asociada al contenido: <strong>structureId</strong>.</li>
<li>Identificador de la plantilla asociada al contenido: <strong>templateId</strong>.</li>
<li>Identificador de grupo: <strong>groupId</strong>.</li>
<li>Identificador de usuario: <strong>userId</strong>.</li>
<li>Información del contenido: <strong>content</strong>.</li>
</ul>
<p>Un contenido web en Liferay es un objeto que implementa la interface <strong>JournalArticle</strong> que se encuentra en el paquete com.liferay.portlet.journal.model:</p>
<p class="rtecenter"><img width="634" height="222" alt="" src="/userfiles/2(4).jpg" /></p>
<p>Son manejados mediante la clase <strong>JournalArticleLocalServiceUtil</strong>.</p>
<pre>
List<<strong>JournalArticle</strong>> lista = <strong>JournalArticleLocalServiceUtil</strong>.getArticles(scopeGroupId);
for(int i=0;i<lista.size();i++){
JournalArticle journalArticle = lista.get(i);
...
</pre>
<p>Esta clase proporciona métodos para recuperar, actualizar, borrar y buscar contenidos web, de la misma forma en la que lo hacen todos los servicios de Liferay. A continuación, pasamos a describir alguna de las operaciones más habituales.</p>
<h2>Mostrando contenidos</h2>
<p class="rteindent1">¿La entidad <strong>JournalArticle</strong> tiene acceso a la información del contenido web? ¿El método <strong>getContent</strong>() me permite recuperar el contenido del contenido web? ¿Esto tiene que ver con <strong>estructuras</strong> y <strong>plantillas</strong>?</p>
<p>Vamos a intentar aclarar estas preguntas a continuación.</p>
<h3>Trabajando con plantillas y estructuras</h3>
<p>Cuando se crea un contenido web con una <strong>estructura</strong> y una <strong>plantilla específicas,</strong> el proceso para mostrar el contenido web es algo diferente. <br />
El método <strong>getContent() </strong>de la interface JournalArticle <strong>NO</strong> es válido.<br />
Para mostrar el contenido generado como resultado de la aplicación de una estructura y una plantilla específicas aparece la entidad <strong>JournalArticleDisplay</strong>.</p>
<p>La interface <strong>JournalArticleDisplay</strong> y su método <strong>getContent()</strong> muestra el contenido web <strong>tras la aplicación</strong> de su estructura y plantilla asociada.</p>
<h1 class="rtecenter"><img width="470" height="221" src="/userfiles/6(1).jpg" alt="" /></h1>
<p>Por ejemplo:</p>
<pre>
// Paso 1: Se recuperan todos los contenidos web
// que se encuentran en la comunidad donde se ha
// desplegado el portlet.
List<JournalArticle> lista = JournalArticleLocalServiceUtil.getArticles(scopeGroupId);
for(int i=0;i<lista.size();i++){
// Paso 2: Se recupera el articulo que se desea
// mostrar.
JournalArticle journalArticle = lista.get(i);
// Paso 3: Se recupera el idioma utilizado.
String languageId =
LanguageUtil.getLanguageId(request);
// Paso 4: Se recupera el objeto JournalArticleDisplay
JournalArticleDisplay articleDisplay =
JournalArticleLocalServiceUtil.getArticleDisplay(
journalArticle,
null,
null,
languageId, 1, null, themeDisplay);
</pre>
<p>Una vez recuperado el objeto de tipo JournalArticleDisplay asociado a un determinado artículo, se podrá mostrar en cualquier página, tal que así:</p>
<pre>
...
<div>
<%= articleDisplay.getContent() %>
</div>
...
</pre>
<h2>Extracción de campos específicos</h2>
<p class="rteindent1">¿Cómo se pueden recuperar <strong>campos específicos</strong> de un contenido web para procesarlos de forma independiente?</p>
<p class="rteindent1"><br />
¿JournalArticle o JournalArticleDisplay?</p>
<p>Como se ha visto en el ejemplo anterior, la información asociada a un contenido web puede recuperarse a través del objeto de tipo JournalArticleDisplay, pero cuando necesito manejar parte de la información almacenada en el contenido, ¿qué puedo hacer? A continuación, se muestra una solución a este problema:</p>
<pre>
/*
* En este ejemplo se supone que el contenido
* esta asociado a una <strong>plantilla</strong> o <strong>estructura</strong> con un
* campo llamado title.
*/
String contenidoArticulo = journalArticle.
getContentByLocale(themeDisplay.getLanguageId());
Document documento = null;
String title=null;
String summary = null;
try{
documento = SAXReaderUtil.read(
new StringReader(contenidoArticulo));
Node node1 = documento.selectSingleNode(
<strong>"/root/dynamic-element[@name='title']/dynamic- content");</strong>
if (node1!=null && node1.getText().length() > 0) {
title = node1.getText();
}
...
</pre>
<h2>¿Para qué trabajar con Assets?</h2>
<p>Cuando trabajamos con <strong>contenidos web</strong>, ¿necesitamos incorporar el concepto <strong>Asset</strong> en algún momento? ¿Por qué existe esta entidad? Debe haber alguna razón. La respuesta es clara: <strong>categorías</strong> y <strong>etiquetas</strong>.<br />
Es <strong>IMPORTANTE</strong> tener claro que la gestión de assets nos permite relacionar cualquier tipo de contenido con <strong>categorías</strong> y <strong>etiquetas</strong>, de cualquier otra forma sería imposible.</p>
<h2>Gestión de assets</h2>
<p>Para manejar assets se trabaja con las clases utility <strong>AssetEntryLocalServiceUtil</strong> y <strong>AssetEntryServiceUtil</strong>. Nos proporcionan los métodos habituales para manejar este tipo de entidades: add, create, delete, update, get, ...<br />
Los procesos de búsqueda pueden llevarse a cabo de forma específica mediante el método <strong>getEntries</strong>:</p>
<pre>
public static List<AssetEntry>
<strong>getEntries</strong>(<strong>AssetEntryQuery</strong> entryQuery)
throws SystemException
</pre>
<p>Por ejemplo:</p>
<pre>
int total = AssetEntryLocalServiceUtil.getAssetEntriesCount();
List <AssetEntry> contenidos = AssetEntryLocalServiceUtil.getAssetEntries(0,total); for(int i=0;i<contenidos.size();i++){
AssetEntry c = contenidos.get(i);
}
</pre>
<h2>Consultas sobre Assets</h2>
<p>El método <strong>getEntries</strong> asociado al servicio <strong>AssetEntryLocalServiceUtil</strong> es de vital importancia a la hora de llevar a cabo consultas:</p>
<pre>
public static List<AssetEntry>
getEntries(AssetEntryQuery entryQuery)
throws SystemException
</pre>
<p>Recibe como parámetro una consulta y devuelve como valor de retorno una lista de contenido que cumple dicha consulta. Ahora bien, ¿cómo se construye ésta?</p>
<p>La clase <strong>AssetEntryQuery</strong> nos permite realizar consultas avanzadas sobre los diferentes assets almacenados en la instalación. Los métodos <strong>set</strong> nos permiten definir los <strong>criterios de búsqueda</strong>, por ejemplo:</p>
<ul>
<li>public void <strong>setGroupIds</strong>(long[] groupIds): comunidades donde se han creado los contenidos.</li>
<li>public void <strong>setClassName</strong>(String className): tipo de contenido.</li>
<li>public void <strong>setAllCategoryIds</strong>(long[] allCategoryIds): contenidos con las siguientes categorías.</li>
<li>public void <strong>setAllTagIds</strong>(long[] allTagIds): contenidos con todas las etiquetas.</li>
<li>...</li>
</ul>
<p>Para ilustrar esta funcionalidad, se muestra a continuación el siguiente trozo de código:</p>
<pre>
...
// Paso 1: Se construye la consulta gracias a la clase // AssetEntryQuery.
AssetEntryQuery <strong>consulta</strong> = new AssetEntryQuery();
// Paso 2: Se inicializa la consulta.
// Paso 2.1: Comunidades donde se quiere realizar la // busqueda.
// Nota: idsComunidades es un array de tipo long
// que ha sido creado previamente con los identificadores
// de cada comunidad
consulta.setGroupIds(idsComunidades);
// Paso 2.2: Rango de documentos.
consulta.setStart(0);
consulta.setEnd(numNoticias);
// Paso 2.3: Tipo de contenido que se quiere modificar: // Contenido web.
// Se obtiene el <strong>identificador unico</strong> del className
// asociado al tipo contenido web.
ClassName nombre = ClassNameLocalServiceUtil.
getClassName(
"com.liferay.portlet.journal.model.JournalArticle");
long classNameIdJournal = nombre.getClassNameId();
long[] tipos = {classNameIdJournal};
// El metodo setClassNameIds nos permite indicar los
// tipos de contenidos que quiere manejar.
consulta.setClassNameIds(tipos);
// Paso 2.4: <strong>Categorias asocidas</strong> a los contenidos web // que se quieren recuperar
// Nota: categoryIds es un array de tipo long creado
// previamente donde se almacenan los ids de las
// categorias a partir de las cuales se realiza
// la busqueda.
consulta.setAllCategoryIds(categoryIds);
// Paso 3: Una vez creada la query, gracias al metodo
// getEntries se ejecuta la consulta de busqueda.
List<AssetEntry> resultados =
AssetEntryLocalServiceUtil.getEntries(consulta);
</pre>
<h1>AssetEntry vs JournalArticle</h1>
<p>Una vez que se recuperan los assets asociados a una consulta ...<br />
¿Cómo recupero los contenidos web asociados?</p>
<p class="rtecenter"><img width="141" height="184" src="/userfiles/7(1).jpg" alt="" /></p>
<p>La relacion entre <strong>JournalArticle</strong> y <strong>AssetEntry</strong> se define mediante una entidad llamada <strong>JournalArticleResource</strong>:</p>
<p><img width="579" height="173" src="/userfiles/8(1).jpg" alt="" /></p>
<p>La entidad <strong>AssetEntry</strong> tiene un campo llamado classPK. Este campo permite relacionar ambas entidades mediante el método <strong>getArticleResource</strong><strong>()</strong></p>
<pre>
...
AssetEntry e = ...;
JournalArticleResource recurso = JournalArticleResourceLocalServiceUtil.
getArticleResource(e.getClassPK());
JournalArticle articulo =
JournalArticleLocalServiceUtil.getArticle(
e.getGroupId(), recurso.getArticleId());
</pre>
<h1>Conclusión</h1>
<p>Si el programador es capaz de manejar los conceptos tratados en este artículo, no tendrá ningún problema a la hora de <strong>extender los portlets del core Liferay</strong> que se encargan de manejar contenidos, por ejemplo:</p>
<ul>
<li>Asset Publisher.</li>
<li>Display Content.</li>
<li>...</li>
</ul>
<p>Lógicamente, también podrá crear nuevos portlets que trabajen con cualquier tipo de contenido.</p>

>
>
Comentarios recientes
hace 33 semanas 4 días
hace 35 semanas 4 días
hace 36 semanas 3 días
hace 39 semanas 4 días
hace 49 semanas 6 días
hace 51 semanas 4 días
hace 1 año 29 semanas
hace 1 año 36 semanas
hace 1 año 41 semanas
hace 2 años 1 semana