sábado, 24 de marzo de 2012

Tutorial : Crear Nuestras Clases Controladoras - Parte 6



La clases controladoras nos permiten encapsular las funcionalidades e interactuar con nuestras clases dominio, independiente de la interface, gráfica, dado que estas son las que le entregan a las interfaces la data a mostrar.



Creamos un paquete denominado control y dentro especificamos nuestras clases controladoras, si gustan pueden usar alguna nomenclatura especial para identificarlas, para este ejemplo simplemente escogeremos la palabra Control como sufijo de nuestras clases.
Así tenemos por ejemplo para la administración de Productos, una clase ProductoControl, con métodos como crear(), editar() y borrar().
Pero antes vamos a hacer un pequeño cambio en nuestra aplicación para facilitarnos ciertas pruebas antes de pasar a hacer nuestra interface.
Primero si ha seguido el Tutorial, sabran que tenemos una BD Stand Alone y cuyo esquema es generado por nuestra aplicación, bueno debemos evitar que cada vez que se ejecute la aplicación se vuelva a generar y perdamos nuestros datos, para esto modificamos nuestro método crearDB así :

public void crearDB() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException, SQLException {
        //Revisamos si no ha sido creada previamiente la BD
        File archivoDB = new File(DB_URL + ".h2.db");
        if (!archivoDB.exists()) {
            //ejecutamos el script de creacion de la BD
            String createTables = leerSqlFile();
            Class.forName(DRIVER).newInstance();
            Connection con = DriverManager.getConnection("jdbc:h2:" + DB_URL, "sa", "sa");
            java.sql.Statement stm = con.createStatement();
            stm.execute(createTables);
            stm.close();
            con.close();
        }
Logger.getLogger(H2Util.class.getName()).log(Level.INFO,"La BD ya fue creada previamiente");
    }



El cambio es generar un objeto File llamado archivoDB, al momento de instanciarlo hemos definido la ruta que tiene y la extensión del archivo .h2.db, en caso no exista se procede a generar la base.
Para certificar que todo funciona, he realizado una escritura en un log utilizando la clase Logger, esto se mostrará en nuestra Output Window


También crearemos una clase Aplicacion, la cual nos va a permitir realizar operaciones sin incluirlas directamente en nuestro void main().. De manera que nuestro código quede asi :

public static void main(String[] args) {
       Aplicacion app=new Aplicacion();
       app.creardb();
       app.pruebas();
    }
Y nuestra clase Aplicacion tendrá el siguiente código :

public void creardb(){
         try {
            H2Util.getInstance().crearDB();
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Minitienda.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(Minitienda.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(Minitienda.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Minitienda.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException ex) {
            Logger.getLogger(Minitienda.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void pruebas(){        
        try {
            //Crear un producto
            Producto p=new Producto();
            p.setCodigo("000123");
            p.setDescripcion("Este es un producto");
            p.setPrecio(new BigDecimal(15.36));
            
            ProductoControl.crear(p);

            //Asumismos para el test que como es nuestro primer producto el id=1
            p.setPrecio(new BigDecimal(17.36));
            ProductoControl.editar(p, 1);
            
            //Crear un producto
            Producto p2=new Producto();
            p2.setCodigo("000123");
            p2.setDescripcion("Este es un producto");
            p2.setPrecio(new BigDecimal(15.36));
            
            ProductoControl.crear(p2);
            
            //asumimos que es el producto con id=2 el ultimo que hemos creado
            ProductoControl.borrar(2);
            
        } catch (SQLException ex) {
            Logger.getLogger(Aplicacion.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }

Como verá ya hemos puesto el código para probar nuestra clase Controladora ProductoControl, cuyo código es el siguiente:

public class ProductoControl {

    public static void crear(Producto producto) throws SQLException {
        PreparedStatement psmt = H2Util.getInstance().getPreparedStatement(H2Util.getInstance().queryInsert(Producto.class));
        psmt.setString(1, producto.getCodigo());
        psmt.setString(2, producto.getDescripcion());
        psmt.setBigDecimal(3, producto.getPrecio());
        H2Util.getInstance().executePsmt(psmt);
    }

    public static void editar(Producto producto, int id) throws SQLException {
        PreparedStatement psmt = H2Util.getInstance().getPreparedStatement(H2Util.getInstance().queryUpdate(Producto.class));
        psmt.setString(1, producto.getCodigo());
        psmt.setString(2, producto.getDescripcion());
        psmt.setBigDecimal(3, producto.getPrecio());
        psmt.setInt(3, id);
        H2Util.getInstance().executePsmt(psmt);
    }

    public static void borrar(int id) throws SQLException {
        String query = "delete from Producto where id=" + id;
        H2Util.getInstance().executeQuery(query);
    }
}


Vamos a explicar un poco el código empleado y tomaremos como ejemplo el método crear
Lo hemos definido como método estático para no tener que instanciar la clase ProductoControl, el único parámetro que se le envía es un objeto de la clase Producto, este método nos arroja una excepción tipo SQL, esto es si existe un error por ejemplo en la conexión o la consulta.

public static void crear(Producto producto) throws SQLException {


La api SQL de J2SE posee una clase PreparedStatement la cual nos permite ejecutar sentencias o consultas, y al mismo tiempo haciendo un cache de las mismas, asi como proveyendo de la facilidad de utilizar sentencias con parámetros, por ejemplo, como verán acá no se ve el código Sql, esto es porque lo he puesto en un método de la clase H2Util, sino el código debiera ser :
insert into Producto (codigo, descripcion, precio) values (?, ?, ?);
Los caracteres ? Son comodines que indican la posición de los parámetros.

PreparedStatement psmt = H2Util.getInstance().getPreparedStatement(H2Util.getInstance().queryInsert(Producto.class));

El valor de los parámetros se asigna mediante los métodos setXXX, donde las XXX es el tipo de variable que contiene el valor, asi si el parámetro es del tipo String entonces se utiliza setString, el primer valor es la posición o índice del parámetro y el siguiente el valor en si.

psmt.setString(1, producto.getCodigo());
 psmt.setString(2, producto.getDescripcion());
 psmt.setBigDecimal(3, producto.getPrecio());

Por último ejecutamos nuestra sentencia.

H2Util.getInstance().executePsmt(psmt);
    }


Como habrán visto varias cosas se han encapsulado dentro de H2Util, aclaro esto dista de ser la mejor solución pero al menos da una idea de como facilitarnos el trabajo.
Así por ejemplo para no tener que estar haciendo manualmente todos nuestros querys como INSERT o UPDATE, he creado unos métodos que aprovechan el Api Reflection de Java, el cual nos permite conocer como está compuesta una clase en tiempo de ejecución, asi he agregado el siguiente código a nuestra clase H2Util


/**
     * 
     * @param clase
     * @return una cadena conteniendo el query INSERT INTO
     */
    public String queryInsert(Class clase) {
        StringBuilder query = new StringBuilder();
        query.append("insert into ").append(clase.getSimpleName());

        StringBuilder comodin = new StringBuilder();
        StringBuilder fields = new StringBuilder();
        for (Field f : clase.getDeclaredFields()) {
            if (!f.getName().equals("id")) {
                fields.append(f.getName()).append(",");
                comodin.append("?,");
            }
        }
        query.append(" (").append(fields.toString().substring(0, fields.length() - 1)).append(")");
        query.append(" values (").append(comodin.toString().substring(0, comodin.toString().length() - 1)).append(")");

        return query.toString();

    }
    
    /**
     * 
     * @param clase
     * @return una cadena conteniendo el query UPDATE
     */
    
    public String queryUpdate(Class clase){
        StringBuilder query = new StringBuilder();
        query.append("update ").append(clase.getSimpleName()).append(" set ");

        StringBuilder fields = new StringBuilder();
        for (Field f : clase.getDeclaredFields()) {
            if (!f.getName().equals("id")) {
                fields.append(f.getName()).append("=?,");
            }
        }
        query.append(fields.toString().substring(0, fields.length() - 1)).append(" where id=?");

        Logger.getLogger(H2Util.class.getName()).log(Level.OFF, query.toString());
        
        return query.toString();
    }



Tener en cuenta que por eso las clases del dominio tienen su campos denominados de igual forma que lo son en sus respectivas tablas.
También habrán visto que utilizo otro método de ayuda para ejecutar el PreparedStatement, este es su código.

/**
     * ejecuta un PreparedStatement previamente definido
     */
    public void executePsmt(PreparedStatement psmt) throws SQLException {
        psmt.executeUpdate();
        //cerramos el psmt y su conexion
        psmt.getConnection().close();
        psmt.close();        
    }


Esto no quiere decir que necesariamente hay que estar haciendo esto con cada query que se nos ocurra ejemplo de ello es el método borrar

public static void borrar(int id) throws SQLException {
        String query = "delete from Producto where id=" + id;
        H2Util.getInstance().executeQuery(query);
    }

Y bueno ahora comprobaremos que lo que he puesto aquí es correcto, ejecutamos nuestra aplicación y …


Utilizamos el QueryBrowser  descrito antes, aquí podrán ver el editor SQL que provee.


 Viene de :

Creacion de Aplicación Java J2SE Swing con Netbeans IDE 7

1 comentario:

  1. amigo puedes poner mas imagenes como hacerlo porque una imagen no sale el del principio si te das cuenta ayudame como hacerlo por favor

    ResponderEliminar

 
Powered by Blogger