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: , , , ,

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: , , , ,

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: , , , , ,

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: , , , ,

index.jspx en Netbeans

6.1.09. Por ooscarr (ooscarr)

Netbeans

Trabajar con JSP 2.0 en NetBeans es sencillo.

Nuevo archivo JSPX

Crear un archivo JSPX, o JSP Document (XML Sytax) o JSP 2.0, es muy fácil.

  1. Sólo debes crear un nuevo archivo Web > JSP

    seleccionando nuevo archivo JSP en Netbeans

  2. Y seleccionar, JSP Document (XML Sytax) después de nombrarlo.

    nombrando archivo index seleccionando opción sintaxis XML en Netbeans

Cómo cambiar la página por defecto

Porque al crear una nueva aplicación web, NetBeans crea la página de bienvenida index.jsp automáticamente; para cambiar la primera página por defecto de la aplicación,

  1. Abro el archivo web.xml

    Web Pages/WEB-INF/web.xml

  2. Voy a la ficha Pages, o Páginas.

    Ficha Pages del editor de web.xml de Netbeans

  3. Y cambio el nombre del archivo de bienvenida que se abrirá automáticamente.

  4. Guardar. Eso es todo.

Etiquetas: ,

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

5.1.09. Por ooscarr (ooscarr)

Netbeans

Consumir un servicio web en Java resultó más difícil de lo que pensaba. Por eso algunos servicios ofrecen SDKs para facilitar las cosas, pero aquí lo haremos a mano, consumiendo el Servicio Web SOAP que ofrece eBay desde el puro archivo WSDL (y la ayuda de NetBeans).

¿Por qué el SW de eBay? Bueno, uno, porque es uno de los pocos servicios web más famosos que ofrecen una API en SOAP (a todos les gustó REST).

De los grandes

Y dos, porque ni con Microsoft ni con Amazon pude lograr un resultado. Mi culpa. Así que sigamos con ebay.

De los más famosos que ofrecen sus servicios web por SOAP gratis, tenemos:

Primero se necesita

4 steps

Registro

Para obtener una clave para utilizar los servicios web de ebay, hay que registrarse en la página para desarolladores de ebay http://developer.ebay.com/.

Clave de desarrollador en eBay

Después de registrarnos, pedimos unas claves Production keys que son como estas:

* Estas claves son inventadas. Consiga sus propias claves.
DEVID03abb543-5t3d-87k-na95f-o234bo854
AppID:UNAP3d995-2kj53-67u8-abcc-po988l9u035
CertID:4hd73h-9385-383d-as3j-ffie34u5eee35

El archivo WSDL

En esta ocasión vamos a utilizar la Shopping API. El archivo WSDL para el SOAP de eBay, se encuentra en la parte de Documentación y es éste:

http://developer.ebay.com/webservices/latest/ShoppingService.wsdl

Nuevo proyecto en Netbeans

Ahora, creamos un proyecto nuevo de tipo Aplicación Java

Nueva aplicación Java

Le puse de nombre SOAPebay.

Nombrando al proyecto SOAPebay en Netbeans 6.5
Terminar.

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

Nuevo archivo Web Services > 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.

Y después que se genera el servicio web, arrastramos y soltamos el método FindItems desde Web Services References/ShoppingService/Shopping/Shopping al main del archivo Main.java del proyecto.

Arrastrar el método y soltar en el código Java en Netbeans.

Código

Lo ideal hubiera sido que se generara todo automáticamente para llegar y reemplazar strings, pero por lo menos tenemos el esqueleto del código hecho.

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.

Main.java

Estructura de la URL pedida http://open.api.ebay.com/shopping?

Reemplace todo el contenido de Main.java por esto:

package soapebay;

import javax.xml.ws.BindingProvider;

public class Main {

 //Cambiar APPID
 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;

 public static void main(String[] args) {
  
  String endpointURL = BASEURL+"callname=" + CALLNAME+"&version="+VERSION+"&appid=" + APPID;

  try {

   ebay.apis.eblbasecomponents.Shopping service = new ebay.apis.eblbasecomponents.Shopping();
   ebay.apis.eblbasecomponents.ShoppingInterface port = service.getShopping();bp = (BindingProvider) port;
   bp = (BindingProvider) port;
   bp.getRequestContext().
    put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
     endpointURL);
   // Inicializa los argumentos
   ebay.apis.eblbasecomponents.FindItemsRequestType findItemsRequest = new ebay.apis.eblbasecomponents.FindItemsRequestType();
   findItemsRequest.setQueryKeywords("iphone");
   // procesa los resultados
   ebay.apis.eblbasecomponents.FindItemsResponseType result = port.findItems(findItemsRequest);
   System.out.println ( " Consulta : " + endpointURL);
   System.out.println("Estado = "+result.getAck());
   System.out.println("Número total de Items= "+result.getTotalItems());
   System.out.println("URL = "+result.getItemSearchURL());

  } catch (Exception ex) {
   // TODO handle custom exceptions here
  }
 }
}

