Crear tu Primera Aplicación Web Real con Tomcat 4 y MySQL

La aplicaci�n Web utilizada para demostrar las tecnolog�as usadas en este tutorial es una simple aplicaci�n de control de una librer�a (solo control y ubicaci�n de los libros, no hay facturaci�n, por ejemplo), llamada Libreria . No es el prop�sito de este tutorial crear una aplicaci�n completa, es s�lo un ejemplo.

Libreria tiene tres clases Java:

  • libreria.ContextListener es un oyente del contexto servlet al que Tomcat llamar� cuando inicie y detenga la aplicaci�n Libreria. Esta clase crea un objeto de la clase LibrosBD y lo almacena como un atributo de contexto con el nombre BaseDatos
  • libreria.LibrosBD es una clase que representa la base de datos de libros. Su constructor establece una conexi�n a la base de datos (utilizando el objeto LibrosBD que se obtiene del atributo de contexto BaseDatos), y la sesi�n se puede compartir entre varias sesiones web. La clase proporciona varios m�todos de acceso a la base de datos (para insertar, borrar, modificar u obtener registros de la base de datos).
  • libreria.Libro es una clase Java que representa un libro. Las p�ginas JSP de la aplicaci�n utilizan esta clase como un Bean contenedor de datos para mostrarlos.

.�libreria.ContextListener

libreria.ContextListener es un oyente del contexto servlet al que se llamar� cuando arranque y cuando se pare la aplicaci�n Libreria. Esto se configura en el descriptor de despliegue de la aplicaci�n web.xml. Cuando se arranca la aplicaci�n Libreria se crea un ejemplar de la clase LibrosBD y se almacena como un atributo de contexto; cuando se cierra la aplicaci�n, el objeto LibrosBD se recupera del atributo de contexto y se cierra la conexi�n con la base de datos. Entre tanto, las JSP recuperan el objeto LibrosBD del atributo de contexto siempre que necesitan acceder a la base de datos.

.�Prop�sito de la clase ContextListener

El prop�sito de la clase Java libreria.ContextListener es crear un ejemplar de libreria.LibrosBD y almacenarlo como un atributo del contexto servlet identificado como: "BaseDatos". Esto permitir� a las p�ginas JSP recuperar el ejemplar de libreria.LibrosBD y acceder a la tabla Libros.

libreria.ContextListener est� configurado como un oyente de contexto servlet en el fichero web.xml.

.�M�todos de la clase ContextListener

  • contextInitialized

    Se llama a contextInitialized siempre que la aplicaci�n web arranca.

    Primero se recupera el contexto servlet desde el evento de contexto servlet:

        ServletContext servletContext = servletContextEvent.getServletContext ();

    Luego se crea un ejemplar de LibrosBD y se graba en el contexto servlet identificado como: "BaseDatos". Si este proceso lanza una excepci�n se guarda un log:

        try {
            LibrosBD LibrosBD = new LibrosBD ();
            servletContext.setAttribute ("BaseDatos", LibrosBD);
        } 
        catch (Exception e)  {
            servletContext.log ("No se pudo crear el atributo BaseDatos: " + e.getMessage());
        }
    
  • contextDestroyed

    Se llama a contextDestroyed cuando se cierra la aplicaci�n web.

    Primero se recupera el contexto servlet desde el evento ServletContexto:

        ServletContext servletContext = servletContextEvent.getServletContext ();

    Luego se recupera el objeto LibrosBD desde el contexto y se cierra la base de datos:

        LibrosBD LibrosBD = (LibrosBD) servletContext.getAttribute ("BaseDatos");
        LibrosBD.close ();
    

    Luego se elimina el atributo del contexto servlet:

        servletContext.removeAttribute ("BaseDatos"); 

.�C�digo Fuente Completo de la clase ContextListener

//
//  ContextListener.java
//

package libreria;

import javax.servlet.*;

public final class ContextListener implements ServletContextListener {
    public void contextInitialized (ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.getServletContext ();
        try {
            LibrosBD LibrosBD = new LibrosBD ();
            servletContext.setAttribute ("BaseDatos", LibrosBD);
        }
        catch (Exception e) {
            servletContext.log ("No se pudo crear el atributo BaseDatos: " + e.getMessage ());
        }
    }

    public void contextDestroyed (ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.getServletContext ();
        LibrosBD LibrosBD = (LibrosBD) servletContext.getAttribute ("BaseDatos");
        LibrosBD.close ();
        servletContext.removeAttribute ("BaseDatos");
    }
}

.�libreria.LibrosBD

