Ejemplo de aplicación web con Hibernate que funciona usando Netbeans IDE y JSTL (JSP(X))

4.12.09. Por ooscarr (ooscarr)

Al final de este tutorial conocerás la dinámica del desarrollo de una aplicación web manejando la persistencia de la base de datos con Hibernate y cómo NetBeans IDE te ayuda a escribir el código y consultar la base de datos. También escribirás una aplicación web JSP que haga consultas a esta base de datos a través usando XML.

Este ejemplo de Hibernate es famoso, está documentado en varias páginas, pero todas tienen el código malo y es frustrante aprender así. Así que lo corregí y lo traduje al español sacando cosas de uno y de otro mismo tutorial que encontré en ¡chino, portugués, inglés y ruso!

Soporte para Hibernate en aplicaciones web está disponible desde NetBeans IDE 6.1. Desde NetBeans IDE 6.5, también puedes hacer ingeniería inversa a las tablas de una BD a archivos de mapeo y clases Java correspondientes usando un asistente intuitivo.

Pasos previos

Antes de empezar necesitarás:

  • Instalar NetBeans IDE. Al momento de escribir esto, anda dando vueltas la versión 6.8 RC2.
  • Instalar MySQL o Java DB, o tener acceso a conectarte a una de estas bases de datos con permiso para acceder o crear la base de datos Sakila. La base de datos Sakila está disponible en estos dos tipos de bases de datos, pero Hibernate funciona con cualquier JDBC, por ejemplo PostgreSQL y Oracle.
  • Importar la base de datos de ejemplo Sakila (a la que le haremos consultas en este ejemplo).

Una vez obtenido esto, asegúrate de configurar NetBeans IDE para poder acceder a la base de datos Sakila desde el panel "Prestaciones" (Menú Ventana > Prestaciones.

Instalar el complemento de Hibernate

El plug-in, si no lo tienes ya instalado, lo obtienes

  1. yendo, en el menú, a Herramientas > Complementos.
  2. En la ficha Plugins disponibles, selecciona la casilla del módulo Hibernate y presiona Instalar.

  3. Siguiente
  4. Acepta los términos de todos los contratos de licencia y presiona el botón de Instalar.
  5. Después que se descargue y se instale, presiona Terminar.
  6. Y listo, el módulo para Hibernate (o Hibernar) se activará solo; o sino, reinicia NetBeans IDE.

Crear Proyecto nuevo

Primero: lo típico. Creamos un Proyecto nuevo de tipo Aplicación web.

Asistente de Nuevo proyecto de NetBeans, bajo la categoría Web está la opción Aplicación web.

Para nuestro ejemplo, le damos el nombre DVDStore.

Elegimos un servidor como Tomcat o Glassfish, Siguiente y marcamos la opción Hibernate y seleccionamos la base de datos jdbc:mysql://localhost:3306/sakila, en nuestro caso, de la lista que, supongo, ya habías configurado anteriormente como indiqué en los pasos previos de este tutorial.

Asistente de Nuevo proyecto de NetBeans, después de marcar la casilla que habilita Hibernate 3.2.5 abajo selecciona la base de datos Sakila instalada en localhost.
Terminar

Fíjate que en:

  • DVDStore
    • Libraries

se agregaron automáticamente las librerías necesarias para utilizar Hibernate y conectar a la base de datos.

Configurar proyecto

hibernate.cfg.xml

Abre el archivo hibernate.cfg.xml que está en la ruta:

  • DVDStore
    • Source Packages
      • <paquete predeterminado>
        • hibernate.cfg.xml

Una vez abierto en NetBeans IDE, en el modo Diseño, en la parte Propiedades opcionales, Propiedades de configuración, pon Agregar... y añade la propiedad:

Nombre de la propiedad:hibernate.show_sql
Valor de la propiedad:true

Com el asistente de diseño de XML de configuración en NetBeans IDE se puede seleccionar los valores en una lista desplegable sin tocar el código XML.

Dentro de las mismas Propiedades opcionales del modo Diseño de NetBeans IDE, más abajo, en Propiedades varias, Agrega la propiedad:

Nombre de la propiedad:hibernate.current_session_context_class
Valor de la propiedad:thread

Después de esto, si ves el archivo hibernate.cfg.xml en el modo Operador XML, quedaría un código más o menos así, pero con otras contraseñas, por supuesto:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/sakila</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">######</property>
    <property name="hibernate.current_session_context_class">thread</property>
    <property name="hibernate.show_sql">true</property>
  </session-factory>
</hibernate-configuration>

Guarda los cambios del archivo.

Asistente de ingeniería inversa de Hibernate

Agreguemos un nuevo archivo, y seleccionemos Hibernar > Asistente de ingeniería inversa de Hibernate

Asistente para la creación de nuevo archivo en NetBeans IDE. El primer paso es seleccionar la categoría Hibernar y luego, en la columna derecha, Asistente de ingeniería inversa de Hibernate

En el siguiente paso dejamos los valores por defecto (asegurándonos que pertenezca al proyecto DVDStore). Siguiente.

Se cargarán automáticamente los nombres de las tablas de la base de datos Sakila (elegida cuando creamos el proyecto), y seleccionaremos las tablas:

  • actor
  • category
  • film
  • film_actor
  • film_category
  • language

Asistente de ingeniería inversa de Hibernate tiene 2 columnas: Tablas disponibles (con las tablas en la base de datos) y Tablas seleccionadas (con las tablas que se utilizarán en el proyecto)
Para pasar tablas de una columnas a la otra, existen los botones Agregar > y < Eliminar.

Si marcas la casilla Incluir tablas relacionadas algunas otras tablas se incluirán automáticamente. Eso está bien.

Al presionar Terminar se va a crear un archivo hibernate.reveng.xml parecido a este:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd">
<hibernate-reverse-engineering>
  <schema-selection match-catalog="sakila"/>
  <table-filter match-name="film"/>
  <table-filter match-name="language"/>
  <table-filter match-name="category"/>
  <table-filter match-name="actor"/>
  <table-filter match-name="film_category"/>
  <table-filter match-name="film_actor"/>
</hibernate-reverse-engineering>

No lo edites, cíerralo.

Archivos de mapas de Hibernate y POJOs de la base de datos

Crea un Archivo nuevo.... Categoría Hibernar, tipo Archivos de mapas de Hibernate y POJOs de la base de datos.

Asistente para la creación de nuevo archivo en NetBeans IDE. El primer paso es seleccionar la categoría Hibernar y luego, en la columna derecha, Archivos de mapas de Hibernate y POJOs de la base de datos.

Debes ponerle nombre a la clase donde estarán los mapas de Hibernate. Para que este tutorial funcione, ponle dvdrental

En el asistente de nuevo archivo de mapas de Hibernate y POJOs de la base de datos, en el paso de la Generación de código, debes seleccionar hibernate.cfg.xml como archivo de configuración de Hibernate e hibernate.reveng.xml como archivo de ingeniería inversa.

...y presiona el botón Terminar. Se deberían generar los siguientes archivos:

  • DVDStore
    • Source Packages
      • dvdrental
        • Actor.hbm.xml
        • Actor.java
        • Category.hbm.xml
        • Category.java
        • Film.hbm.xml
        • Film.java
        • FilmActor.hbm.xml
        • FilmActor.java
        • FilmActorId.java
        • FilmCategory.hbm.xml
        • FilmCategory.java
        • FilmCategoryId.java
        • Language.hbm.xml
        • Language.java

HibernateUtil.java

Lo último sería crear un Archivo Nuevo..., Categoría Hibernar, Tipo HibernateUtil.java.

Al crear el nuevo archivo HibernateUtil.java, en el asistente de nuevo archivo de NetBeans IDE, por favor fijarse en cambiar el nombre del archivo propuesto NewHibernateUtil por HibernateUtil sin el New y agregarlo al paquete dvdrental
Terminar

Empecemos

FilmHelper.java

Crea una nueva Clase Java (Archivo Nuevo..., Categoría Java, tipo Clase Java) y llámale FilmHelper y ponlo dentro del paquete dvdrental.

Creación de una nueva clase Java llamada FilmHelper en el paquete dvdrental utilizando NetBeans IDE 6.8 para Mac OS X.
Terminar

Agrega el siguiente código (en negrita) para crear una sesión de Hibernate.

package dvdrental;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }

}

Van a aparecer unos errores que se arreglan usando el menú contextual (botón secundario del ratón) y eligiendo la opción Reparar importaciones.

Menú contextual aparece cuando uno hace click sobre el código fuente.
La opción Reparar importaciones en inglés se llama Fix import.

Si dejamos el valor por defecto, quedaría el código de FilmHelper.java de la siguiente manera:

package dvdrental;

import org.hibernate.Session;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }
 
}

Consultas HQL

Probemos algo. Haz click con el botón secundario sobre el archivo Source Packages/<paquete predeterminado>/hibernate.cfg.xml y selecciona la opción Ejecutar la consulta HQL del menú contextual.

Opción Ejecutar la consulta HQL aparece en el menú contextual sólo cuando se hace click sobre el archivo hibernate.cfg.xml.

En la barra de herramientas del editor de consultas HQL, selecciona la Sesión: hibernate.cfg y escribe lo siguiente en la primera caja de texto grande:

from Film

Y presiona el botón que está al lado de la lista desplegable que debería estar mostrando hibernate.cfg como opción seleccionada para hacer la consulta y obtener un resultado como el siguiente.

El Editor de consultas HQL de NetBeans IDE tiene dos partes: arriba para escribir la consultas y abajo para mostrar los resultados o equivalente SQL.

Ahora prueba con una consulta un poquito más complicada:

from Film as film where film.filmId between 100 and 200

Con las consultas probadas, obteniendo los resultados esperados, podemos utilizarlas en la clase helper.

Hibernate

Edita el archivo FilmHelper.java y agrégale el siguiente método (marcado con negrita):

package dvdrental;

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }
 
  // Obtiene los films donde el id de film está entre un cierto rango especificado por las variables startID y endID

 public List getFilmTitles(int startID, int endID) {
  List<Film> filmList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
   filmList = (List<Film>) q.list();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return filmList;
 }
 
}

Repara las importaciones (Fix Import) si es necesario, utilizando las clases de hibernate.

Asistente para reparar importaciones en el código Java de NetBeans IDE. Instrucciones Import: Query org.hibernate.Query y List java.util.List.

para que quede completamente igual como está en el código de ejemplo anterior.

Vuelve a abrir el Editor de Consultas HQL y haz la siguiente query:

from Actor as actor where actor.actorId in (select filmActor.actor.actorId from FilmActor as filmActor where filmActor.film.filmId='10')

Esta consulta obtiene los actores de la película del filmid = 10.

Ahora súmale el siguiente método (marcado con negrita) al archivo FilmHelper.java:

package dvdrental;

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }

  // Obtiene los films donde el id de film está entre un cierto rango especificado por las variables startID y endID

 public List getFilmTitles(int startID, int endID) {
  List<Film> filmList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
   filmList = (List<Film>) q.list();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return filmList;
 }

 // Obtiene los actores en un film particular
 public List getActorsByID(int filmId) {
  List<Actor> actorList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Actor as actor where actor.actorId in (select filmActor.actor.actorId from FilmActor as filmActor where filmActor.film.filmId='" + filmId + "')");
   actorList = (List<Actor>) q.list();

  } catch (Exception e) {
   e.printStackTrace();
  }

  return actorList;
 }

}

Repara las importaciones si es necesario. Guarda.

Ahora agrega 3 métodos más y algunos métodos que inventé para hacer uso de beans en el código JSPX.


package dvdrental;

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }

 // Obtiene los films donde el id de film está entre un cierto rango especificado por las variables startID y endID
 public List getFilmTitles(int startID, int endID) {
  List<Film> filmList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
   filmList = (List<Film>) q.list();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return filmList;
 }

 // Obtiene los actores en un film particular
 public List getActorsByID(int filmId) {
  List<Actor> actorList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Actor as actor where actor.actorId in (select filmActor.actor.actorId from FilmActor as filmActor where filmActor.film.filmId='" + filmId + "')");
   actorList = (List<Actor>) q.list();

  } catch (Exception e) {
   e.printStackTrace();
  }

  return actorList;
 }

 // Obtiene una lista de categorías de acuerdo al filmId
 public Category getCategoryByID(int filmId) {
  List<Category> categoryList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Category as category where category.categoryId in (select filmCat.category.categoryId from FilmCategory as filmCat where filmCat.film.filmId='" + filmId + "')");
   categoryList = (List<Category>) q.list();

  } catch (Exception e) {
   e.printStackTrace();
  }

  return categoryList.get(0);
 }

 // Obtiene un solo film de acuerdo al filmId
 public Film getFilmByID(int filmId) {

  Film film = null;

  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Film as film where film.filmId=" + filmId);
   film = (Film) q.uniqueResult();
  } catch (Exception e) {
   e.printStackTrace();
  }

  return film;
 }


 // Obtiene el idioma del film de acuerdo a un langId
 public String getLangByID(int langId) {

  Language language = null;

  try{
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Language as lang where lang.languageId=" + langId);
   language = (Language) q.uniqueResult();
  } catch (Exception e) {
   e.printStackTrace();
  }

  return language.getName();
 }



 //Métodos para no poner código java en el JSPX
 int startId;
 int endId;

 int filmId;
 int langId;

 public void setAttributeStartID(int startId){
  this.startId = startId;
 }
 public void setAttributeEndID(int endId){
  this.endId = endId;
 }
 public List getFilmTitlesList(){
  return getFilmTitles(startId,endId);
 }
 public void setAttributeFilmByID(int filmId){
  this.filmId = filmId;
 }
 public List getActorsID() {
  return getActorsByID(filmId);
 }
 public Category getCategoryID() {
  return getCategoryByID(filmId);
 }
 public Film getFilmID() {
  return getFilmByID(filmId);
 }
 public void setAttributeLangByID(int langId){
  this.langId = langId;
 }
 public String getLangID() {
  return getLangByID(langId);
 }

}

JSP(X)

Hurra. Por fin llegamos a las páginas web. A mi me gusta escribir las JSP con JSTL así que antes de seguir deberás...

Instalar la librería JSTL

  1. Entra a las propiedades del proyecto (botón secundario del ratón sobre DVDStore, opción Propiedades).

  2. En la sección Libraries hay un botón Add Library.... Presiónalo.
  3. Si no te aparece inmediatamente, Importa la librería (o biblioteca también le llaman) JSTL 1.1 o superior.
  4. Selecciona la librería JSTL y añádela al proyecto.
  5. Aceptar

Nuevo archivo JSPX

Primero elimina el archivo index.jsp del proyecto que está en la carpeta DVDStore/Web Pages/ del proyecto.

Agrega un nuevo archivo JSPX y cambia la página por defecto.

En el archivo index.jspx escribe lo siguiente.

index.jspx
<?xml version="1.0" encoding="UTF-8"?>
<!-- 
    Document   : index
    Created on : 01-dic-2009, 21:43:16
    Author     : ooscarr
-->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
     xmlns:c="http://java.sun.com/jsp/jstl/core"
     xmlns:fn="http://java.sun.com/jsp/jstl/functions">

 <jsp:output
  omit-xml-declaration="no"
  doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
  doctype-root-element="html"/>

 <jsp:directive.page import="dvdrental.*"/>
 <jsp:directive.page import="java.util.List"/>

 <jsp:directive.page contentType="text/html" pageEncoding="UTF-8"/>

 <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
   <title>DVDStore</title>
  </head>
  <body>


   <c:set var="startID" value="1"/>
   <c:set var="endID" value="10"/>
   <c:set var="prev_startID" value="1"/>
   <c:set var="prev_endID" value="10"/>
   
   <c:set var="FILM_RECORD_COUNT" value="1000"/>
   
   <c:set var="RECORD_START_PAGE" value="false"/>
   <c:set var="RECORD_END_PAGE" value="false"/>


   <c:if test="${not empty param.startid}">
    <c:set var="startID" value="${param.startid}"/>
   </c:if>
   <c:if test="${not empty param.endid}">
    <c:set var="endID" value="${param.endid}"/>
   </c:if>

   <jsp:useBean id="helper" class="dvdrental.FilmHelper"/>
   <!-- Invento para pasar filmID a FilmHelper.java -->
   <c:set target="${helper}" property="attributeStartID" value="${startID}"/>
   <c:set target="${helper}" property="attributeEndID" value="${endID}"/>
   <c:set var="filmTitles" value="${helper.filmTitlesList}"/>

   <c:if test="${startID == 1}">
    <c:set var="RECORD_START_PAGE" value="true"/>
   </c:if>
   <c:if test="${endID == FILM_RECORD_COUNT}">
    <c:set var="RECORD_END_PAGE" value="true"/>
   </c:if>

   <c:set var="prev_startID" value="${startID-10}"/>
   <c:set var="prev_endID" value="${endID-10}"/>

   <c:set var="startID" value="${endID+1}"/>
   <c:set var="endID" value="${endID+10}"/>

   <c:set var="filmTitlesSize" value="${fn:length(filmTitles)}"/>


   <table>
    <thead>

     <c:choose>
      <c:when test="${RECORD_START_PAGE}">
       <tr>
        <td class="NEXT"> </td>
        <td class="NEXT"> </td>
        <td class="NEXT"> </td>
        <td class="NEXT">
         <a class="NEXT" href="index.jspx?startid=${startID}&amp;endid=${endID}">Next</a></td>
       </tr>
      </c:when>
      <c:when test="${RECORD_END_PAGE}">
       <tr>
        <td class="NEXT"> </td>
        <td class="NEXT"> </td>
        <td class="NEXT">
         <a class="NEXT" href="index.jspx?startid=${prev_startID}&amp;endid=${prev_endID}">Prev</a></td>
        <td class="NEXT"> </td>
       </tr>
      </c:when>
      <c:otherwise>
       <tr>
        <td class="NEXT"> </td>
        <td class="NEXT"> </td>
        <td class="NEXT">
         <a class="NEXT" href="index.jspx?startid=${prev_startID}&amp;endid=${prev_endID}">Prev</a></td>
        <td class="NEXT">
         <a class="NEXT" href="index.jspx?startid=${startID}&amp;endid=${endID}">Next</a>
        </td>
       </tr>
      </c:otherwise>
     </c:choose>


     <tr><th>Title</th><th>Description</th><th> </th><th> </th></tr>
    </thead>
    <tbody>

     <c:forEach items="${filmTitles}" var="i">
      <c:set var="film" value="${i}"/>
      <c:set var="filmID" value="${film.filmId}"/>
      <tr>
       <td class="COL1">
        <a href="browse.jspx?id=${filmID}">${film.title}</a>
       </td>
       <td class="COL2">${film.description}</td>
       <td class="COL2">
        <a href="browse.jspx?id=${filmID}">More</a>
       </td>
       <td class="COL2">
        <a href="rent.jsp?id=${filmID}">Rent</a>
       </td>
      </tr>
     </c:forEach>

    </tbody>
   </table>

  </body>
 </html>
</jsp:root>

Ya lo puedes hacer correr si quieres probarlo.

Si no te gusta escribir las JSP con JSTL, puedes revisar el código oficial donde está lo mismo pero en clave Java clásico.

browse.jspx

Crea otro archivo JSP con sintaxis XML que se llame browse con el siguiente código:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
    Document   : browse
    Created on : 29-nov-2009, 19:47:16
    Author     : ooscarr
-->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
     xmlns:c="http://java.sun.com/jsp/jstl/core">

 <jsp:output
  omit-xml-declaration="no"
  doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
  doctype-root-element="html"/>

 <jsp:directive.page import="dvdrental.*"/>
 <jsp:directive.page import="java.util.List"/>

 <jsp:directive.page contentType="text/html" pageEncoding="UTF-8"/>

 <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
   <title>DVDStore browse</title>
  </head>
  <body>
   
   <!-- Get title ID -->
   <c:set var="filmID" value="1"/>
   <c:if test="${not empty param.id}">
    <c:set var="filmID" value="${param.id}"/>
   </c:if>

   <c:set var="startPage">false</c:set>
   <c:set var="endPage">false</c:set>

   <jsp:useBean id="helper" class="dvdrental.FilmHelper"/>

   <!-- Invento para pasar filmID a FilmHelper.java -->
   <c:set target="${helper}" property="attributeFilmByID" value="${filmID}"/>

   <jsp:useBean id="film" class="dvdrental.Film"/>
   <c:set var="film" value="${helper.filmID}"/>

   <c:set var="filmTitle" value="${film.title}"/>
   <c:set var="filmDescription" value="${film.description}"/>

   <!-- Get Actors -->
   <c:set var="actors" value="${helper.actorsID}"/>

   <!-- Get Category -->
   <c:set var="category" value="${helper.categoryID}"/>

   <c:set var="totalCast">
    <c:forEach items="${actors}" var="i">${i.firstName} ${i.lastName}, </c:forEach>
   </c:set>

   <!-- Invento para pasar langId a FilmHelper.java -->
   <c:set target="${helper}" property="attributeLangByID" value="${film.languageByLanguageId.languageId}"/>
   <!-- Obtiene el idioma usando el langId entregado anteriormente -->
   <c:set var="language" value="${helper.langID}"/>
   
   <c:set var="filmLength" value="${film.length}"/>
   <c:set var="filmRating" value="${film.rating}"/>
   <c:set var="filmYear" value="${film.releaseYear}"/>
   
   <c:set var="rentalDuration" value="${film.rentalDuration}"/>
   <c:set var="rentalRate" value="${film.rentalRate}"/>

   <c:set var="specialFeatures" value="${film.specialFeatures}"/>


   <table>
    <tr>
     <td class="RENT"> </td>
     <td class="RENT">
      <a class="RENT" href="browse.jspx?id=${filmID}">Arrendar</a>
     </td>
    </tr>
    <tr>
     <th class="TITLE">Título</th>
     <td class="TITLE">${filmTitle}</td>
    </tr>
    <tr>
     <th class="COL1">Descripción</th>
     <td class="COL2">${filmDescription}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Género</th>
     <td class="COL2">${catName}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Reparto</th>
     <td class="COL2">${totalCast}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Duración de la película</th>
     <td class="COL2">${filmLength} <abbr title="minutos">mins.</abbr></td>
    </tr>
    <tr>
     <th class="COL1">Idioma</th>
     <td class="COL2">${language}</td>
    </tr>
    <tr>
     <th class="COL1">Calificación cinematográfica</th>
     <td class="COL2">${filmRating}</td>
    </tr>
    <tr>
     <th class="COL1">Año</th>
     <td class="COL2">${filmYear}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Características especiales</th>
     <td class="SPECIAL">${specialFeatures}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Precio Arriendo</th>
     <td class="COL2">US$ ${rentalRate}</td>
    </tr>
    <tr>
     <th class="COL1">Duración de Arriendo</th>
     <td class="COL2">${rentalDuration} días</td>
    </tr>
   </table>

   </body>
 </html>
</jsp:root>

Ejecuta la aplicación en el servidor, visita la página (en mi máquina se está ejecutando en http://localhost:8084/DVDStore/) y Voilà!. Funciona o te equivocaste.

Conclusiones

A pesar de que este ejemplo sólo hace lecturas a la base de datos, me puedo imaginar que escribir debe ser igual de sencillo ya que autmáticamente se generan la clases bean para insertar valores (set).

Con la persistencia ya no me tengo que preocupar de hacer la conexión y desconexión en cada página, la contraseña está guardada de manera más segura y estandarizada, y el acceso a las tablas se hace sencillo manejándolas como clases (un editor de Java ayuda a completar el código) y no andan las consultas SQL dando vueltas por todo el código, lo que ofrece mayor abstracción entre los distintos niveles del código otorgando flexibilidad a cambios.

Si se me ocurre cambiar la base de datos (agregar una columna, modificar el nombre de una tabla o las relaciones y tipos de datos), habría que regenerar los mapas de Hibernate y volver a compilar todo.

También, si nos fijamos en todo lo que hay que saber sobre programación Java, se hace más difícil la programación, aunque supongo y reconozco que con el tiempo se debe volver más sencillo con la experiencia. Obvio.

Mejoras en el rendimiento... No sé. Supongo que al tener todas las consultas guardadas... Y con Hibernate preocupado de las conexiones y desconexiones... Me imagino que sí hay alguna mejora, lo desconozco.

En el próximo capítulo...

Esto fue cómo leer desde una base de datos con Hibernate, prometo escribir sobre cómo escribir en la base de datos usando Hibernate y hacer este mismo ejemplo usando JPA, que ya lo tengo hecho, pero hay que desarrollarlo y darle formato. Hasta el próximo mes.

Referencias

Artículos relacionados

Etiquetas: , , , ,

Ejecutar Chrome OS como si fuera otra aplicación (abrir imagen VMWare en VirtualBox)

25.11.09. Por ooscarr (ooscarr)

Con el software opensource de virtualización de escritorios VirtualBox puedes probar ya el nuevo sistema operativo de Google completamente gratis y fácilmente en una ventana gracias a la posibilidad de abrir imágenes VMWware. Jump the shark.

Pestaña de aplicaciones de Chrome OS corriendo en VirtualBox.

Instrucciones

  1. Consigue una imagen de Chrome OS ya compilada (anda una imagen VMware dando vueltas por ahí).

  2. Mueve el archivo .vmdk a una carpeta personal, por ejemplo Mis documentos o ~/Library/VirtualBox/HardDisks o en cualquier lugar que no se te pierda.

  3. Abre VirtualBox y agrega una Máquina > Nueva...

  4. Dale un nombre, en Sistema Operativo elije la opción Linux y en Versión: Other Linux. Siguiente.

    Asistente de Nueva máquina virtual en VirtualBox.

  5. Especifica la memoria base. 256MB es lo mínimo recomendado, luego Siguiente.

  6. En el paso siguiente, marca la casilla de Disco duro de arranque (Primario maestro), selecciona la opción Usar un disco duro existente y busca la imagen VMWare de Chrome OS que conseguiste.

    Agregando imagen VMWare dentro del asistente de Nueva máquina virtual en VirtualBox.

  7. Siguiente. Terminar. Ahora selecciona la nueva máquina virtual de la lista que tiene VirtualBox e iníciala.

  8. Ahí está. El usuario y contraseña son los mismos que usas para iniciar sesión en Google.

También puedes bootear Chrome OS desde un pendrive USB si lo vas a usar en serio para obtener un rendimiento mayor y ver por qué es una buena idea.

Bonus track

Probé el WebOS de Palm en VirtualBox

En http://developer.palm.com/ puedes descargar, previo registro, un instalador del WebOS (el sistema operativo que usa el Palm pre) para VirtualBox gratis también para jugar.

Referencias

Relacionados

Etiquetas: , , , ,

Importar la base de datos de ejemplo MySQL (Sakila DB Schema) con Netbeans IDE es fácil

22.11.09. Por ooscarr (ooscarr)

Con el plug-in de Netbeans, instalar la base de datos de ejemplo Sakila es sencillo (con los permisos adecuados).

La base de datos de ejemplo Sakila fue desarrollada por Mike Hillyer, un pasado miembro del equipo de documentación de MySQL AB, y su intención fue la de proveer un esquema estándar que pueda ser usado para ejemplos en libros, tutoriales, artículos, ejemplos, y así en adelante. La base de datos de ejemplo Sakila también sirve para destacar las últimas características de MySQL tales como Vistas, Procedimientos Almacenados, y Disparadores (Triggers).

Scheme de Sakila DB hecho con MySQL Workbench
Diagrama relacional del Scheme de Sakila DB (ver más grande)

Instalar el plug-in de Sakila es muy sencillo, sólo vamos al menú Herramientas > Complementos, en el panel que se abre, existe una sección llamada Plugins disponibles.

En el panel de Plugins de Netbeans IDE, hay que marcar la opción Sakila Sample Database

Para instalarlo, espera que cargue la larga lista de plugins disponibles, marca la casilla de Sakila Sample Database y presiona el botón Instalar que está debajo. Sigue el proceso de instalación, reinicia Netbeans IDE si es necesario.

Luego, en el panel de Servicios (si no lo ves, elije el menú Ventana > Prestaciones) y con el menú contextual sobre la parte de Bases de datos elije la opción Registrar servidor MySQL... si todavía no lo has hecho.

Ya, cuando te hayas conectado al servidor MySQL como root u otra cuenta con los suficientes permisos, selecciónala y en el menú contextual elije la nueva opción Crear base de datos....

Para crear base de datos MySQL con el plugin de Sakila de Netbeans IDE se necesita tener permisos de root.

En el cuadro de diálogo que se abre, seleccionamos sakila en el primer campo, y en el segundo seleccionamos al usuario que tendrá todo el poder sobre esta nueva base de datos.

En el cuadro de diálogo de Crear nueva base de datos MySQL en Netbeans IDE, también aparecen otras bases de datos de ejemplo además de Sakila.

Ya, con eso, después de esperar que se creen todas las tablas y se llenen de datos de ejemplo, podemos conectarnos y empezar a utilizarlas para nuestros experimentos y lecciones.

Netbeans IDE cuenta con un administrador de bases de datos basado en ODBC.

Referencias

Etiquetas: , , , ,

Borrar base de datos en MySQL

20.11.09. Por ooscarr (ooscarr)

Voy a borrar toda una base de datos usando las líneas de comandos.

Eliminar una base de datos involucra eliminar también todas las tablas y contenidos de éstas y para hacerlo se necesita tener permiso para borrar dicha base de datos, y en mi caso usaré la cuenta root.

Voy al terminal, e inicio sesión como root:

/usr/local/mysql/bin/mysql -u root -p

Si el usuario root tiene contraseña, la ingresamos.

El comando para borrar una base de datos, según la documentación oficial, es:

DROP {DATABASE | SCHEMA} [IF EXISTS] db_name

Por ejemplo, para el caso que quiera eliminar una base de datos llamada ooscarr, pondría:

DROP DATABASE IF EXISTS ooscarr;

Obviamente, se advierte precaución ya que si no se ha hecho un respaldo previo, los datos no se podrán recuperar.

Para salir de MySQL, el comando es exit.

Referencias

Etiquetas: , , ,

Instalé MySQL en Mac OS X

14.11.09. Por ooscarr (ooscarr)

Mac OS X viene con Apache y PHP, pero sólo la versión server incluye MySQL, y hasta ahora no lo había instalado.

Puedes compilar MySQL tú mismo, como con PostgreSQl, pero para qué.

Descarga e instalación

1. Descarga MySQL

Ve a la página http://dev.mysql.com/downloads/mysql/ y descarga la última versión para Mac OS X. La versión x86 en formato DMG es la recomendada.

Si estás usando un Mac con un procesador de 64 bits (como un Core 2 Duo o Core i5, i7) y tienes algún Leopardo (OS X 10.5 u OS X 10.6) mejor descarga la versión de 64 bits para ir acorde a Apache2 que se ejecuta a 64 bits.

2. Leer antes de instalar

Si usas Mac OS X Server te recomiendo que leas el archivo Readme.txt que viene con el DMG para leer la documentación (en inglés) ya que Mac OS X Server viene con MySQL pre-instalado.

Aún si no usas la versión server, puede que ya tengas MySQL previamente instalado. Revisa si lo tienes instalado buscando algún archivo o carpeta con la palabra "mysql" en la carpeta /usr/local ó en Librería/StartupIyems, ya sea con el Finder (Menú Ir > Ir a la carpeta...) o con el Terminal:

ls /usr/local
ls /Library/StartupItems

Otra opción es ejecutar el comando de apagar el servidor MySQL que podría estar corriendo (y que es necesario hacerlo antes de comenzar la instalación) con el comando:

mysqladmin shutdown

Si no existe el comando, estamos bien. De todos modos, el instalador archivará una versión antigua de MySQL con la extensión .bak (siempre que el servidor MySQL haya sido parado antes de instalar).

3. Asistente de instalación

Ahora instala el paquete de instalación que NO se llama "MySQLStartupItem.pkg" y el rutinario Siguiente, Siguiente, Instalar, Finalizar.

El instalador te puede decir que no hay espacio, es un bug; retrocede y vuelve a intentarlo y no debería pasar.

Una vez que aparezca o suene la señal de instalación correcta, hay que elegir la opción Finalizar para cerrar el asistente de instalación.

Ojo, el instalador requiere un usuario llamado "mysql", pero los buenos de Apple lo crearon durante la instalación del sistema operativo. :-)

Configurar Mac OS X

Iniciar servidor

Iniciar y apagar MySQL es mucho más fácil y gráfico si se instala el panel de preferencias del sistema abriendo el archivo MySQL.prefPane incluido en la DMG de instalación de MySQL.

El botón de iniciar o detener el servidor MySQL se encuentra en las Preferencias del sistema, en la última sección de Complementos, se agrega un botón llamado MySQL.

Con esto, iniciar o detener el servidor MySQL es muy sencillo; basta presionar un botón en el panel de Preferencias del sistema MySQL, incluso se puede configurar para que se inicie automáticamente cuando arranque el sistema sin necesidad de modificar archivos de sistema.

PHP

Apple fue lo suficientemente amable para compilar php con soporte para MySQL así que sólo hay que configurar el archivo php.ini.

Primero ve a la carpeta /etc ó /private/etc, si ves algún archivo llamado php.ini no sigas el siguiente comando que consiste en crear una copia del archivo php.ini.default para usarlo como php.ini. Las intrucciones para el Terminal son las siguientes:

cd /etc

sudo cp php.ini.default php.ini

Edita el archivo recién creado con permisos de administrador con la instrucción:

sudo pico php.ini

Presiona control + W, busca mysql.default_socket, y hazlo que se vea como esto:

mysql.default_socket = /tmp/mysql.sock

Guarda los cambios presionando control X, luego presiona Y, luego presiona enter.

Si tenías el Compartir web corriendo, reinicia Apache desactivándolo y volviéndolo a activar.

Si quieres hacer una prueba, crea el siguiente archivo:

<?php
$con = mysql_connect("localhost","root","");
if (!$con){
 die('No se pudo conectar porque: ' . mysql_error());
} else{
 echo "Conectado exitosamente";
}
mysql_close($con);
?>

Guárdalo como probando.php en tu carpeta ~/Web o ~/Sites, entra a http://localhost/~USUARIO/probando.php y si sale

Conectado exitosamente

Entonces todo salió bien. Si no, quizás todavía no has configurado Apache para que funcione con PHP o qué sé yo.

Configurar bases de datos inciales

Durante la instalación por defecto de MySQL, se crearon unas cuentas de usuario:

root
El usuario root tiene acceso de super-usuario a todas las bases de datos, sólo se puede conectar desde el computador local y por defecto no lleva contraseña.
Cuentas anónimas
Dos cuentas de usuario anónimas son creadas y tampoco llevan contraseña, y sólo se puede conectar a ellas desde el local-host. Estas cuentas tienen todos los privilegios para la base de datos de prueba (test) y para otras bases de datos con nombres que empiezan con test_.

Cambiar las contraseñas por defecto

Primero debes averiguar cuáles son las cuentas que se crearon; para eso, voy al Terminal y primero me conecto como root:

/usr/local/mysql/bin/mysql -u root

...listo las cuentas con la consulta:

mysql> SELECT Host,User FROM mysql.user ORDER BY User DESC;

En mi caso me entregó lo siguiente:

+------------------+------+
| Host             | User |
+------------------+------+
| localhost        | root |
| MacBook.local    | root |
| 127.0.0.1        | root |
| localhost        |      |
| MacBook.local    |      |
+------------------+------+
5 rows in set (0.00 sec)

Como se ve, hay 3 cuentas root (127.0.0.1, MacBook.local, y localhost; y 2 anónimas (localhost y MacBook.local)

Las cuentas anónimas se pueden eliminar, pero como ignoro si me servirán algún día, mejor le cambiaré sus contraseñas solamente.

Para cambiar estas 5 contraseñas que están en blanco por el momento, escribo las siguientes consultas:

mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('contraseña_root');
mysql> SET PASSWORD FOR 'root'@'MacBook.local' = PASSWORD('contraseña_root');
mysql> SET PASSWORD FOR 'root'@'127.0.0.1' = PASSWORD('contraseña_root');
mysql> SET PASSWORD FOR ''@'localhost' = PASSWORD('contraseña_anónima');
mysql> SET PASSWORD FOR ''@'MacBook.local' = PASSWORD('contraseña_anónima');

Obviamente, reemplazando contraseña_root por la clave que le quieras poner al super-usuario, y las contraseña_anónima por la de las cuentas anónimas.

Desde ahora, la próxima vez que ingreses a MySQL con una cuenta que requiera contraseña, deberás agregar el parámetro -p al final, por ejemplo:

/usr/local/mysql/bin/mysql -u root -p

Si se te olvida la contraseña, consulta el manual.

Crear nueva base de datos

Ahora voy a crear una base de datos nueva llamada "db_name". Para eso, entro a MySQL como root y escribo:

CREATE DATABASE IF NOT EXISTS db_name;

Crear un nuevo usuario

Pata crear un nuevo usuario escribimos (como root MySQL):

CREATE USER 'ooscarr'@'localhost' IDENTIFIED BY 'obscure';

Con esto se creará el usuario "ooscarr" con la contraseña "obscure" para que se conecte desde localhost. Si queremos que pueda acceder desde otro equipo, habría que hacer lo mismo que se hizo anteriormente con los dominios o la dirección IP listados, que en mi caso sería:

CREATE USER 'ooscarr'@'MacBook.local' IDENTIFIED BY 'obscure';
CREATE USER 'ooscarr'@'127.0.0.1' IDENTIFIED BY 'obscure';

Asignar base de datos a un usuario

Ya, finalmente, le damos el permiso al usuario "ooscarr" recién creado para que administre la base de datos db_name, por ejemplo, con la siguiente sentencia SQL:

GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
 ON db_name.*
 TO 'ooscarr'@'localhost';

Y como uno se puede imaginar:

GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
 ON db_name.*
 TO 'ooscarr'@'MacBook.local';
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
 ON db_name.*
 TO 'ooscarr'@'127.0.0.1';

Para salir de MySQL escribimos exit; y para salir del Terminal, tipeamos logout.

Instalar software para trabajar con MySQL

Existen herramientas más cómodas para utilizar una base de datos MySQL, como son las interfaces gratuitas phpMyAdmin, Netbeans IDE y la sensacional Sequel Pro, entre otros.

Importante

En el futuro si lo actualizas, asegúrate de hacerle un dump a tus bases de datos, ya que haciendo una instalación sobre una instalación existente destruirá tu directorio de datos.

Referencias

Artículos relacionados

Etiquetas: , , ,

Instalar Oracle DB en Mac OS X

5.10.09. Por ooscarr (ooscarr)

Era cosa de tiempo para que los empleados de Sun Microsystems comenzaran a recomendar Oracle DB. Aquí dejo el link sobre su instalación en sistemas Mac OS X escrito por Arun Gupta.

Oracle ® + Sun Microsystems ®

Después él enseña a conectar a Oracle en Netbeans y más adelante crea una aplicación web elemental de lectura de base de datos en JSF 2.0 + JPA 2.0 + EJB 3.1 con estas herramientas sobre Glassfish v3 (su favorito).

Digo, para saber y tener algo más de experiencia de cómo son las cosas en las otras plataformas.

Links

  1. TOTD #106: How to install Oracle Database 10g on Mac OS X (Intel) ?
  2. TOTD #107: Connect to Oracle database using NetBeans
  3. TOTD #108: Java EE 6 web application (JSF 2.0 + JPA 2.0 + EJB 3.1) using Oracle, NetBeans, and GlassFish

Artículos relacionados

Etiquetas: , ,

Exportar a formato Excel con JSP de forma bien básica (TSV)

19.8.09. Por ooscarr (ooscarr)

En este tutorial voy a mostrar la manera de generar un archivo compatible con Microsoft Excel que consiste en valores separados por espacios tabuladores muy elemental y sin gráficos o estilos.

Primero hay que partir diciendo qué opciones de formatos compatibles con Excel hay:

CSV
Es el más conocido, y consiste en un archivo de texto plano, generalmente con la extención .csv donde los valores de cada celda van separados por una coma (,) en el caso de las columnas, y un salto de línea para las filas.
TSV
TSV es una variación al anterior CSV, donde las columnas van separadas por un espacio tabulador y las filas por un salto de línea. Esto permite que se puedan introducir celdas con valores que incluyan una coma y no sean confundidas por un salto de columna, por ejemplo.
XLS
El formato Microsoft Excel tradicional que es un archivo binario para Windows donde se guardan en hojas, gráficos y macros. Mucho tiempo su especificación fue cerrada, pero desde que se comenzó a documentar el formato con ingeniería inversa y debido a las presiones de las cortes para aceptar su formato como un estándar, Microsoft se vio obligada a publicar su estructura de funcionamiento bien particular.
XLSX
Esta es la última especificación Office Open XML que Microsoft no sé cómo logró estandarizar, y que consiste en una serie de archivos XML y otros, organizados en una carpeta todo comprimido en un archivo ZIP (al igual que el estándar OpenDocument que también es soportado por Microsoft Office 2007 pero que no es de propiedad de Microsoft).

Y otros más menos importantes.

El formato

El formato que voy a exportar desde el JSP en este tutorial es el TSV, pero con extensión .xls. El archivo siguiente:

Uno Due Tre Quattro
Uno Dos Tres Cuatro
One Two
Ichi Ni San Shi
Odin Dva Tri

Se vería así en la planilla de cálculo:

ABCD
1UnoDueTreQuattro
2UnoDosTresCuatro
3OneTwo
4IchiNiSanShi
5OdinDvaTri
Más información »

Etiquetas: , , , , ,

Cómo instalar un .war en Tomcat desde la página Tomcat manager

2.8.09. Por ooscarr (ooscarr)

Para una tarea tuve que hacer un manual de cómo instalar un archivo .war en el viejo Tomcat. Super sencillo y básico, no se asombren.

No a la guerra.

En computación, un archivo WAR (el cual sus iníciales significan “archivo de aplicación web”) es un archivo JAR utilizado para distribuir una colección de JavaServer Pages, servlets, clases Java, archivos XML, librerías de tags y páginas web estáticas (HTML y archivos relacionados) que juntos constituyen una aplicación web.

1. Abrir la página inicial de Tomcat

Tomcat manager viene incluido con tomcat cuando se instala, para acceder a él se ingresa a la página del servidor donde está ejecutándose Tomcat.

Página de $CATALINA_HOME de Tomcat desplegándose en la URL http://localhost:2348/
Usualmente se encuentra en el http://localhost:8080/ o en el mismo puerto del servidor externo.

2. Entrar a Tomcat Manager

En dicha página en la columna de Administración izquierda se encuentra un link a Tomcat Manager

Inmediatamente preguntará por la constraseña, que por defecto es

usuario
tomcat
contraseña
tomcat

Página de Tomcat Manager típica
En la página de Tomcat manager, aparece una lista con todas las aplicaciónes que Tomcat tiene instaladas o ejecutándose (incluyéndose a sí mismo).

3. Desplegar aplicación

Casi al final, aparece un formulario llamado Desplegar.

En la parte donde dice Seleccione archivo WAR a deplegar, es cosa se buscar el archivo WAR, subirlo al servidor con el botón Desplegar...

Formulario de despliegue de aplicación web en Tomcat Manager típico

Y si no había otra aplicación con el mismo contexto, debería aparecer un mensaje de OK en la parte superior de la página al terminar la transferencia.

Advertencias

  • No todos los .war funcionan en todas las versiones de Tomcat

Referencias

Etiquetas: , ,

Accediendo a otro servidor de una red por SSH

27.7.09. Por ooscarr (ooscarr)

Terminal

El comando para conectarse al puerto del servidor que está en la Universidad y que no podemos acceder desde la casa (a través de otro servidor dentro de la red).

Primer caso

En la Universidad tenemos un servidor Windows 2003 que ofrece el servicio de Tomcat por el puerto 8080 como es normal. http://serrano.unap.cl:8080/. Pero la red de la Universidad tiene el puerto 8080 bloqueado para afuera de la U y no podemos conectarnos desde la casa.

Por medio de SSH, nosotros nos conectamos a otro servidor con Linux que está en la misma red, http://acinfo.unap.cl/, por el puerto de siempre, el 22, y a través de esta conexión accedemos al servidor del puerto 8080.

Diagrama con un notebook (localhost:2348) conectándose a un servidor con linux (acinfo.unap.cl:22) que a su vez está conectado a un servidor con Tomcat (serrano.unap.cl:8080)
Algo más o menos así.

En el Terminal, esto se hace con el comando

ssh ooscarr@acinfo.unap.cl -L 2348:serrano.unap.cl:8080

ó

ssh ooscarr@acinfo.unap.cl -L 2348/serrano.unap.cl/8080

Reemplazamos el ooscarr por tu nombre de usuario, por supuesto, y así accedemos al puerto 8080 del otro servidor como si estuviéramos en la mismísima U.

Página de $CATALINA_HOME de Tomcat desplegándose en la URL http://localhost:2348/
¡A través de la dirección http://localhost:2348/ accedemos a http://serrano.unap.cl:8080/!

Fin.

No, mentira. Segundo caso

Pongámonos en un segundo caso. Acaban de instalar Tomcat en el servidor acinfo.unap.cl:8080 así que ya no hace falta conectarse al serrano.unap.cl:8080. El puerto 8080 del servidor también está bloqueado,

Diagrama con un notebook (localhost:2348) conectándose a un servidor con linux (acinfo.unap.cl:8080)
Ahora sin el serrano.

En este caso, bastaría cambiar serrano.unap.cl por localhost ó acinfo.unap.cl así

ssh ooscarr@acinfo.unap.cl -L 2348:localhost:8080

ó

ssh ooscarr@acinfo.unap.cl -L 2348:acinfo.unap.cl:8080

ó

ssh ooscarr@acinfo.unap.cl -L 2348/acinfo.unap.cl/8080

ó

ssh -N -p 22 ooscarr@acinfo.unap.cl -L 2348:acinfo.unap.cl:8080

Y el mismo resultado.

Página de $CATALINA_HOME de Tomcat desplegándose en la URL http://localhost:2348/
¡A través de la dirección http://localhost:2348/ accedemos a http://acinfo.unap.cl:8080/.

Podríamos conectarnos a ambos servidores, utilizando un puerto distinto al 2348 para el segundo servidor.

¿Y si uso Windows, cómo lo hago?

Bueno, para esos casos, mi amigo Fernando (el Puma) hizo un mini-tutorial en su blog.

Referencias

Artículos relacionados

Etiquetas: , , , ,

Ejecuta otro sistema operativo en una ventana sin reiniciar con VirtualBox

9.4.09. Por ooscarr (ooscarr)

VirtualBox

Se me acabó el período de prueba de Parallels (US$79,99), y ya que también se estaba acabando el período de descarga de Windows 7 beta (12 de febrero de 2009), me animé a probar Virtualbox, un proyecto opensource para correr máquinas virtuales del que se estaba hablando harto en el mundo mac.

En un mundo dominado por el sistema operativo Windows, hay un par de cosas en las que dependo de este SO que son: un programa que me piden en la Universidad y que no puedo ejecutar con wine, y un pendrive que viene diseñado para ser reconocido sólo por Windows (debería cambiarlo).

Personalmente, participé en dos presentaciones de Virtualbox donde pude aclarar mis dudas por medio de demostraciones, haciendo preguntas y viendo las de otras personas, en vivo y en directo con los desarrolladores de Sun; y esa demostración me convenció de que Virtualbox es una herramienta ya madura que puedo considerar y recomendar aceptablemente. La uso a menudo.

windows 7 corriendo en VirtualBox bajo Mac OS X Leopard

Con respecto a las máquinas virtuales, hay algunas palabras claves que hay que conocer:

Máquina virtual
Es una manera especial de correr diferentes sistemas operativos dentro del SO que estás ocupando. Por ejemplo, dentro de una ventana como cualquier otro programa.
Host o Anfitrión
Se refiere al computador donde se está ejecutando Virtualbox, o sea, el real.
Guest o invitado
Corresponde a la máquina virtual. El sistema operativo invitado cree que se está ejecutando sobre hardware real y funciona.
Tecla anfitrión o Host key
Esto es específico de Virtualbox. Es la tecla o combinación de teclas para intercambiar el puntero y el teclado entre ambos sistemas operativos. Si aparece la palabra izquierda, significa que es la tecla del lado izquierdo, no siempre la flechita . Es un problema de traducción.
Más información »

Etiquetas: , , ,

Consumir servicio web SOAP (ShoppingAPI de eBay) desde un WSDL con JSP(X) en NetBeans

6.1.09. Por ooscarr (ooscarr)

Netbeans

Ahora haré lo mismo que hice por consola pero con una interfaz web. El consumo de un servicio web SOAP (el de ebay) a partir de un archivo WSDL

El código es casi el mismo, sólo cambia el envoltorio.

Necesitamos

En resumen,

  • Registrarnos en el sitio de desarrolladores de ebay.
  • Obtener una clave.
  • Anotar la dirección del archivo WSDL.

Más detalle de esto en el artículo anterior.

Nuevo proyecto en Netbeans

Creamos un proyecto nuevo de tipo Aplicación Web

Nueva aplicación web

Le puse de nombre Tebay.

Nombrando Tebay al proyecto

El servidor, como siempre, Glassfish o Tomcat.

Seleccioné Tomcat

Netbeans creando nuevo proyecto
Terminar

Nuevo Cliente de Servicio Web

Después agregamos un Archivo nuevo de tipo Web Service Client

Pegamos la dirección del WSDL http://developer.ebay.com/webservices/latest/ShoppingService.wsdl.

Specify the WSDL file of the Web Service
Terminar.

Protocolo

ebay ofrece sus servicios web en diferentes formatos de pedido y respuesta como se muestra en la siguiente figura.

Diferentes formatos de pedido y respuesta de la Shopping API de ebay: URL, XML, JSON, SOAP

En esta ocasión no utilizaremos SOAP para hacer los pedidos, en vez de eso, haremos las requests por medio de URL (a lo REST), pero por lo menos lo que recibiremos será SOAP.

JavaBean

Creamos una nueva clase java.

NetBeans: Archivo nuevo > Java > Clase Java

La nombro, por ejemplo, BuscaItems y la agrego a un paquete, eeh.. consumidor.

Nombrando a una nueva clase Java en NetBeans y agregándola a un nuevo paquete consumidor

BuscaItems.java

En el archivo .java escribo el código correspondiente a un bean, muy parecido al código de la clase java anterior

package consumidor;

import javax.xml.ws.BindingProvider;

public class BuscaItems {

 public String que="No definido";
 public String consulta="No definida";
 public String estado="No procesado";
 public Integer nitems=0;//Número de items
 public String url="";

 private static final String APPID = "UNAP3d995-2kj53-67u8-abcc-po988l9u035";
 private static final String CALLNAME = "FindItems";
 private static final String VERSION = "557";
 private static final String BASEURL="http://open.api.ebay.com/shopping?";

 private static BindingProvider bp;
 
 //Constructor
 public BuscaItems(){
 }
 
 public void setQue(String que){
  
  String endpointURL = BASEURL+"callname=" + CALLNAME+"&version="+VERSION+"&appid=" + APPID;

  try { // Llama Operación del Servicio Web
   ebay.apis.eblbasecomponents.Shopping service = new ebay.
    apis.eblbasecomponents.Shopping();
   ebay.apis.eblbasecomponents.ShoppingInterface port = service.
    getShopping();
   bp = (BindingProvider) port;
   bp.getRequestContext().
    put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
     endpointURL);
   // Inicializa los argumentos de la operación del SW
   ebay.apis.eblbasecomponents.
    FindItemsRequestType findItemsRequest = new ebay.
     apis.eblbasecomponents.FindItemsRequestType();
   findItemsRequest.setQueryKeywords(que);
   // Procesa los resultados
   ebay.apis.eblbasecomponents.FindItemsResponseType result = port.findItems(findItemsRequest);
   consulta=endpointURL;
   estado=result.getAck().toString();
   nitems=result.getTotalItems();
   url=result.getItemSearchURL();

  } catch (Exception ex) {
   estado=ex.getMessage();
  }
 }

 public String getConsulta(){
  return consulta;
 }
 public String getEstado(){
  return estado;
 }
 public Integer getNitems(){
  return nitems;
 }
 public String getUrl(){
  return url;
 }

}

Nuevo JSPX

Biblioteca JSTL

Porque voy a usar <c:choose>, <c:when>, <c:otherwise>, <c:if> y <c:out>, y porque lo hice en Tomcat, es necesario agregar la biblioteca JSTL.

Para eso, en las propiedades del proyecto, en la sección Librerías presionamos el botón Add Library... (Añadir biblioteca...)

Panel de propiedades del proyecto en Netbeans

Y añadimos la biblioteca JSTL.

Captura de pantalla del aistente para añadir bibliotecas de Netbeans con la biblioteca JSTL 1.1 seleccionada

index.jspx

Para hacerlo más entretenido, la JSP la escribiré en el nuevo formato de etiquetas, así que crea un nuevo archivo JSP 2.0, e ingresa lo siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
    Document   : index
    Created on : 06-ene-2009, 23:47:10
    Author     : ooscarr
-->
<jsp:root
 xmlns:jsp="http://java.sun.com/JSP/Page"
 version="2.0"
 xmlns:c="http://java.sun.com/jsp/jstl/core">
 <jsp:output
  omit-xml-declaration="no"
  doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
  doctype-root-element="html"/>
 <jsp:directive.page contentType="text/html" pageEncoding="UTF-8"/>
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  <title>JSP Page</title>
 </head>
 <body>
  <div class="encabezado">
   <h1>¿Tebay?</h1>
   <p>Nombra un producto y te diré si se encuentra en el sitio de ebay.</p>
  </div>

  <!-- Formulario de consulta -->
  <h2>Consulta</h2>
  <form action="index.jspx" method="get"><p>
   <c:choose>
    <c:when test="${empty param.que}">
     <input type="text" name="que"/>
    </c:when>
    <c:otherwise>
     <input type="text" name="que" value="${param.que}"/>
    </c:otherwise>
   </c:choose>
   <button type="submit">Buscar</button>
  </p></form>
  <p>(Se obtienen mejores resultados con consultas en inglés).</p>


  <!-- Si se consultó algo -->
  <c:if test="${not empty param.que}">


   <h2>Resultados de la búsqueda "<c:out value="${param.que}" />"</h2>

   <jsp:useBean id="b" scope="page" class="consumidor.BuscaItems">
    <jsp:setProperty name="b" property="que" value="${param.que}"/>
   </jsp:useBean>
   
   <c:set var="cuantos">
    <jsp:getProperty name="b" property="nitems"/>
   </c:set>

   <c:choose>
    <c:when test="${cuantos > 0}">

     <!-- La intención de guardar esta variable es para
       procesarla con c:out -->
     <c:set var="url">
      <jsp:getProperty name="b" property="url"/>
     </c:set>

     <p>Se encontraron
      <jsp:element name="a">
       <jsp:attribute name="href">
        <!-- Al procesar con c:out los "&" se convierten en "%amp;" -->
        <c:out value="${url}"/>
       </jsp:attribute>
       <jsp:body>
        <jsp:getProperty name="b" property="nitems"/>
        resultados en ebay
       </jsp:body>
      </jsp:element>
     </p>

    </c:when>
    <c:otherwise>
     <p><jsp:element name="a">
       <jsp:attribute name="href">
        <jsp:getProperty name="b" property="consulta"/>
       </jsp:attribute>
       <jsp:body>No hubieron resultados</jsp:body>
     </jsp:element>.</p>
    </c:otherwise>
   </c:choose>


  </c:if>

  <hr /><p>Oscar Fernández</p>
 </body>
</html>
</jsp:root>

Resultado

Al presionar el botón Ejecutar (Run Main Project), después de compilar y hacer Deploy automáticamente, se debería abrir la página http://localhost:8084/Tebay/index.jspx parecida a la siguiente:

Ver página de referencia de resultado.
* La página es sólo de referencia. No funciona.

Conclusiones

Este método claramente se demora debido a que debe comunicarse con los servidores de ebay antes de generar la página de resultado, por lo que el uso de estos servicios web en servidores externos son más recomendables procesarlos en el computador del cliente por medio de técnicas como, en el caso de la web, Javascript (bueno, AJAX).

Artículos relacionados

Etiquetas: , , , ,

Publicidad