Y al presionar el botón Ejecutar (Run Main Project), en la consola o Panel de Salida debería aparecer lo siguiente:

compile:
run:
 Consulta : http://open.api.ebay.com/shopping?callname=FindItems&version=557&appid=UNAP3d995-2kj53-67u8-abcc-po988l9u035
Estado = SUCCESS
Número total de Items= 64525
URL = http://search.ebay.com/ws/search/SaleSearch?fsoo=1&fsop=1&satitle=iphone
GENERACIÓN CORRECTA (tiempo total: 59 segundos)

No olvidar cambiar la clave de la API en el código fuente. Y si se va a compilar por segunda vez, se debe limpiar (Clean) antes.

Por web

También intenté hacerlo por web, donde tiene más sentido el consumo de este servicio, pero no pude terminarlo debido a mi ignorancia en JavaBeans. Help.

Referencias

Etiquetas: , , , ,

Crear un simple servicio web SOAP en Java con NetBeans es re-fácil

21.12.08. Por ooscarr (ooscarr)

Netbeans

A través de un video tutorial (mencionado al final de este documento), aprendí a crear un simple servicio web con NetBeans.

Según leí, Sun removió el soporte para el WSDK (aunque igual se sigue distribuyendo) para reemplazarlo por GlassFish. Así que ni modo. Pero estas instrucciones también funcionan con Tomcat.

Crear nuevo proyecto

Lo primero es crear un nuevo proyecto, así que...

  1. Creamos un Nuevo proyecto, en mi caso de tipo Aplicación Web

    Captura de pantalla del asistente para crear un Nuevo proyecto en Netbeans

  2. Elijo un nombre para la aplicación web. Yo le llamé Holaste.

    Captura de pantalla del asistente para crear una Nueva Aplicación Web

  3. En los ajustes del servidor, elijo GlassFish o Tomcat, como siempre.

    Opción GlasshFish en los ajustes de servidor del asistente para crear nuevo Proyecto de Aplicación Web en NetBeans

  4. Y Terminar

    Asistente de Nuevo Proyecto de NettBeans creando el nuevo proyecto

¿Código?

Como toda apliación web, me aparece el típico index.jsp predeterminado en el que puedo aprovechar de describir el Servicio Web (puedo poner cualquier cosa, en realidad, porque esto no es parte del servicio web).

index.jsp

<%-- 
    Document   : index
    Created on : 21-dic-2008, 12:06:37
    Author     : ooscarr
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es-cl">
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 <title>Servicio web</title>
</head>
<body>
 <h1>Este es el Servicio web</h1>
 <p>Este servicio lo que hace es decir "Hola, [nombre]" a cambio
   de un parámetro [nombre] de tipo <code>String</code>.</p>
</body>
</html>

Creación del Servicio Web

Mmm... Bueno, en NetBeans es muy sencillo crear un Servicio Web, sólo basta seleccionar el nombre del proyecto (Holaste en mi caso) y poner Archivo Nuevo. Ahi también hay una opción llamada Web Service.

agregando un Nuevo archivo al proyecto con el asistente en NetBeans

Y le damos un nombre, por ejemplo, ServicioWeb.

Nombrando servicio web en NetBeans
Aproveché de agregarlo a un paquete llamado hola.

Añadir operaciones

Para añadir operaciones hay que sólo posicionarse sobre el Servicio Web y poner Add Operation...

Menú contextual para Servicio web en NetBeans

De otra forma, en el modo Design existe el botón Add Operation....

Botón Add Operation... en el modo Design del editor de servicios web de NetBeans.

Ahí le pongo un nombre, puedo añadir parámetros y elegir si lo quiero de tipo String, boolean, int, etc.

Añadiendo Operaciones a un Servicio web en NetBeans

ServicioWeb.java

Con eso se generará automáticamente el código esqueleto que puedo modificar para que me retorne "Hola, " + nombre;. Así:

package hola;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 *
 * @author ooscarr
 */
@WebService()
public class ServicioWeb {

 /**
  * Web service operation
  */
 @WebMethod(operationName = "diHola")
 public String diHola(@WebParam(name = "nombre")
 String nombre) {
  //TODO write your implementation code here:
  return "Hola, " + nombre;
 }

}

Probémoslo

Ya. Probémoslo. Para eso primero hay que armar el proyecto con el menú contextual del proyecto, opción Deploy.