libreria.LibrosBD es una clase que representa la base de datos de libros. Su constructor establece una conexi�n a la base de datos, y la sesi�n se puede compartir entre varias sesiones web. La clase proporciona varios m�todos de acceso a la base de datos.

.�Prop�sito de la clase LibrosBD

El prop�sito de la clase libreria.LibrosBD es establecer una conexi�n a la base de datos p�blica y proporcionar m�todos para acceder de forma segura y actualizar la tabla Libros contenida en la base de datos sin conflictos con otros usuarios que est�n accediendo a los mismos datos.

S�lo hay una conexi�n a la base de datos que es compartida por todos los usuarios de la aplicaci�n Web Libreria. Esto es adecuado mientras el n�mero de usuarios concurrentes no sea excesivo. Vamos a mantenerlo lo m�s simple posible, s�lo debemos a�adir soporte para varias conexiones si es realmente necesario. Observa, sin embargo, que si vamos a realizar esas complejidades, es en esta clase Java donde debemos hacerlas.

.�M�todos de la Clase LibrosBD

  • Constructor de LibrosBD:

    Establece una conexi�n a la base de datos p�blica.

    Hasta hace poco, si quer�amos establecer una conexi�n a una base de datos desde un Servlet bajo Tomcat ten�amos que codificar el driver JDBC, la URL de la base de datos, y el nombre de usuario y su password dentro del Servlet de esta forma:

        Class.forName ("org.gjt.mm.mysql.Driver").newInstance ();
        connection = DriverManager.getConnection ("jdbc:mysql://localhost/MiBase", 
                              "mysqlusername", "mysqlpassword");
    

    No es buena idea codificar dicha informaci�n en el c�digo fuente de la aplicaci�n. Tomcat 4 resuelve este problema permitiendo al Servlet acceder a Tomcat y recuperar una conexi�n desde el DataSource que se define en el fichero Libreria.xml, como veremos m�s adelante.

    Primero se recupera el javax.naming.InitialContext para que se pueda realizar una b�squeda JNDI:

        InitialContext initialContext = new InitialContext ();

    Despu�s se recupera el contexto de la aplicaci�n Libreria:

        Context envContext = (Context) initialContext.lookup ("java:comp/env");

    Luego se recupera el propio DataSource:

        DataSource dataSource = (DataSource) envContext.lookup ("jdbc/biblioteca");

    Y por �ltimo se recupera la conexi�n desde el DataSource:

        this.connection = dataSource.getConnection ();

    Todos los par�metros del DataSource tenemos que definirlos en el fichero Libreria.xml (que veremos m�s adelante), aunque tambi�n se pueden modificar usando las facilidades de administraci�n de Tomcat, con la direcci�n http://localhost:8080/admin .

  • getConnection

    Se utilizan los m�todos getConnection y releaseConnection para asegurarse de que la conexi�n a la base de datos se puede compartir de forma segura, el recurso de la conexi�n se controla utilizando los m�todos sincronizados getConnection y releaseConnection.

    Primero getConnection espera hasta que se libera la conexi�n:

        while (this.connectionFree == false)  {
            try {
                wait ();
            }
            catch (InterruptedException e)  {
            }
        }
    

    Luego marca el indicador de conexi�n libre como no libre, as� bloquea la conexi�n hasta que se llame a releaseConnection:

        this.connectionFree = false;

    Luego se lo notifica a cualquier otro thread de LibrosBD que est� esperando una conexi�n:

        notify ();

    Finalmente devuelve la conexi�n:

        return this.connection;
  • releaseConnection

    Primero espera hasta que la conexi�n est� ocupada:

        while (this.connectionFree == true) {
            try {
                wait ();
            }
            catch (InterruptedException e) {
            }
        }
    

    Luego selecciona el indicador de conexi�n libre a libre, as� desbloquea la conexi�n hasta que se llame a getConnection:

        this.connectionFree = true;

    Finalmente se lo notifica a cualquier otro thread de LibrosBD que est� esperando una conexi�n:

        notify ();

    Todas las dem�s rutinas que acceden a la base de datos emplean getConnection y releaseConnection, para que s�lo pueda acceder a la base de datos un thread a la vez.

  • getLibro

    El m�todo getLibro toma un par�metro id y devuelve el Libro para ese id; si no se puede encontrar ese id se devuelve un Libro null.

    getLibro primero obtiene una conexi�n libre

        this.getConnection ();

    Luego crea una sentencia select, e inserta el id en la posici�n adecuada:

        PreparedStatement preparedStatement = 
            this.connection.prepareStatement ("SELECT * FROM Libros WHERE id = ?");
        preparedStatement.setString (1, id);
    

    Luego ejecuta la sentencia:

        ResultSet resultSet = preparedStatement.executeQuery ();

    Si la sentencia select devuelve datos, se ensambla un objeto Libro con los datos, se cierra la consulta sql; se libera la conexi�n se devuelve el objeto Libro:

        if (resultSet.next ()) {
            Libro libro = new Libro (
                resultSet.getString (1), resultSet.getString (2), resultSet.getString (3),
                resultSet.getString (4), resultSet.getString (5), resultSet.getString (6), 
                resultSet.getString (7)
            );
            preparedStatement.close ();
            this.releaseConnection ();
            return libro;
        }
    

    Si la sentencia select no devuelve datos, se cierra la sentencia, se libera la conexi�n, y se devuelve un objeto Libro null:

        else {
            preparedStatement.close ();
            this.releaseConnection ();
            return null;
        }
    
  • insertarLibro, borrarLibro, modificarLibro, y obtenerLibros

    Todos estos m�todos utilizan una t�cnica similar a la del m�todo getLibro

  • close

    close simplemente cierra la conexi�n:

        this.connection.close ();

