miércoles, 23 de mayo de 2012

Acceso a Bases de Datos

Todo sistema de información posee bases de datos para la persistencia de los datos. Para realizar una conexión es necesario utilizar un componente conocido como JDBC (Java Data Base Connector) el cual, debe proveer el creador del motor de base de datos que se desee utilizar. El JDBC está diseñado para ser independiente de la plataforma e incluso de la base de datos, de esta manera, la aplicación se comunica con el JDBC y este con la base de datos. Para manipular la base de datos desde la aplicación en Java, es necesario utilizar el lenguaje SQL (Structured Query Language).

Considerando un motor de base de datos MySql, se debe descargar el JDBC para mysql del sitio web http://dev.mysql.com. El JDBC es un componente embebido en un archivo .jar. Este archivo debe incluirse en el build path del proyecto para poder ser utilizado por la aplicación.

Conexion a Bases de Datos

Para realizar la conexión es necesario hacer uso de las clases Conection, Statement y DriverManager que hacen parte del paquete java.sql. Adicionalmente se debe conocer los siguientes parámetros:

  • JDBC. Es necesario conocer la clase que permite que el JDBC realice la conexión a la base de datos de acuerdo al motor seleccionado. Para MySql, la clase es com.mysql.jdbc.Driver.
  • Cadena de conexión. Esta cadena contiene información del jdbc, servidor, puerto y nombre de base de datos.
  • Usuario. El usuario debe ser incluido en la conexión para hacer uso de los diferentes servicios del motor de la base de datos.
  • Contraseña. Corresponde a la contraseña del usuario anterior.

La siguiente clase, muestra una forma de realizar la conexión con una base de datos en motor MySql.

package Persistencia;
import java.sql.*;

public class Conexion {

 private Statement statement;
 private Connection connection; 
 private String jdbc;
 private String ruta;
 private String usuario;
 private String contra;

 public Conexion(){
  this.connection = null;
  this.statement = null;
  this.jdbc = "com.mysql.jdbc.Driver";
  this.ruta = "jdbc:mysql://localhost:3306/videotienda";
  this.usuario ="root";
  this.contra ="";  
 } 

 private void abrirConexion(){
  try {
   Class.forName(this.jdbc);
   this.connection = DriverManager.getConnection(this.ruta,this.usuario, this.contra);
   this.statement = this.connection.createStatement();
  }catch (SQLException e){
   e.printStackTrace();
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
 }

 private void cerrarConexion(){
  try {
   this.connection.close();
  } 
  catch (SQLException e){
   e.printStackTrace();
  }
 }

 public String ejecutar(String sentencia){
  try {
   this.abrirConexion();
   this.statement.executeUpdate(sentencia);
   return "Op Exitosa";  
  }catch (SQLException e){   
   return e.toString();
  }finally{
   this.cerrarConexion();
  }
 }

 public ResultSet consultar(String sentencia){
  ResultSet resultado=null;
  try {
   this.abrirConexion();
   resultado=statement.executeQuery(sentencia); 
  }catch (SQLException e){
   e.printStackTrace();
  }
  return resultado;     
 }
}

En el método abrirConexión, permite que el atributo connection cree una conexión con la base de datos y que el atributo statement cree un objeto que permita enviar sentencias SQL a la base de datos. Para ello requiere de las siguientes características

  • El método estático forName de la clase Class, permite cargar a la aplicación el conector de la base de datos. Recibe el parámetro JDBC expuesto anteriormente.
  • El método estático getConnection de la clase DriverManager permite establecer una conexión a la base de datos a través del JDBC. Recibe como parámetro la cadena de conexión, el usuario y la contraseña.
  • El método createStatement de la clase Connection, crea un statement a través de la conexión establecida con la base de datos.
  • Es necesario realizar el manejo de las siguientes excepciones.
    • SQLException. Se produce si no es posible realizar una conexión a la base de datos con el servidor, usuario y contraseña especificados.
    • SQLException. Se produce si no es posible realizar una conexión a la base de datos con el servidor, usuario y contraseña especificados.

El método cerrarConexion, permite destruir todos los objetos que están involucrados en la conexión abierta.

El método ejecutar, permite enviar una sentencia SQL que recibe por parámetro, con base en la conexión abierta por medio del método excecuteUpdate. Esta sentencia debe ser necesariamente insert, update o delete. Este método debe manejar la excepción SQLException, la cual permite controlar casos de excepción como:

  • Agregación de un registro cuya llave primaria ya existe.
  • Eliminación de un registro que no existe
  • Actualización de un registro que no existe
  • Error de la sintaxis de la sentencia
  • Sentencia con una tabla de la base de datos que no existe.
  • Sentencia con una columna que no existe

El método consultar, permite enviar una sentencia SQL que recibe por parámetro, con base en la conexión abierta por medio del método excecuteQuery. Esta sentencia debe ser necesariamente select, debido a que retorna información a través de un objeto Resulset. Este método debe manejar la excepción SQLException, la cual permite controlar casos de excepción como:

  • Error de la sintaxis de la sentencia
  • Sentencia con una tabla de la base de datos que no existe.
  • Sentencia con una columna que no existe
DAO (Data Access Object)

DAO es un patrón de diseño de capa de persistencia que indica que se debe crear una clase por cada entidad creada en el modelo entidad relación de la base de datos. Esta clase debe mapear los atributos de la entidad y proporcionar única y exclusivamente métodos que construyan las sentencias sql requeridas para la manipulación de los datos. Con base en ello, cada clase DAO, implementa métodos altamente cohesionados con cada entidad.

Considerando una video tienda que contiene en su base de datos una entidad cliente con los atributos id, nombre y apellido, la clase DAO que mapea dicha entidad es la siguiente.

Clase ClienteDAO
package Persistencia;

public class ClienteDAO {