GENERACIÓN CORRECTA (tiempo total: 7 segundos)

Y probar el servicio web, seleccionando el Servicio web, opción Test Web Service.

INFO: Dynamically creating request wrapper Class hola.jaxws.DiHola
INFO: Dynamically creating response wrapper bean Class hola.jaxws.DiHolaResponse
INFO: parsing WSDL...
INFO: generating code...
INFO: 
compiling code...
INFO: Invoking wsimport with http://localhost:8080/Holaste/ServicioWebService?WSDL
INFO: wsimport successful
INFO: parsing WSDL...
INFO: generating code...
INFO: 
compiling code...
INFO: Invoking wsimport with http://localhost:8080/Holaste/ServicioWebService?WSDL
INFO: wsimport successful

Si todo está bien instalado, se debería abrir una ventana del navegador más o menos así.

Página web, con formulario para probar las operaciones del Servicio Web, generada por NetBeans

Aquí, por ejemplo, si pongo Oscar en el formulario, se puede ver el código que entrega el servicio Web al cliente.

ver referencia.

WSDL

También es bueno hacer notar que NetBeans genera automáticamente el archivo WSDL (y su XML Schema también) para ser usado en las implementaciones de los Clientes.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.5-hudson-$BUILD_NUMBER-. -->
<definitions targetNamespace="http://hola/" name="ServicioWebService" xmlns:tns="http://hola/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema>
<xsd:import namespace="http://hola/" schemaLocation="ServicioWebService_schema1.xsd"/>
</xsd:schema>
</types>
<message name="diHola">
<part name="parameters" element="tns:diHola"/>
</message>
<message name="diHolaResponse">
<part name="parameters" element="tns:diHolaResponse"/>
</message>
<portType name="ServicioWeb">
<operation name="diHola">
<input message="tns:diHola"/>
<output message="tns:diHolaResponse"/>
</operation>
</portType>
<binding name="ServicioWebPortBinding" type="tns:ServicioWeb">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="diHola">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="ServicioWebService">
<port name="ServicioWebPort" binding="tns:ServicioWebPortBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
</port>
</service>
</definitions>

Fuente

Todo lo que dije lo saqué de un video hecho por un desarrollador de Sun. Lo puedes ver (en inglés) desde el siguiente link, por si te quedó alguna duda.

[ACTUALIZACIÓN] Después él hizo otro video consumiendo datos desde una base de datos usando JPA (pero con menos calidad):

Ver video en youtube.com

Etiquetas: , ,

Agregar patrones a un elemento con atributos en un W3C XML Schema

26.11.08. Por ooscarr (ooscarr)

Llevo 3 días sufriendo pensando y probando todas las combinaciones posibles para agregar una restricción de patrón a un elemento con atributos. Finalmente di con la respuesta. Era mi primer XML Schema.

Explicar qué es y cómo se escribe un XML Schema da para largo y todavía no estoy muy seguro de algunos aspectos más avanzados, así que no lo voy a hacer (a menos que me sobre el tiempo).

Así que por lo que pude probar usando el excelente editor de XML Schema de netbeans (seguramente basado en algún validador de XML Schemas del W3C), sólo podía agregar restricciones a:

  • Elementos simples sin atributos
  • Elementos complejos con elementos hijos

Pero yo necesitaba agregar una restricción al contenido de un elemento con atributos a mi W3C XML Schema.

Problema

Digamos que tengo la siguiente etiqueta en mi XML:

<title type="text">A1</title>

...y necesito agregarle las siguientes restricciones de XML Schema:

<xsd:restriction base="xsd:string">
 <xsd:pattern value="[A-Z]+[0-9]+"/>
 <xsd:minLength value="2"/>
</xsd:restriction>

(Sí, se tratan de celdas de una planilla de cálculo)

Solución

Y la manera en que lo logré fue... ¡Ah! ¡Primero deja explicar que tenia un namespace llamado tns en la cabecera! (Poco relevante)

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 targetNamespace="http://www.ooscarr.com"
 xmlns:tns="http://www.ooscarr.com"
 elementFormDefault="qualified">

W3C XML Schema

Primero creé un tipo simple llamado ncelda

<xsd:simpleType name="ncelda">
 <xsd:restriction base="xsd:string">
  <xsd:pattern value="[A-Z]+[0-9]+"/>
 </xsd:restriction>
</xsd:simpleType>

Luego creé un tipo complejo llamado titulo basado en el ncelda

<xsd:complexType name="titulo">
 <xsd:simpleContent>
  <xsd:extension base="tns:ncelda">
   <xsd:attribute name="type" type="xsd:string"/>
  </xsd:extension>
 </xsd:simpleContent>
</xsd:complexType>

Y finalmente, agregué el elemento title de tipo titulo

<xsd:element name="title" type="tns:titulo"/>

Fin.

Con Netbeans

Netbeans

Para hacer lo mismo con la interfaz gráfica de netbeans; (de los 3: Source, Schema y Design) en el modo Schema, es cosa de

  1. agregar un Simple Type...
    Menú contextual Agregar un Simple Type...
  2. llamarlo ncelda
  3. con el método de derivación restriction
  4. usando la definición existente Built-in Types > string

Menú contextual Propiedades

Después ir a las propiedades del tipo creado y agregar al patrón (Pattern) la expresión regular

[A-Z]+[0-9]+

Y de ahí,

  1. Se crea el elemento complejo llamado titulo
  2. Lo personalizamos
    menú contextual, opción Personalizar
    y usamos la extensión existente ncelda
    Global Complex Type customizer
  3. Después creamos el elemento title usando el tipo existente titulo y le agregamos el atributo type
    menú contextual de agregar atributo

árbol del esquema en el modo Schema del editor de XML Schema de netbeans

0 Error(s),  0 Warning(s).

Etiquetas: , ,

Conectar a la base de datos desde JSP

3.9.08. Por ooscarr (ooscarr)

Netbeans

Con JSTL, conectarse a una base de datos es sencillo y no requiere todo ese peligroso código Java que antes producía dolores de cabeza y frustración.

Preparación

ACTUALIZACIÓN: Netbeans 6.5 agregó al asistente para crear nuevos proyectos web, un formulario extra para ingresar los drivers y los datos de la base de datos desde el principio.

Luego de crear el proyecto JSP y antes de conectar a la base de datos, hay que instalar las librerías Java para la base de datos.

  1. Vamos a las propiedades del proyecto, en la sección Librerías presionamos el botón Add Library... (Agregar librería...)

    Panel de propiedades del proyecto en Netbeans

  2. Importar

    Importar librería en Netbeans

  3. Seleccionamos la librería de PostgreSQL (o Mysql, según...)

    PostgreSQL JDBC Driver
    Aprovechar de agregar la JSTL si no ha sido incluida.

  4. Add Library (Agregar Librería)

    Add Library

  5. OK

Conexión

Luego creamos un JSPF para la conexión

  1. Nuevo archivo > JSP

  2. Le ponemos un nombre...

    Nuevo archivo JSP(F) en Netbeans
    Nos aseguramos que el archivo quede en la carpeta WEB-INF/jspf

El árbol de archivos del proyecto indicando Web Pages > WEB-INF > jspf > conexion.jspf

conexion.jspf

El código del archivo conexion.jspf contendría sólo y nada más que:

<sql:setDataSource driver="org.postgresql.Driver"
 url="jdbc:postgresql://locahost:5432/usuario"
 user="usuario"
  password="contraseña"
 var="bdatos" />

* Si se utiliza Mysql, cambiar parte de la segunda línea por jdbc:mysql://
** Si el servidor se encuentra en otra máquina, cambiar la parte locahost:5432 por la IP y el puerto correspondiente.

La conexión se guarda en una variable var="bdatos" para poder ser usada después en el código.

Código

Ya en el código JSP, primero agregamos el tag sql

<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%>

Y después llamamos a la parte de la conexión como siempre con:

<%@include file="/WEB-INF/jspf/conexion.jspf" %>

Por ejemplo, el código completo de una página con una consulta simple sería:

index.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>Página JSP</title>
 </head>
 <body>
  <h1>¡Hola, mundo!</h1>

<%@include file="/WEB-INF/jspf/conexion.jspf" %>
<sql:transaction dataSource="${bdatos}">

 <c:catch var="ex">
  <sql:query var="encontrados">
   SELECT primer_nombre FROM persona LIMIT 4
  </sql:query>
 </c:catch>


 <c:choose>
  <c:when test="${not empty ex}">
   <p>Problema: <c:out value="${ex.message}"/></p>
  </c:when>
  <%-- Si no hubo ninguna excepción --%>
  <c:otherwise>


   <c:choose>

    <%-- Si encontró algo --%>
    <c:when test="${encontrados.rowCount>0}">
     <ol>
      <c:forEach items="${encontrados.rows}" var="persona">
       <li><c:out value="${persona.primer_nombre}" /></li>
      </c:forEach>
     </ol>


    </c:when>
    <c:otherwise>
     <p>No se encontraron datos.</p>
    </c:otherwise>
   </c:choose>

  </c:otherwise>
 </c:choose>
</sql:transaction>
 </body>
</html>

Ejecución

ver index.jsp.

Referencias

Artículos relacionados

Etiquetas: , , , ,

Publicidad