.�C�digo Fuente Completo de la clase LibrosBD

//
//  LibrosBD.java
//

package libreria;

import java.sql.*;
import java.util.*;
import javax.sql.*;
import javax.naming.*;

public class LibrosBD {
    Connection connection;
    private boolean connectionFree = true;
    private ArrayList libros;

    public LibrosBD () throws Exception {
        try {
            InitialContext initialContext = new InitialContext ();
            Context envContext = (Context) initialContext.lookup ("java:comp/env");
            DataSource dataSource = (DataSource) envContext.lookup ("jdbc/biblioteca");
            this.connection = dataSource.getConnection ();
        }
        catch (Exception e) {
            throw new Exception ("No se pudo abrir la base de datos biblioteca: " + e.getMessage ());
        }
    }

    protected synchronized Connection getConnection () {
        while (this.connectionFree == false) {
            try {
                wait ();
            }
            catch (InterruptedException e) {
            }
        }
        this.connectionFree = false;
        notify ();
        return this.connection;
    }

    protected synchronized void releaseConnection () {
        while (this.connectionFree == true) {
            try {
                wait ();
            }
            catch (InterruptedException e) {
            }
        }
        this.connectionFree = true;
        notify ();
    }

    public Libro getLibro (String id) {
        try {
            this.getConnection ();
            PreparedStatement preparedStatement = this.connection.prepareStatement 
              ("SELECT id, isbn, editorial, autor, categoria, titulo, ubicacion FROM libros" + 
               " WHERE id = ?");
            preparedStatement.setString (1, id);
            ResultSet resultSet = preparedStatement.executeQuery ();
            if (resultSet.next ()) {
                Libro libro = new Libro (
                    resultSet.getString (1), resultSet.getString (2), resultSet.getString (3),
                    resultSet.getString (4), resultSet.getString (5), resultSet.getString (6),  
                    resultSet.getString (7)
                );
                preparedStatement.close ();
                this.releaseConnection ();
                return libro;
            }
            else {
                preparedStatement.close ();
                this.releaseConnection ();
                return null;
            }
        }
        catch (SQLException e) {
            this.releaseConnection ();
            return null;
        }
    }

    public int insertarLibro (Libro libro) {
        int rowsAffected = 0;
        try {
            this.getConnection ();
            PreparedStatement preparedStatement = this.connection.prepareStatement 
                 ("INSERT INTO libros (isbn, editorial, autor, categoria, titulo, " + 
                  " ubicacion) VALUES (?, ?, ?, ?, ?, ?)");
            preparedStatement.setString (1, libro.getIsbn ());
            preparedStatement.setString (2, libro.getEditorial ());
            preparedStatement.setString (3, libro.getAutor ());
            preparedStatement.setString (4, libro.getCategoria ());
            preparedStatement.setString (5, libro.getTitulo ());
            preparedStatement.setString (6, libro.getUbicacion ());
            rowsAffected = preparedStatement.executeUpdate ();
            preparedStatement.close ();
            this.releaseConnection ();
        }
        catch (SQLException e) {
            this.releaseConnection ();
            return 0;
        }
        return rowsAffected;
    }