 private int id;
 private  String nombre;
 private  String apellido;
 
 public ClienteDAO(int id, String nombre, String apellido) {
  super();
  this.id = id;
  this.nombre = nombre;
  this.apellido = apellido;
 }

 public ClienteDAO(int id) {
  super();
  this.id = id;
 }

 public ClienteDAO() {
  super();
 } 

 public String insertar(){
  return "insert into cliente (id,nombre,apellido) values ('"+this.id+"', '"+this.nombre+"', '"+this.apellido+"')";
 }

 public String consultar(){
  return "select * from cliente where id='"+this.id+"'";
 }

 public String actualizar(){
  return "update cliente set nombre='"+this.nombre+"', apellido='"+this.apellido+"' where id='"+this.id+"'";
 }

 public String buscar(String filtro){
  return "select * from cliente where nombre like '"+filtro+"%' or apellido like '"+filtro+"%'";
 }

 public String eliminar(){
  return "delete from cliente where id='"+this.id+"'";
 } 
}

Esta clase posee tres atributos que son id, nombre y apellido que corresponde a la entidad de la base de datos. Además posee los siguientes métodos.

  • Método insertar, que retorna un String con la sentencia sql requerida para insertar un cliente en la base de datos.
  • Método consultar, que retorna un String con la sentencia sql requerida para consultar un cliente de la base de datos con base en su llave primaria que es id.
  • Método actualizar, que retorna un String con la sentencia sql requerida para actualizar un cliente de la base de datos con base en su llave primaria que es id.
  • Método buscar, que retorna un String con la sentencia sql requerida para consultar a través de la sentencia like un conjunto de clientes de la base de datos. El objetivo de una sentencia de esta característica, es obtener un conjunto de clientes filtrados por su nombre y/o apellido.
  • Método eliminar, que retorna un String con la sentencia sql requerida para eliminar un cliente de la base de datos con base en su llave primaria que es id.

Con base en la misma video tienda, también se debe presentar una entidad denominada administrador quien será el actor del sistema que tenga servicios de gestión como gestionar clientes, vendedores, películas, entre otros.

Así mismo debe presentar una entidad vendedor quien será el actor que tenga servicios de consulta y de alquiler.

Los atributos de cada uno de estos actores son id, nombre, apellido y contraseña. Su implementación es la siguiente

Clase AdministradorDAO
package Persistencia;

public class AdministradorDAO {

 private int id;
 private  String nombre;
 private  String apellido;
 private  String contra;
 
 public AdministradorDAO(int id, String nombre, String apellido) {
  super();
  this.id = id;
  this.nombre = nombre;
  this.apellido = apellido;
 }

 public AdministradorDAO(int id) {
  super();
  this.id = id;
 }

 public AdministradorDAO() {
  super();
 } 

 public AdministradorDAO(int id,String contra) {
  super();
  this.id = id;
  this.contra=contra;
 }
 
 public String autenticar(){
  return "select * from admin where id='"+this.id+"' and contra = md5('"+this.contra+"')";
 } 

 public String insertar(){
  return "insert into vendedor (id,nombre,apellido,contra) values ('"+this.id+"','"+this.nombre+"','"+this.apellido+"',md5('"+this.id+"'))";
 }

 public String consultar(){
  return "select * from vendedor where id='"+this.id+"'";
 }

 public String actualizar(){
  return "update vendedor set nombre='"+this.nombre+"', apellido='"+this.apellido+"' where id='"+this.id+"'";
 }

 public String actualizarContra(){
  return "update vendedor set contra=md5('"+this.contra+"') where id='"+this.id+"'";
 }

 public String buscar(String filtro){
  return "select * from vendedor where nombre like '"+filtro+"%' or apellido like '"+filtro+"%'";
 }

 public String eliminar(){
  return "delete from vendedor where id='"+this.id+"'";
 } 
}
Clase VendedorDAO
package Persistencia;

public class VendedorDAO {

 private int id;
 private  String nombre;
 private  String apellido;
 private  String contra;
 
 public VendedorDAO(int id, String nombre, String apellido) {
  super();
  this.id = id;
  this.nombre = nombre;
  this.apellido = apellido;
 }

 public VendedorDAO(int id) {
  super();
  this.id = id;
 }

 public VendedorDAO() {
  super();
 } 

 public VendedorDAO(int id,String contra) {
  super();
  this.id = id;
  this.contra=contra;
 }
 
 public String autenticar(){
  return "select * from vendedor where id='"+this.id+"' and contra = md5('"+this.contra+"')";
 }

 public String insertar(){
  return "insert into vendedor (id,nombre,apellido,contra) values ('"+this.id+"','"+this.nombre+"','"+this.apellido+"',md5('"+this.id+"'))";
 }

 public String consultar(){
  return "select * from vendedor where id='"+this.id+"'";
 }

 public String actualizar(){
  return "update vendedor set nombre='"+this.nombre+"', apellido='"+this.apellido+"' where id='"+this.id+"'";
 }

 public String actualizarContra(){
  return "update vendedor set contra=md5('"+this.contra+"') where id='"+this.id+"'";
 }

 public String buscar(String filtro){
  return "select * from vendedor where nombre like '"+filtro+"%' or apellido like '"+filtro+"%'";
 }

 public String eliminar(){
  return "delete from vendedor where id='"+this.id+"'";
 } 
}

Estas clases poseen cuatro atributos que son id, nombre, apellido y contraseña que corresponde a las entidades de la base de datos. Puede tener los mismos métodos que la clase cliente, sin embargo, por ser clases que hacen referencia a actores, deben tener un método de autenticación que retorna un String con la sentencia sql requerida para consultar un administrador o vendedor respectivamente en la base de datos con base en su llave primaria que es id y su contraseña que por motivos de seguridad siempre debe estar encriptada. En este caso la contraseña se encripta con el algoritmo md5. Adicionalmente, puede tener un método adicional para actualizar la contraseña, debido a que se recomienda que la contraseña se actualice en un servicio independiente para el usuario final.

Para hacer uso de los DAO, es necesario crear una capa de lógica, que permita crear instancias de las clases de la capa de persistencia. A través de estas instancias, se hace uso de los servicios que contiene la clase conexión y de los servicios de las clases DAO.

Con base en el caso de la video tienda, en donde hay clientes, administradores y vendedores, se puede crear en la capa de lógica una clase para cada concepto. Además, se puede crear una clase abstracta persona, con el fin de aplicar herencia.

La implementación es la siguiente.

Clase Persona
package Logica;

public abstract class Persona {
 
 protected int id;
 protected String nombre;
 protected String apellido;
 
 public Persona(int id, String nombre, String apellido) {
  super();
  this.id = id;
  this.nombre = nombre;
  this.apellido = apellido;
 }

 public Persona(int id) {
  super();
  this.id = id;
 }

 public Persona() {
  super();
 }

 public int getId() {
  return id;
 }
 
 public void setId(int id) {
  this.id = id;
 }
 
 public String getNombre() {
  return nombre;
 }
 
 public void setNombre(String nombre) {
  this.nombre = nombre;
 }
 
 public String getApellido() {
  return apellido;
 }
 
 public void setApellido(String apellido) {
  this.apellido = apellido;
 }

 public abstract String insertar();
 public abstract boolean consultar();
 public abstract String actualizar(); 
}

La clase Persona contiene tres atributos protegidos para que sean heredados por cliente, administrador y vendedor. Además contiene tres constructores sobrecargados en donde el primero recibe toda las información de la persona con el fin de agregar a la base de datos dicha información, el segundo contiene la identificación de la persona con el fin de consultar o eliminar dicha persona y el tercero no contiene parámetros con el fin de realizar la búsqueda de personas a través de un filtro. Contiene también todos los métodos consultores y modificadores de la clase. Finalmente contiene la definición de métodos abstractos para proporcionar los servicios para el acceso a la base de datos de la aplicación.

Clase Cliente
package Logica;

import java.sql.ResultSet;
import java.sql.SQLException;

import Persistencia.ClienteDAO;
import Persistencia.Conexion;

public class Cliente extends Persona {

 public Cliente(int id, String nombre, String apellido) {
  super(id, nombre, apellido);
 }
 
 public Cliente(int id) {
  super(id);  
 }

 public Cliente() {
  super();  
 }

 @Override
 public String insertar() {
  Conexion c = new Conexion();
  ClienteDAO clienteDAO = new ClienteDAO(this.id, this.nombre, this.apellido);
  return c.ejecutar(clienteDAO.insertar());   
 }

 public String eliminar() {
  Conexion c = new Conexion();
  ClienteDAO clienteDAO = new ClienteDAO(this.id);
  return c.ejecutar(clienteDAO.eliminar());   
 }

 @Override
 public boolean consultar() {
  Conexion c = new Conexion();
  ClienteDAO clienteDAO = new ClienteDAO(this.id);
  ResultSet resultado = c.consultar(clienteDAO.consultar());
  try {
   if (resultado.next()){
    this.nombre=resultado.getString("nombre");
    this.apellido=resultado.getString("apellido");
    return true;
   }else{
    return false;
   }
  } catch (SQLException e) {
   e.printStackTrace();
   return false;
  }
 }

 @Override
 public String actualizar() {
  Conexion c = new Conexion();
  ClienteDAO clienteDAO = new ClienteDAO(this.id, this.nombre, this.apellido);
  return c.ejecutar(clienteDAO.actualizar());   
 }
 
 public String[][] buscar(String filtro){
  Conexion con = new Conexion();
  ClienteDAO clienteDAO = new ClienteDAO();
  ResultSet resultado=con.consultar(clienteDAO.buscar(filtro));
  String [][] datos=null;
  try {
   resultado.last();  
   datos=new String[resultado.getRow()][3];
   resultado.beforeFirst();
   int i=0;
   while(resultado.next()){    
    datos[i][0]=resultado.getString("id");
    datos[i][1]=resultado.getString("nombre");
    datos[i][2]=resultado.getString("apellido");
    i++;
   }
  } catch (SQLException e) {
   e.printStackTrace();
  }
  return datos;  
 }
}

La clase Cliente, hereda de Persona y contiene tres constructores sobrecargados con el mismo objetivo de la clase Persona haciendo el llamado al respectivo constructor.

El método insertar, crea una instancia llamada c de la clase Conexión y otra instancia llamada clienteDAO de la clase ClienteDAO enviando por el constructor toda la información del cliente a través de sus atributos. Con el objeto c hace el llamado al método ejecutar en donde se envía por parámetro la sentencia SQL que retorna el método insertar de la clase ClienteDAO. Este método retorna un String que contiene el mensaje “Op Exitosa” en caso de realizar correctamente el proceso o un mensaje generado por el manejo de excepción en caso que falle el proceso.

El método eliminar, funciona de la misma forma que el método insertar, excepto por el hecho que solo envía la identificación por parámetro en el momento de crear la instancia de la clase ClienteDAO y utiliza el método eliminar de esta clase con el fin de ejecutar la sentencia SQL requerida para dicho proceso.

El método consultar, crea una instancia llamada c de la clase Conexión y otra instancia llamada clienteDAO de la clase ClienteDAO enviando por el constructor solamente la identificación del cliente. Con el objeto c hace el llamado al método consultar en donde se envía por parámetro la sentencia SQL que retorna el método consultar de la clase ClienteDAO. El método consultar de la clase Conexión, retorna un Resulset el cual contiene la información del cliente consultado. El método next de la clase Resulset, permite avanzar en el conjunto de registros retornado al realizar la consulta. Además, este método retorna verdadero si hay registros al avanzar y retorna falso si no hay registros al avanzar. Debido a que la consulta se hace a través de la llave primaria, se asegura que hay un registro en caso de que exista el cliente o cero registros en caso que no exista. Por tal motivo, la sentencia if(resultado.next()), permite identificar si hay o no registro y en caso de haberlo, permite asignar a los atributos de la clase la información obtenida de la base de datos con base en el método getString el cual recibe como parámetro el nombre de la columna en la tabla consultada de base de datos. En este caso es posible utilizar otros métodos como getInt, getDouble, conociendo el tipo de dato de la columna en la base de datos. Este método retorna verdadero en caso de encontrar el registro o falso en caso de no hacerlo.

El método actualizar, funciona de la misma forma que el método insertar, excepto por el hecho que utiliza el método actualizar de la clase ClienteDAO con el fin de ejecutar la sentencia SQL requerida para dicho proceso.

El método buscar, crea una instancia llamada c de la clase Conexión y otra instancia llamada clienteDAO de la clase ClienteDAO. Con el objeto c hace el llamado al método consultar en donde se envía por parámetro la sentencia SQL que retorna el método buscar de la clase ClienteDAO que recibe un String que contiene un filtro. El método consultar de la clase Conexión, retorna un Resulset el cual contiene la información del conjunto de clientes consultados. A diferencia del método consultar, el Resulset puede tener múltiples registros. Por tal motivo, la sentencia while(resultado.next()), permite a través de un proceso iterativo identificar si hay o no más registros y en caso de haberlos, permite asignar a una matriz la información obtenida de la base de datos con base en el método getString el cual recibe como parámetro el nombre de la columna en la tabla consultada de base de datos. Los métodos last y beforeFirst, se utilizan para conocer la cantidad de registros obtenido antes de iniciar el proceso iterativo con el fin de asignar el tamaño apropiado a la matriz. Este método hace el retorno de dicha matriz.

Clase Administrador
package Logica;

import java.sql.ResultSet;
import java.sql.SQLException;
import Persistencia.AdministradorDAO;
import Persistencia.Conexion;

public class Administrador extends Persona {
 private String contra;
 
 public Administrador(int id, String nombre, String apellido) {
  super(id, nombre, apellido);
 }
 
 public Administrador(int id) {
  super(id);  
 }

 public Administrador() {
  super();  
 }

 public Administrador(int id, String contra){
  super(id);
  this.contra=contra;
 }
 
 public boolean autenticar(){
  Conexion c = new Conexion();
  AdministradorDAO administradorDAO = new AdministradorDAO(this.id, this.contra);
  ResultSet resultado = c.consultar(administradorDAO.autenticar());
  try {
   if (resultado.next()){
    this.nombre=resultado.getString("nombre");
    this.apellido=resultado.getString("apellido");
    return true;
   }else{
    return false;
   }
  } catch (SQLException e) {
   e.printStackTrace();
   return false;
  }
 } 
 
 @Override
 public String insertar() {
  Conexion c = new Conexion();
  AdministradorDAO administradorDAO = new AdministradorDAO(this.id, this.nombre, this.apellido);
  return c.ejecutar(administradorDAO.insertar());   
 }

 @Override
 public boolean consultar() {
  Conexion c = new Conexion();
  AdministradorDAO administradorDAO = new AdministradorDAO(this.id);
  ResultSet resultado = c.consultar(administradorDAO.consultar());
  try {
   if (resultado.next()){
    this.nombre=resultado.getString("nombre");
    this.apellido=resultado.getString("apellido");
    return true;
   }else{
    return false;
   }
  } catch (SQLException e) {
   e.printStackTrace();
   return false;
  }
 }

 @Override
 public String actualizar() {
  Conexion c = new Conexion();
  AdministradorDAO administradorDAO = new AdministradorDAO(this.id, this.nombre, this.apellido);
  return c.ejecutar(administradorDAO.actualizar());   
 } 
}
Clase Vendedor
package Logica;

import java.sql.ResultSet;
import java.sql.SQLException;
import Persistencia.Conexion;
import Persistencia.VendedorDAO;

public class Vendedor extends Persona {
 private String contra;
 
 public Vendedor(int id, String nombre, String apellido) {
  super(id, nombre, apellido);
 }
 
 public Vendedor(int id) {
  super(id);  
 }

 public Vendedor() {
  super();  
 }

 public Vendedor(int id, String contra){
  super(id);
  this.contra=contra;
 }
 
 public boolean autenticar(){
  Conexion c = new Conexion();
  VendedorDAO vendedorDAO = new VendedorDAO(this.id, this.contra);
  ResultSet resultado = c.consultar(vendedorDAO.autenticar());
  try {
   if (resultado.next()){
    this.nombre=resultado.getString("nombre");
    this.apellido=resultado.getString("apellido");
    return true;
   }else{
    return false;
   }
  } catch (SQLException e) {
   e.printStackTrace();
   return false;
  }
 }
 
 
 @Override
 public String insertar() {
  Conexion c = new Conexion();
  VendedorDAO vendedorDAO = new VendedorDAO(this.id, this.nombre, this.apellido);
  return c.ejecutar(vendedorDAO.insertar());   
 }

 @Override
 public boolean consultar() {
  Conexion c = new Conexion();
  VendedorDAO vendedorDAO = new VendedorDAO(this.id);
  ResultSet resultado = c.consultar(vendedorDAO.consultar());
  try {
   if (resultado.next()){
    this.nombre=resultado.getString("nombre");
    this.apellido=resultado.getString("apellido");
    return true;
   }else{
    return false;
   }
  } catch (SQLException e) {
   e.printStackTrace();
   return false;
  }
 }

 @Override
 public String actualizar() {
  Conexion c = new Conexion();
  VendedorDAO vendedorDAO = new VendedorDAO(this.id, this.nombre, this.apellido);
  return c.ejecutar(vendedorDAO.actualizar());   
 }
}

Las clases Administrador y Vendedor tienen las mismas características. Además contiene los métodos sobre escritos insertar, consultar y actualizar que fueron implementados de la misma forma que en la clase Cliente, modificando el objeto DAO. Estas clases tienen un método adicional que es autenticar el cual permite hacer la consulta mediante su identificación y contraseña. Funciona de la misma forma que el método consultar, excepto por el hecho que al crear la instancia del DAO correspondiente, envía por parámetro la identificación y la contraseña. Además, hace el llamado al método autenticar del DAO correspondiente para enviar la cadena SQL requerida al método consultar de la clase Conexión. Finalmente retorna verdadero si encuentra registro o falso si no encuentra registro.

La capa de Presentación en el caso de la video tienda, debe incluir los frames necesarios para manipular las clases de la capa de Logica. Para demostrar el funcionamiento se presentan los siguientes frames:

  • Principal. Este Frame contiene dos cuadros de texto para realizar la autenticación.
  • Sesión Administrador. Este Frame contiene un menú que provee servicios de gestión de cliente como agregar, consultar y buscar
  • Sesión Vendedor. Este Frame contiene un menú que provee servicios de consulta de cliente y alquiler.
  • Agregar Cliente. Este Frame contiene el formulario para agregar cliente a la base de datos.
  • Consultar Cliente. Este Frame contiene un formulario en el cual se visualizar la información consultada de la base de datos. Además provee mecanismos para la actualización de los datos.
  • Buscar Cliente. Este Frame contiene una tabla en donde se presentan los registros encontrados basado es un filtro proporcionado.

La implementación de la capa de presentación es la siguiente.

Clase FPrincipal
package Presentacion;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.SwingUtilities;
import Logica.Administrador;
import Logica.Vendedor;

public class FPrincipal extends javax.swing.JFrame {
 private JPanel PAutenticacion;
 private JLabel jLabel2;
 private JButton BIngresar;
 private JPasswordField TContra;
 private JTextField TId;
 private JLabel jLabel1;

 public static void main(String[] args) {
  SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    FPrincipal inst = new FPrincipal();
    inst.setLocationRelativeTo(null);
    inst.setVisible(true);
   }
  });
 }
 
 public FPrincipal() {
  super();
  initGUI();
 }
 
 private void initGUI() {
  try {
   setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
   getContentPane().setLayout(null);
   this.setTitle("Video Tienda");
   {
    PAutenticacion = new JPanel();
    GridLayout PAutenticacionLayout = new GridLayout(3, 2);
    PAutenticacionLayout.setHgap(5);
    PAutenticacionLayout.setVgap(5);
    PAutenticacionLayout.setColumns(1);
    PAutenticacion.setLayout(PAutenticacionLayout);
    getContentPane().add(PAutenticacion);
    PAutenticacion.setBounds(26, 33, 239, 80);
    {
     jLabel1 = new JLabel();
     PAutenticacion.add(jLabel1);
     jLabel1.setText("Id");
    }
    {
     TId = new JTextField();
     PAutenticacion.add(TId);
    }
    {
     jLabel2 = new JLabel();
     PAutenticacion.add(jLabel2);
     jLabel2.setText("Contraseña");
    }
    {
     TContra = new JPasswordField();
     PAutenticacion.add(TContra);
    }
    {
     BIngresar = new JButton();
     PAutenticacion.add(BIngresar);
     BIngresar.setText("Ingresar");
     BIngresar.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
       BIngresarActionPerformed(evt);
      }
     });
    }
   }
   pack();
   this.setSize(300, 200);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
 private void BIngresarActionPerformed(ActionEvent evt) {
  Administrador administrador = new Administrador(Integer.parseInt(this.TId.getText()),String.valueOf(this.TContra.getPassword()));
  if(administrador.autenticar()){
   FSesionAdministrador form = new FSesionAdministrador(administrador.getNombre()+" "+administrador.getApellido());
   form.setVisible(true);
   this.setVisible(false);
  }else{
   Vendedor vendedor=new Vendedor(Integer.parseInt(this.TId.getText()),String.valueOf(this.TContra.getPassword()));
   if(vendedor.autenticar()){
    FSesionVendedor form = new FSesionVendedor(vendedor.getNombre()+" "+vendedor.getApellido());
    form.setVisible(true);
    this.setVisible(false);    
   }else{
    JOptionPane.showMessageDialog(this, "Usuario o contra incorrecta","Error de autenticacion", JOptionPane.ERROR_MESSAGE);
    this.TContra.setText("");    
   }   
  }
 }
}

Este Frame, realiza la autenticación al hacer clic en el botón ingresar, de la siguiente forma.

  • Crea un objeto instancia de la clase Administrador enviando por el constructor el parámetro de identificación y de contraseña.
  • Hace el llamado al método autenticar. Si retorna verdadero, crea una instancia del Frame FSesionAdministrador enviando por parámetro el nombre y apellido obtenido de la consulta de autenticación.
  • Si retorna falso el llamado al método autenticar de la clase Administrador, Crea un objeto instancia de la clase Vendedor enviando por el constructor el parámetro de identificación y de contraseña.
  • Hace el llamado al método autenticar. Si retorna verdadero, crea una instancia del Frame FSesionVendedor enviando por parámetro el nombre y apellido obtenido de la consulta de autenticación.
  • Si retorna falso el llamado al método autenticar de la clase Vendedor, muestra un cuadro de mensaje con el texto “Usuario o contraseña incorrecta”.

El frame se presenta de la siguiente forma.

Clase FSesionVendedor
package Presentacion;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JDesktopPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.WindowConstants;

public class FSesionVendedor extends javax.swing.JFrame {
 private JMenuBar MBMenu;
 private JMenu MCliente;
 private JDesktopPane DPContenedor;
 private JMenuItem MIBuscarCliente;
 private JMenuItem MIAgregarAlquilerº;
 private JMenu MAlquiler;
 private JMenuItem MIConsultarCliente;

 public FSesionVendedor(String nombre) {
  super();
  initGUI();
  this.setTitle(this.getTitle()+" "+nombre);
 }
 
 private void initGUI() {
  try {
   setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
   BorderLayout thisLayout = new BorderLayout();
   getContentPane().setLayout(thisLayout);
   this.setTitle("VIDEO TIENDA. Vendedor:");
   {
    DPContenedor = new JDesktopPane();
    getContentPane().add(DPContenedor, BorderLayout.CENTER);
   }
   {
    MBMenu = new JMenuBar();
    setJMenuBar(MBMenu);
    {
     MCliente = new JMenu();
     MBMenu.add(MCliente);
     MCliente.setText("Cliente");
     {
      MIConsultarCliente = new JMenuItem();
      MCliente.add(MIConsultarCliente);
      MIConsultarCliente.setText("Consultar");
      MIConsultarCliente.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent evt) {
        MIConsultarClienteActionPerformed(evt);
       }
      });
     }
     {
      MIBuscarCliente = new JMenuItem();
      MCliente.add(MIBuscarCliente);
      MIBuscarCliente.setText("Buscar");
      MIBuscarCliente.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent evt) {
        MIBuscarClienteActionPerformed(evt);
       }
      });
     }
    }
    {
     MAlquiler = new JMenu();
     MBMenu.add(MAlquiler);
     MAlquiler.setText("Alquiler");
     {
      MIAgregarAlquilerº = new JMenuItem();
      MAlquiler.add(MIAgregarAlquilerº);
      MIAgregarAlquilerº.setText("Agregar");
     }
    }
   }
   pack();
   setSize(800, 600);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
  
 private void MIConsultarClienteActionPerformed(ActionEvent evt) {
  FIConsultarCliente form = new FIConsultarCliente();
  this.DPContenedor.add(form);
 }
 
 private void MIBuscarClienteActionPerformed(ActionEvent evt) {
  FIBuscarCliente form = new FIBuscarCliente();
  this.DPContenedor.add(form);
 }
}

Este Frame, recibe por constructor el nombre del vendedor autenticado y lo muestra en la barra de titulo. Tiene una barra de menú con los servicios consultar cliente, buscar cliente y agregar alquiler.

El frame se presenta de la siguiente forma.

Clase FSesionAdministrador
package Presentacion;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JDesktopPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.WindowConstants;

public class FSesionAdministrador extends javax.swing.JFrame {
 private JMenuBar MBMenu;
 private JMenu MCliente;
 private JDesktopPane DPContenedor;
 private JMenuItem MIBuscarCliente;
 private JMenuItem MIConsultarCliente;
 private JMenuItem MIAgregarCliente;

 
 public FSesionAdministrador(String nombre) {
  super();
  initGUI();
  this.setTitle(this.getTitle()+" "+nombre);
 }
 
 private void initGUI() {
  try {
   setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
   BorderLayout thisLayout = new BorderLayout();
   getContentPane().setLayout(thisLayout);
   this.setTitle("VIDEO TIENDA. Administrador:");
   this.setPreferredSize(new java.awt.Dimension(500, 400));
   {
    DPContenedor = new JDesktopPane();
    getContentPane().add(DPContenedor, BorderLayout.CENTER);
   }
   {
    MBMenu = new JMenuBar();
    setJMenuBar(MBMenu);
    {
     MCliente = new JMenu();
     MBMenu.add(MCliente);
     MCliente.setText("Cliente");
     {
      MIAgregarCliente = new JMenuItem();
      MCliente.add(MIAgregarCliente);
      MIAgregarCliente.setText("Agregar");
      MIAgregarCliente.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent evt) {
        MIAgregarClienteActionPerformed(evt);
       }
      });
     }
     {
      MIConsultarCliente = new JMenuItem();
      MCliente.add(MIConsultarCliente);
      MIConsultarCliente.setText("Consultar");
      MIConsultarCliente.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent evt) {
        MIConsultarClienteActionPerformed(evt);
       }
      });
     }
     {
      MIBuscarCliente = new JMenuItem();
      MCliente.add(MIBuscarCliente);
      MIBuscarCliente.setText("Buscar");
      MIBuscarCliente.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent evt) {
        MIBuscarClienteActionPerformed(evt);
       }
      });
     }
    }
   }
   pack();
   this.setSize(500, 400);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
 private void MIAgregarClienteActionPerformed(ActionEvent evt) {
  FIAgregarCliente form = new FIAgregarCliente();
  this.DPContenedor.add(form);
 }
 
 private void MIConsultarClienteActionPerformed(ActionEvent evt) {
  FIConsultarCliente form = new FIConsultarCliente();
  this.DPContenedor.add(form);
 }
 
 private void MIBuscarClienteActionPerformed(ActionEvent evt) {
  FIBuscarCliente form = new FIBuscarCliente();
  this.DPContenedor.add(form);
 }
}

Este Frame, recibe por constructor el nombre del administrador autenticado y lo muestra en la barra de título. Tiene una barra de menú con los servicios agregar cliente, consultar cliente, y buscar cliente.

El frame se presenta de la siguiente forma.

Clase FAgregarCliente
package Presentacion;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import Logica.Cliente;

public class FIAgregarCliente extends javax.swing.JInternalFrame {
 private JPanel PFormulario;
 private JTextField TNombre;
 private JButton BLimpiar;
 private JButton BAgregar;
 private JTextField TApellido;
 private JLabel jLabel3;
 private JLabel jLabel2;
 private JTextField TID;
 private JLabel jLabel1;
 
 public FIAgregarCliente() {
  super();
  initGUI();
 }
 
 private void initGUI() {
  try {
   setPreferredSize(new Dimension(400, 300));
   this.setBounds(0, 0, 400, 300);
   setVisible(true);
   getContentPane().setLayout(null);
   this.setTitle("Agregar Cliente");
   this.setClosable(true);
   {
    PFormulario = new JPanel();
    getContentPane().add(PFormulario, "Center");
    GridLayout jPanel1Layout = new GridLayout(4, 1);
    jPanel1Layout.setHgap(10);
    jPanel1Layout.setVgap(10);
    jPanel1Layout.setColumns(1);
    jPanel1Layout.setRows(4);
    PFormulario.setLayout(jPanel1Layout);
    PFormulario.setBounds(85, 52, 245, 129);
    {
     jLabel1 = new JLabel();
     PFormulario.add(jLabel1);
     jLabel1.setText("ID");
    }
    {
     TID = new JTextField();
     PFormulario.add(TID);
    }
    {
     jLabel2 = new JLabel();
     PFormulario.add(jLabel2);
     jLabel2.setText("Nombre");
    }
    {
     TNombre = new JTextField();
     PFormulario.add(TNombre);
    }
    {
     jLabel3 = new JLabel();
     PFormulario.add(jLabel3);
     jLabel3.setText("Apellido");
    }
    {
     TApellido = new JTextField();
     PFormulario.add(TApellido);
    }
    {
     BAgregar = new JButton();
     PFormulario.add(BAgregar);
     BAgregar.setText("Agregar");
     BAgregar.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
       BAgregarActionPerformed(evt);
      }
     });
    }
    {
     BLimpiar = new JButton();
     PFormulario.add(BLimpiar);
     BLimpiar.setText("Limpiar");
     BLimpiar.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
       BLimpiarActionPerformed(evt);
      }
     });
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
 private void BAgregarActionPerformed(ActionEvent evt) {
  Cliente cliente = new Cliente(Integer.parseInt(this.TID.getText()), this.TNombre.getText(), this.TApellido.getText());
  JOptionPane.showMessageDialog(this, cliente.insertar(), "Insertar", JOptionPane.INFORMATION_MESSAGE);
  this.BLimpiarActionPerformed(evt);
 }
 
 private void BLimpiarActionPerformed(ActionEvent evt) {
  this.TID.setText("");
  this.TNombre.setText("");
  this.TApellido.setText("");
 }
}

Este Frame, contiene un formulario que permite ingresar la información del cliente a la base de datos a través del botón Agregar. Si ingresa el cliente correctamente presenta un cuadro de mensaje con el texto “Op Exitosa”

El frame se presenta de la siguiente forma.

Los resultados de la base de datos dejan evidencia que se hizo la operación correctamente. Para visualizar los resultados se puede hacer uso de la siguiente sentencia ejecutada directamente en el motor de la base de datos que para este caso es MySql.

SELECT * FROM cliente

Los resultados son los que se presentan en la siguiente figura.

Clase FConsultarCliente
package Presentacion;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import Logica.Cliente;


public class FIConsultarCliente extends javax.swing.JInternalFrame {
 private JPanel PFormulario;
 private JTextField TNombre;
 private JButton BActualizar;
 private JButton BConsultar;
 private JTextField TApellido;
 private JLabel jLabel3;
 private JLabel jLabel2;
 private JTextField TID;
 private JLabel jLabel1;
 private String idConsultado="";
 

 public FIConsultarCliente() {
  super();
  initGUI();
 }
 
 private void initGUI() {
  try {
   setPreferredSize(new Dimension(400, 300));
   this.setBounds(0, 0, 400, 300);
   setVisible(true);
   getContentPane().setLayout(null);
   this.setTitle("Consultar Cliente");
   this.setClosable(true);
   {
    PFormulario = new JPanel();
    getContentPane().add(PFormulario, "Center");
    GridLayout jPanel1Layout = new GridLayout(4, 1);
    jPanel1Layout.setHgap(10);
    jPanel1Layout.setVgap(10);
    jPanel1Layout.setColumns(1);
    jPanel1Layout.setRows(4);
    PFormulario.setLayout(jPanel1Layout);
    PFormulario.setBounds(85, 52, 245, 129);
    {
     jLabel1 = new JLabel();
     PFormulario.add(jLabel1);
     jLabel1.setText("ID");
    }
    {
     TID = new JTextField();
     PFormulario.add(TID);
     TID.addKeyListener(new KeyAdapter() {
      public void keyReleased(KeyEvent evt) {
       TIDKeyReleased(evt);
      }
     });
    }
    {
     jLabel2 = new JLabel();
     PFormulario.add(jLabel2);
     jLabel2.setText("Nombre");
    }
    {
     TNombre = new JTextField();
     PFormulario.add(TNombre);
    }
    {
     jLabel3 = new JLabel();
     PFormulario.add(jLabel3);
     jLabel3.setText("Apellido");
    }
    {
     TApellido = new JTextField();
     PFormulario.add(TApellido);
    }
    {
     BConsultar = new JButton();
     PFormulario.add(BConsultar);
     BConsultar.setText("Consultar");
     BConsultar.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
       BConsultarActionPerformed(evt);
      }
     });
    }
    {
     BActualizar = new JButton();
     PFormulario.add(BActualizar);
     BActualizar.setText("Actualizar");
     BActualizar.setBounds(202, 153, 117, 24);
     BActualizar.setEnabled(false);
     BActualizar.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
       BActualizarActionPerformed(evt);
      }
     });
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
 private void BConsultarActionPerformed(ActionEvent evt) {
  Cliente cliente = new Cliente(Integer.parseInt(this.TID.getText()));
  if(cliente.consultar()){
   this.TNombre.setText(cliente.getNombre());
   this.TApellido.setText(cliente.getApellido());
   this.BActualizar.setEnabled(true);
   this.idConsultado=this.TID.getText();
   
  }else{
   JOptionPane.showMessageDialog(this, "No hay resultados", "Consultar", JOptionPane.INFORMATION_MESSAGE);
   
  }
 }
 
 private void BActualizarActionPerformed(ActionEvent evt) {
  Cliente cliente = new Cliente(Integer.parseInt(this.TID.getText()), this.TNombre.getText(), this.TApellido.getText());
  JOptionPane.showMessageDialog(this, cliente.actualizar(), "Actualizar", JOptionPane.INFORMATION_MESSAGE);
 }
 
 private void TIDKeyReleased(KeyEvent evt) {
  this.BActualizar.setEnabled(false);
  if(this.idConsultado.equals(this.TID.getText())){
   this.BActualizar.setEnabled(true);
  }
 }
}

Este Frame, contiene un formulario que permite visualizar la información consultada. Posee un botón de actualizar que permite modificar la información a través de los cuadros de texto del formulario.

El frame se presenta de la siguiente forma.

Clase FBuscarCliente
package Presentacion;

import java.awt.Dimension;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import Logica.Cliente;

public class FIBuscarCliente extends javax.swing.JInternalFrame {
 private JTextField TFiltro;
 private JTable TResultados;
 private JScrollPane SPTabla;

 public FIBuscarCliente() {
  super();
  initGUI();
 }
 
 private void initGUI() {
  try {
   setPreferredSize(new Dimension(400, 300));
   this.setBounds(0, 0, 400, 300);
   setVisible(true);
   this.setTitle("Buscar Cliente");
   getContentPane().setLayout(null);
   this.setClosable(true);
   {
    TFiltro = new JTextField();
    getContentPane().add(TFiltro, "North");
    TFiltro.setBounds(112, 12, 178, 21);
    TFiltro.addKeyListener(new KeyAdapter() {
     public void keyReleased(KeyEvent evt) {
      TFiltroKeyReleased(evt);
     }
    });
   }
   {
    SPTabla = new JScrollPane();
    getContentPane().add(SPTabla, "Center");
    SPTabla.setBounds(36, 45, 327, 211);
    {
     TResultados = new JTable();
     SPTabla.setViewportView(TResultados);
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 
 private void TFiltroKeyReleased(KeyEvent evt) {
  Cliente cliente = new Cliente();
  String [][] datos = cliente.buscar(this.TFiltro.getText());
  String [] titulos = new String[] { "Id", "Nombre", "Apellido"};
  TableModel TResultadosModel = new DefaultTableModel(datos, titulos);
  TResultados.setModel(TResultadosModel);
  TResultados.setPreferredSize(new java.awt.Dimension(350,datos.length*16));
  TableRowSorter ordenador=new TableRowSorter(TResultadosModel);
  this.TResultados.setRowSorter(ordenador);  
 }
}

Este Frame, contiene una tabla que permite visualizar todos los clientes. Adicionalmente tiene un cuadro de texto que permite filtrar la información de clientes de acuerdo con el texto incluido de tal forma que visualizara en la tabla todos los resultados en donde el nombre o apellido del cliente inicie por el texto colocado.

El frame con todos los clientes registrados en la base de datos se presenta en la siguiente figura.

Al aplicar un filtro, por ejemplo la letra “p”, solo se mostrarían los registros correspondientes al código 20 y código 40.

Además haciendo clic en el nombre de la columna, se ordena los resultados gracias al uso de la clase TableRowSorter.

2 comentarios:

  1. Profesor! excelente entrada, no tuve la oportunidad
    de ver clase con ud en la UD pero me hubiera gustado mucho , el profesor podría ayudarme con hibernate con varios compañeros estamos intentando usarlo pero no hemos podido, de antemano muchas gracias

    ResponderEliminar
    Respuestas
    1. Claro que puedo ayudarles con ese tema. Tal vez publique una entrada con hibernate. De hecho, puede encontrar informacion en el siguiente articulo "arquitectura multicapa usando ajax y orm"

      Eliminar