En esta oportunidad estoy liberando dos libros de Oracle
LIBROS DE ORACLE
Grabar Imagen en Base de Datos Utilizando JDBC
- NetBeans 6.9
- MySQL 5.1
Para este ejercicio se creará una aplicación de tipo Cliente/Servidor cuya interfaz se ilustra a continuación:
Para grabar una imagen en una base de datos MySQL debemos utilizar el tipo de dato BLOB, para este caso utilizaremos la tabla PRODUCTO cuya estructura se muestra a continuación:
+-----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+----------------+
| PRO_ID | int(11) | NO | PRI | NULL | auto_increment | | AUT_ID | int(11) | NO | MUL | NULL | | | CAT_ID | int(11) | NO | MUL | NULL | | | EDI_ID | int(11) | NO | MUL | NULL | | | PRO_NOMBRE | varchar(100) | NO | | NULL | | | PRO_DESCRIPCION | text | YES | | NULL | | | PRO_STOCK | int(11) | NO | | NULL | | | PRO_PRECIO | decimal(10,2) | NO | | NULL | | | PRO_FOTO | blob | YES | | NULL | | +-----------------+---------------+------+-----+---------+----------------+
9 rows in set (0.04 sec)
La clase entity para la tabla PRODUCTO quedaría implementada de la siguiente manera:
private int id;
private int autor;
private int categoria;
private int editorial;
private String nombre;
private String descripcion;
private int stock;
private double precio;
private byte[] foto;
// Implementar los métodos getters y setters
}
Para la columna de tipo blob se crea un campo de tipo ARRAY de BYTES.
El método que corresponde a la capa de persistencia que crea un nuevo producto en la base de datos se implementa de la siguiente manera:
package dao.componentes; import dao.database.AccesoDB; import dao.entity.Producto; import dao.interfaces.IProductoDAO; import excepcion.TiendaException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; public class ProductoDAO implements IProductoDAO { public void crear(Producto prod) throws TiendaException { Connection cn = null; PreparedStatement pstm = null; try { cn = AccesoDB.getConnection(); cn.setAutoCommit(false); String query = "insert into producto(AUT_ID,CAT_ID,EDI_ID,PRO_NOMBRE," + "PRO_DESCRIPCION,PRO_STOCK,PRO_PRECIO,PRO_FOTO) " + "values(?,?,?,?,?,?,?,?)"; pstm = cn.prepareStatement(query); pstm.setInt(1, prod.getAutor()); pstm.setInt(2, prod.getCategoria()); pstm.setInt(3, prod.getEditorial()); pstm.setString(4, prod.getNombre()); pstm.setString(5, prod.getDescripcion()); pstm.setInt(6, prod.getStock()); pstm.setDouble(7, prod.getPrecio()); pstm.setBytes(8, prod.getFoto()); pstm.executeUpdate(); cn.commit(); } catch (Exception e) { try { cn.rollback(); } catch (Exception e1) { } throw new TiendaException(e.getMessage()); } finally { try { pstm.close(); } catch (Exception e) { } } } . . . . . . }
Para acceder a la capa DAO se utiliza una capa model implementada de la siguiente manera:
package model; import dao.componentes.ProductoDAO; import dao.entity.Producto; import excepcion.TiendaException; import java.util.List; public class CatalogoModel { public void crearProducto( Producto prod) throws TiendaException{ new ProductoDAO().crear(prod); } . . . . . . }
Primero se debe seleccionar el archivo para lo cual se ha implementado el botón Buscar [...], el script es el siguiente:
private void btnBuscarFotoActionPerformed(java.awt.event.ActionEvent evt) { JFileChooser openFile = new JFileChooser(); int returnValue = openFile.showOpenDialog(this); if (returnValue == JFileChooser.CANCEL_OPTION) { return; } File archivo = openFile.getSelectedFile(); this.txtFoto.setText(archivo.getAbsolutePath()); ImageIcon tmp = new ImageIcon(archivo.getAbsolutePath()); ImageIcon imagen = new ImageIcon(tmp.getImage().getScaledInstance( this.lblFoto.getWidth(), this.lblFoto.getHeight(), Image.SCALE_DEFAULT)); this.lblFoto.setIcon(imagen); }
Y para grabar el registro en la base de datos se ha implementado el botón Grabar, el script es el siguiente:
private void btnGrabarActionPerformed(java.awt.event.ActionEvent evt) { try { Producto prod = new Producto(); prod.setAutor(listaAutores.get(cboAutor.getSelectedIndex()).getId()); prod.setCategoria(listaCategorias.get(cboCategoria.getSelectedIndex()).getId()); prod.setEditorial(listaEditoriales.get(cboEditorial.getSelectedIndex()).getId()); prod.setNombre(txtNombre.getText()); prod.setDescripcion(txtDescripcion.getText()); prod.setStock(Integer.parseInt(txtStock.getText())); prod.setPrecio(Double.parseDouble(txtPrecio.getText())); // Obtener la imagen File archivo = new File(this.txtFoto.getText()); byte[] imgFoto = new byte[(int) archivo.length()]; InputStream input = new FileInputStream(archivo); input.read(imgFoto); prod.setFoto(imgFoto); model.crearProducto(prod); utilitarios.Util.showMessage("Producto creado en la base de datos satisfactoriamente."); limpiarFormulario(); } catch (Exception e) { utilitarios.Util.showError("ERROR: " + e.getMessage()); } }
Para obtener la aplicación ejemplo utilice el siguiente enlace:
Descargar Código Fuente de la AplicaciónPatron MVC con PHP
El patrón MVC divide una aplicación Web en tres capas:
Vista: Se encarga de generar el HTML que se envía al browser.
Controlador: Recibe y procesa los requerimiento del usuario y comunica los resultados a la vista para que los envíe al browser.
Modelo: Implementa la lógica del negocio.
La siguiente figura muestra un diagrama de bloques del funcionamiento de este patrón.
Para este ejemplo estoy utilizando NetBeans 6.8.
El objetivo de este ejemplo es implementar una aplicación que permita realizar una suma o una multiplicación.
La estructura de la solución es la siguiente:
La clase Session se utiliza para manejar datos de sesión:
public static function existsAttribute($name){
$rpta = FALSE;
if( isset( $_SESSION[$name] ) ){
$rpta = TRUE;
}
return $rpta;
}
public static function getAttribute($name) {
$rpta = null;
if( self::existsAttribute($name) ){
$rpta = $_SESSION[$name];
}
return $rpta;
}
public static function getAttribute2($name) {
$rpta = null;
if( self::existsAttribute($name) ){
$rpta = $_SESSION[$name];
unset( $_SESSION[$name] );
}
return $rpta;
}
public static function setAttribute($name, $value) {
$_SESSION[$name] = $value;
}
}
La clase Matematica implementa la lógica, en este caso las dos operaciones: sumar y multiplicar.
public function suma($n1, $n2){
$su = $n1 + $n2;
return $su;
}
public function producto($n1, $n2) {
$pr = $n1 * $n2;
return $pr;
}
}
session_start();
require_once '../util/Session.php';
$n1 = Session::getAttribute2("num1");
$n2 = Session::getAttribute2("num2");
$rpta = Session::getAttribute2("rpta");
$action = Session::getAttribute2("action");
?>
<html>
<head>
<title>Operaciones Simples</title>
</head>
<body>
<h1>Operaciones Simples</h1>
<form method="post" action="../controller/Controller.php">
<div>
<label>Operacion</label>
<select name="action">
<option value="sumar">Suma</option>
<option value="multiplicar">Producto</option>
</select>
</div>
<div>
<label>Número 1</label>
<input type="text" name="num1">
</div>
<div>
<label>Número 2</label>
<input type="text" name="num2">
</div>
<div>
<input type="submit" value="Procesar">
</div>
</form>
<div>
<table>
<tr>
<td>Action :</td>
<td><?php echo($action); ?></td>
</tr>
<tr>
<td>Num 1 :</td>
<td><?php echo($n1); ?></td>
</tr>
<tr>
<td>Num 2 :</td>
<td><?php echo($n2); ?></td>
</tr>
<tr>
<td>Rpta :</td>
<td><?php echo($rpta); ?></td>
</tr>
</table>
</div>
</body>
</html>
En el programa tenemos un control de tipo SELECT, al que se le ha dado el nombre ACTION, este este control que comunica al controlador el método a ejecutar.
La clase Controller recibe los datos del formulario, entre ellos el método a ejecutar, hace uso del Model para resolver el problema y se comunica con el View para que genere el HTML que irá al browser.
El script de la clase controller es el siguiente:
session_start();
require_once '../model/Matematica.php';
require_once '../util/Session.php';
$action = $_REQUEST["action"];
$obj = new Controller();
$target = call_user_func(array($obj,$action));
header("location: $target");
return;
class Controller {
public function sumar() {
$n1 = $_REQUEST["num1"];
$n2 = $_REQUEST["num2"];
$mate = new Matematica();
$rpta = $mate->suma($n1, $n2);
Session::setAttribute("num1", $n1);
Session::setAttribute("num2", $n2);
Session::setAttribute("rpta", $rpta);
Session::setAttribute("action", "Sumar");
return "../view/main.php";
}
public function multiplicar() {
$n1 = $_REQUEST["num1"];
$n2 = $_REQUEST["num2"];
$mate = new Matematica();
$rpta = $mate->producto($n1, $n2);
Session::setAttribute("num1", $n1);
Session::setAttribute("num2", $n2);
Session::setAttribute("rpta", $rpta);
Session::setAttribute("action", "Multiplicar");
return "../view/main.php";
}
}
?>
Como podemos apreciar, la programación del controlador es bastante sencillo, el campo action podría ser un campo oculto en un formulario, incluso su valor puede ser manipulado con JavaScript y también se puede manejar con AJAX.
Patron de Diseño Singleton
Existen escenarios donde la aplicación solo necesita emplear una única instancia (objeto) de una clase, y esta instancia debe ser accesible desde diferentes partes del sistema.
Las clases que cumplen estas características suelen tener alguna de estas funciones:
- Controlar el acceso a un recurso que por su naturaleza no admite el acceso concurrente (impresora, socket, fichero).
- Obtener referencias de clases que actúan como servidoras de recursos (pool de conexiones).
- Ejecutar código carente de estado (si el estado no cambia solo necesitamos una instancia).
- Mantener un estado que debe ser globalmente único.
acterísticas porque:
- Controla el acceso al recipiente de la información de log.
- Toda la información del log se envía a través de un punto único.
- Su único estado es la configuración, que es global y no suele variar.
Necesitamos crear una instancia de un clase que sea accesible globalmente, y que sea única.
- Hacer que la clase provea una instancia de sí misma.
- Permitir que otros objetos obtengan esa instancia, mediante la llamada a un método de la clase.
- Declarar el constructor como privado, para evitar la creación de otros objetos.
Según la notación UML el número 1 en la esquina superior derecha, indica que solamente habrá una instancia de esta clase. El signo "-" en el constructor, lo señala como privado. Esto consigue que nadie aparte de la propia clase, pueda crear una instancia.
class Demo{ private static $instancia = null; public static function getInstancia(){ if( self::$instancia == null ){ self::$instancia = new Demo(); } return self::$instancia; } private function __construct() { } . . . . . . }Una segunda implementación considera la instanciación de la clase en la misma instrucción donde se declara la variable $instancia, tal como ilustra a continuación:
class Demo{ private static $instancia = new Demo(); public static function getInstancia(){ return self::$instancia; } private function __construct() { } . . . . . . }El acceso a la instancia se realiza de la siguiente manera:
$demo = Demo::getInstancia();
public class Demo{ private static Demo instancia = null; public static Demo getInstancia(){ if( instancia == null ){ instancia = new Demo(); } return instancia; } private Demo() { } . . . . . . }Una segunda implementación considera la instanciación de la clase en la misma instrucción donde se declara la variable instancia, tal como ilustra a continuación:
public class Demo{ private static Demo instancia = new Demo(); public static Demo getInstancia(){ return instancia; } private Demo() { } . . . . . . }El acceso a la instancia se realiza de la siguiente manera:
Demo demo = Demo.getInstancia();
ComentariosSi estamos en un ambiente de un solo hilo (single-thread) la primera implementación es suficiente. En contrapartida, tiene serios problemas en entornos multihilo (multi-thread) dado que, debido a cuestiones de sincronización y concurrencia, puede crearse más de una instancia. ¿Cómo puede ser esto posible? Imaginemos que dos hilos evalúan la condición $instancia == null ( en Java: instacia == null ) y en ambos casos es verdadera. En este caso, ambos hilos crearán la instancia, violando el propósito del patrón Singleton.
Para solucionar el problema de que existe la posibilidad de crear mas de una instancia en entornos multihilo puede utilizar la segunda implementación.