    public int borrarLibro (String id){
        int rowsAffected = 0;
        try {
            this.getConnection ();
            PreparedStatement preparedStatement = 
                this.connection.prepareStatement ("DELETE FROM libros WHERE id = ?");
            preparedStatement.setString (1, id);
            rowsAffected = preparedStatement.executeUpdate ();
            preparedStatement.close ();
            this.releaseConnection ();
        }
        catch (SQLException e) {
            this.releaseConnection ();
            return 0;
        }
        return rowsAffected;
    }

    public int modificarLibro (Libro libro) {
        int rowsAffected = 0;
        try {
            this.getConnection ();
            PreparedStatement preparedStatement = 
              this.connection.prepareStatement ("UPDATE libros SET isbn=?, editorial=?," +
                 " autor=?, categoria=?, titulo=?, ubicacion=? WHERE id =?");
            preparedStatement.setString (1, libro.getIsbn ());
            preparedStatement.setString (2, libro.getEditorial ());
            preparedStatement.setString (3, libro.getAutor ());
            preparedStatement.setString (4, libro.getCategoria ());
            preparedStatement.setString (5, libro.getTitulo ());
            preparedStatement.setString (6, libro.getUbicacion ());
            preparedStatement.setString (7, libro.getId ());
            rowsAffected = preparedStatement.executeUpdate ();
            preparedStatement.close ();
            this.releaseConnection ();
        }
        catch (SQLException e) {
            this.releaseConnection ();
            return 0;
        }
        return rowsAffected;
    }

    public Collection getLibros () {
        libros = new ArrayList ();
        try {
            this.getConnection ();
            PreparedStatement preparedStatement = this.connection.prepareStatement 
                  ("SELECT id, isbn, editorial, autor, categoria, titulo, ubicacion FROM libros");
            ResultSet resultSet = preparedStatement.executeQuery ();
            while (resultSet.next ()) {
                Libro libro = new Libro (
                    resultSet.getString (1), resultSet.getString (2), resultSet.getString (3),
                    resultSet.getString (4), resultSet.getString (5), resultSet.getString (6), 
                    resultSet.getString (7)
                );
                libros.add (libro);
            }
            preparedStatement.close ();
        }
        catch (SQLException e) {
            return null;
        }
        this.releaseConnection ();

        return libros;
    }

    public void close () {
        try {
            this.connection.close ();
        }
        catch (SQLException e) {
            System.out.println (e.getMessage ());
        }
    }

}

.�libreria.Libro

libreria.Libro es una clase Java que representa un libro. Las clases que recolectan datos todav�a son una buena idea cuando se programan JSPs, por eso esta clase es una buena idea para la aplicaci�n Libreria.

El constructor de libreria.Libro almacena los campos del libro en el objeto. Esta clase tambi�n incluye los habituales m�todos get para recuperar los datos del libro:

  • Libro(String id, String isbn, String editorial, String autor, String categoria,
    String titulo, String ubicacion)
  • getId()
  • getIsbn()
  • getEditorial()
  • getAutor()
  • getCategoria()
  • getTitulo()
  • getUbicacion()

.�Prop�sito de la clase Libros

El prop�sito de esta clase es recolectar los datos relativos a un libro de nuestra base de datos.

.�M�todos de la clase Libros

  • Constructor de la clase Libro

    El constructor almacena los campos suministrados del libro:

            this.id = id;
            this.isbn = isbn;
            this.editorial = editorial;
            this.autor = autor;
            this.categoria = categoria;
            this.titulo = titulo;
            this.ubicacion = ubicacion;
    
  • getId, getIsbn, getEditorial, getAutor, getCategoria, getTitulo y getUbicacion

    Estos m�todos devuelven los distintos campos que componente un libro.

.�C�digo Fuente Completo de la clase Libro

//
//  Libro.java
//

package libreria;

public class Libro {
    private String id = null;
    private String isbn = null;
    private String editorial = null;
    private String autor = null;
    private String categoria = null;
    private String titulo = null;
    private String ubicacion = null;

    public Libro (String id, String isbn, String editorial, 
       String autor, String categoria, String titulo, String ubicacion)  {
        this.id = id;
        this.isbn = isbn;
        this.editorial = editorial;
        this.autor = autor;
        this.categoria = categoria;
        this.titulo = titulo;
        this.ubicacion = ubicacion;
    }

    public String getId () {
        return this.id;
    }

    public String getIsbn () {
        return this.isbn;
    }

    public String getEditorial () {
        return this.editorial;
    }

    public String getAutor () {
        return this.autor;
    }

    public String getCategoria () {
        return this.categoria;
    }

    public String getTitulo () {
        return this.titulo;
    }

    public String getUbicacion () {
        return this.ubicacion;
    }

}

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR