lunes, 24 de noviembre de 2008

Campos BLOB

En los post anteriores sobre insertar imágenes en una base de datos mediante una aplicación web o una stand alone mencionamos el tipo de dato BLOB, donde se almacena información en formato binario, este tipo de dato puede variar, varia de acuerdo a las bases de datos , y como lo apunta Danguer en su comentario podría darnos problemas si el archivo es mas grande de lo que nos permite guardar el tipo BLOB. Entonces hay que revisar si el motor de base de datos que estamos usando y su implementación de los BLOB estan de acuerdo a nuestras necesidades en otro caso seria mejor buscar otro tipo de dato como lo hizo Danguer que uso un tipo LONGBLOB

Bien les dejo una tablita tipos de datos BLOB de MySQL que muestra la capacidad de almacenamiento:

TINYBLOB, TINYTEXT L+1 byte, donde L <>
BLOB, TEXT L+2 bytes, donde L <>
MEDIUMBLOB, MEDIUMTEXT L+3 bytes, donde L <>
LONGBLOB, LONGTEXT L+4 bytes, donde L <>


En derby los datos BLOB se les puede asignar un tamaño, por default el tamaño es de 2 gb.


Mas informacion en:

http://dev.mysql.com/doc/refman/5.0/es/storage-requirements.html
http://db.apache.org/derby/docs/10.4/ref/ref-single.html

jueves, 20 de noviembre de 2008

OAS + JAAS

Hace unos días, tuve que usar el estándar de
seguridad Java (JAAS) para mayor referencia Click Aquí.
En esta ocasión para el servidor de aplicaciones
OAS.
En esta página puedes revisar a fondo
JAAS sobre OAS.Jaas sobre OAS

En esta ocasión solo definiré perfiles y usuarios
el archivo web.xml y su correspondiente en el archivo
jazn-data.xml por parte de OAS.


Los archivos que deben ser modificados para poder
implementar esta seguridad son los siguientes:

web.xml




Continua...

miércoles, 19 de noviembre de 2008

Insertar una imagen en una base de datos mediante una aplicacion stand alone

En la entrada anterior vimos como insertar una imagen en la base de datos en una app web, bueno el procedimiento anterior es aplicable a cualquier otro archivo ya que en donde se inserta es un dato de tipo BLOB es decir un archivo muy grande (bueno creo que es hasta 4gb) en modo binario, ahora veremos como hacerlo desde la aplicación stand alone o de escritorio (Esto lo pidieron en un comentario jejeje).

El proyecto lo hice en netbeans, Lo que necesitamos:

- Driver para la base de datos, (en mi caso es derbyclient.jar)
- Base de datos con soporte para datos BLOB
- Netbeans (opcional)

Tenemos la siguiente tabla (la definición corresponde a derby tal vez necesite adecuarse para MySql y/u otras) :

create table IMAGEN_T
(
ID_IMAGEN INTEGER not null primary key,
DESCRIPCION VARCHAR(100),
IMAGEN BLOB(1048576)
)

Para insertar las imágenes tenemos un DAO el cual contiene el método insertaImagen (aunque este método debe funcionar para cualquier archivo recordemos que el archivo se guarda en binario)

insertaImagen(String nameFile, int id)
throws FileNotFoundException, SQLException{

File fileIn = new File(nameFile);
InputStream fis = new FileInputStream(fileIn);
ps = conn.prepareStatement("INSERT INTO IMAGEN_T VALUES (?, ?, ?)");
ps.setInt(1,id);
ps.setString(2, "Probando insertar una imagen");
int fileLength = (int) fileIn.length();
System.out.println(" los datos " + fileLength + " fis " + fis.toString());
ps.setBinaryStream(3, fis, fileLength);
ps.executeUpdate();
ps.close();

}

En este método creamos un File con el nombre del archivo que recibe (el nombre contiene la ruta completa) para a su vez crear un FileInputStream que a su vez asignamos a un InputStream, con estos objetos se leerán los bytes del archivo, obtenemos un objeto PreparedStatment y colocamos el id para el registro, una descripción (aqui podria ser mejor guardar el nombre para cuando se necesite recuperar el archivo recuerden que esta app es solo un ejemplo) y posteriormente se realiza el setBinaryStream y le pasamos el objeto InputStream para que pueda leer los bytes y también le pasamos el tamaño del archivo es decir el numero de bytes que se tienen que leer.

A continuación tenemos el método que recupera el archivo:

recuperaImagenBD(int idImagen, String path)
throws IOException, SQLException{

FileOutputStream fos = null;
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs = null;
Statement st = null;
String sql = "SELECT IMAGEN FROM IMAGEN_T WHERE ID_IMAGEN = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, idImagen);

rs = ps.executeQuery();
if (rs.next()){

String pathname= path;
File file = new File(pathname);
fos = new FileOutputStream(file);
Blob bin = rs.getBlob("IMAGEN");
InputStream inStream = bin.getBinaryStream();
int size = (int)bin.length();
byte[] buffer = new byte[size];
int length = -1;
while ((length = inStream.read(buffer)) != -1) {
fos.write(buffer, 0, length);
}
}

}

En este método tenemos que crear un objeto FileOutputStream para poder escribir los bytes que nos retorna la consulta, a este objeto le pasamos un objeto file que ha sido creado con una ruta donde se guardara el archivo, después obtenemos el dato BLOB y de este obtenemos un objeto InputStream para leer los bytes, después obtenemos el numero de bytes del Blob, posteriormente creamos un arreglo de bytes en el que se leerán los bytes y de donde el outputStream obtendrá los bytes, le hice una pequeña ventanita para hacer pruebitas



En cuanto pueda colocare los proyectos en algun servicio de hostig, si alguien le intereas el codigo escriba un comentario con su mail para enviarselos.
Tal vez haya algunas mejoras en el código, espero sus comentarios ...

lunes, 17 de noviembre de 2008

Insertar imagenes en una base de datos en una aplicacion web

Que tal, en esta primer entrada veremos como insertar una imagen en la base de datos y también como recuperarla y mostrarla dentro de nuestra aplicación web. Para hacer esto, haremos uso de un par de jar's de jakarta-commons, no hay que re-inventar la rueda.

Lo que necesitamos:

- eclipse (con wtp para mayor comodidad)
- apache tomcat 6 (o algun otro contenedor de servlets)
- commons-fileupload-1.2.jar
- commons-io-1.3.1.jar
- mysql-connector-java-5.1.5-bin.jar (Este driver depende de su motor de base de datos)
- MySql 5.0.67 (Esta es la bd que uso, podrían ocupar cualquier otra que soporte datos BLOB)
- Opcionalmente: log4-1.2.11.jar, jstl.jar, standar.jar (las ultimas dos vienen en los ejemplos de apache-tomcat 6, en versiones anteriores se encuentran en el directorio lib de tomcat)

No es absolutamente necesario usar eclipse, podrían realizar el proyecto con algún otro ide o sin usar algún ide.

Para insertar la imagen realice el siguiente método que pertenece a mi DAO:

public void insertaImagenProducto(int idProducto,
InputStream inps, long size) {

PreparedStatement ps=null;
try {

ps = con.prepareStatement(
"UPDATE PRODUCTOS SET IMAGEN = ? WHERE" +
" PRODUCTO_ID = ?");

ps.setBinaryStream(1, inps, (int)size);
ps.setInt(2, idProducto);
ps.executeUpdate();
ps.close();

} catch (SQLException e) {

e.printStackTrace();
}
}


En el método de insertaImagen, únicamente recibo un InputStream del cual se leerán los bytes que se insertaran en el campo BLOB, tambien se recibe el tamaño del InputStream o el numero de bytes que contiene y finalmente se llama al método setBinaryStream del objeto preparedStatment con el cual se inserta la imagen en la bd

Para recuperar un dato BLOB de la bd se realiza lo siguiente:
public byte[] obtenImagenProducto(int idProducto)  {

ResultSet rst = null;
PreparedStatement pstm = null;
byte[] buffer = null;

try {
logger.info("Datos producto id " +idProducto);
String sql = "select imagen from
productos where producto_id = ?";
pstm = con.prepareStatement(sql);
pstm.setInt(1, idProducto);
rst = pstm.executeQuery();
while (rst.next()){
Blob bin = rst.getBlob("imagen");
if (bin != null) {
InputStream inStream = bin.getBinaryStream();
int size = (int) bin.length();
System.out.println(" El tamaño en bytes " + size);
buffer = new byte[size];
int length = -1;
int k = 0;
try {
inStream.read(buffer, 0, size);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

} catch (SQLException ex) {
logger.error("ERROR " + ex);
return null;
} finally {
/*
rst.close();
stm.close();
*/
rst = null;
pstm = null;
}
return buffer;
}
Este método obtiene un dato de tipo BLOB, si el dato es diferente de nulo entonces se crea un objeto de tipo InputStream con el cual se leerán los bytes del dato blob, se crea un arreglo de bytes de acuerdo al tamaño del blob y posteriormente se leen, una vez leídos los bytes estos simplemente se retornan en el arreglo creado, en la siguiente capa se reciben estos bytes y se envian al navegador.

Lo anterior es la parte que pertenece al modelo, ahora vamos con la parte correspondiente a la vista, en esta parte tenemos un jsp que contiene el siguiente formulario :

<form name="myform" action="./ServletProductoImagen"
method="post" enctype="multipart/form-data">

<input type="hidden" value="${param.idProducto}" name="idProducto">
Selecciona la Image:

<input type="file" name="myimage">

<input type="submit" name="Aceptar" value="Submit your files">
<form>
Bien con este formulario escogeremos el archivo que se agregara a la base de datos,
yo le paso un parámetro, el idProducto con este sabre en que registro insertar la imagen,

Ahora veamos el servlet que inserta la imagen, en el método post :
// first check if the upload request
//coming in is a multipart request
//Revisa si la peticion es multipart
boolean isMultipart = ServletFileUpload.isMultipartContent(request);

// Create a factory for disk-based file items
//Esto es parte de la lib de commons-fileupload
//y es un objeto para generar archivos temporales
FileItemFactory factory = new DiskFileItemFactory();

// Create a new file upload handler
//Aqui crea un objeto para manejar la peticion
//que llega con un archivo
ServletFileUpload upload = new ServletFileUpload(factory);


// parse this request by the handler
// this gives us a list of items from the request
List items = null;
try {
//Se obtienen los items de la forma
//es decir obtenemos los parametros de la forma
items = upload.parseRequest(request);
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String idProducto = "";
Iterator itr = items.iterator();
while(itr.hasNext()) {

//recorremos los items en busca del id
//para realizar el insert
FileItem item = (FileItem) itr.next();

if(item.isFormField()) {
// get the name of the field
String fieldName = item.getFieldName();

if(fieldName.equals("idProducto"))
idProducto = item.getString();
}
logger.info("ID Producto" + idProducto);
}
itr = items.iterator();
//ahora lo recorremos para obtener el archivo que se
//envio en la forma
while(itr.hasNext()) {
FileItem item = (FileItem) itr.next();

// check if the current item is a form field or
//an uploaded file
if(! item.isFormField() ){

// the item must be an uploaded file save it to disk.
// Note that there
// seems to be a bug in item.getName() as it
//returns the full path on
// the client's machine for the uploaded file name,
// instead of the file
// name only. To overcome that, I have used a
// workaround using
// fullFile.getName().
//Aqui es donde se obtiene el nombre del archivo, esto podriamos
//usarlo si queremos gurdar el nombre o guardar el archivo en
//alguno de nuestros directorios.
//File fullFile = new File(item.getName());
//File savedFile = new File(fullFile.getName());
try {
//Este metodo comentado escribe el archivo en nuestro
//sistema de archivos con una ruta adecuada
//item.write(savedFile);

//pero lo que nos interesa es gurdar la imagen en la bd, asi
//que invocamos a nuestro dao y le pasmos los valores
//necesarios y es todo
daoProductos.insertaImagenProducto(
Integer.parseInt(idProducto),
item.getInputStream(),
item.getSize());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

System.out.println("Archivo guardado");
}
}

RequestDispatcher r =
request.getRequestDispatcher("./index.jsp");

r.forward(request, response);
}
Aqui es donde hacemos uso de el jar commons-fileupload, con este obtenemos
el archivo que se envio al servlet a travez de la forma, revisamos por los
parametros que se encuentran en la forma, el id para saber el registro en
donde se insertara la imagen, posteriormente obtenemos un inputStream con los
bytes de la imagen y el numero de bytes. Y lo enviamos a nuestro dao para que
realize el insert en la bd.

Para terminar, para mostrar la imagen en nuestro jsp entonces invocamos al metodo
doGet de el servlet en el cual tenemos lo siguiente:
String idProducto = request.getParameter("idProducto");
System.out.println(" El id del idProducto " + idProducto);
if(idProducto!=null && !idProducto.equals("")){

int idProd = Integer.parseInt(idProducto);
response.setContentType("image/gif");
byte [] imag = this.obtieneProducto(idProd);
if(imag != null) {
ServletOutputStream out = response.getOutputStream();
out.write(imag);
}
}
Aqui le enviamos el id del registro del cual se obtendra la imagen despues colocamos el contentype del response como image, invocamos anuestro dao que nos devolvera los bytes, obtenemos el ServletOutputStream para enviar los bytes de la imagen, en nuestro jsp simplemente hariamos:
<img src="./ServletProductoImagen?idProducto=${producto.idProducto}"
alt="${producto.nombre}" height="150" width="150" >
Espero colocar el proyecto de eclipse para que puedan descargarlo solo debo ver como o donde