====== Mapear BFILES con Hibernate ====== En esta wiki se va a describir cómo mapear tipos de datos **BFILE** de Oracle para trabajar directamente con ficheros en Hibernate/JPA. Un **BFILE** no es un fichero, es un **puntero a un fichero** que se encuentra en un directorio gestionado por Oracle. ===== Guía detallada ===== Ficheros que intervienen en el mapeo: * **FundeWebOracle10gDialect**: Dialect para registrar los types de Oracle. __Librería fundeweb-hibernate a partir de las versiones: [1.5.107 , 2.0.13, 2.0.111]__. * **BFileToByteArrayType**: type para trabajar directamente con byte[] en la entidad. * **BFileType**: type para trabajar con OracleBfile en la entidad. * **PreventRemove**: Listener básico para prevenir que no se borren los registros de la entidad (si se borra un bfile/puntero puede dejar un fichero huérfano en los directorios de la bbdd). __Librería fundeweb-jpa a partir de las versiones: [1.5.113 , 2.0.18, 2.0.103].__ ===== Configuración y uso ===== De momento esta configuración solo es válida para la **LECTURA** de BFILEs. \\ === 1. Fichero persistence.xml === \\ Sustituir la propiedad **hibernate.dialect** por: \\ === 2. Entidad === - Anotar la entidad que contiene la columna BFILE con: @EntityListeners( PreventRemove.class ) \\ Elegir una de las siguientes opciones para mapear el BFILE en la entidad. - __**[OPCIÓN A]** Si el formato de los ficheros a recuperar es **conocido y siempre es el mismo**__: * Declarar la columna del BFILE como **byte[]** private byte[] fichero; * Anotar el **get** de la columna con: @Column( name = "[NOMBRE_COLUMNA]", updatable = false, insertable = false ) @Type( type = "es.um.atica.hibernate.type.BFileToByteArrayType" ) public byte[] getFichero() { return fichero; } \\ - __**[OPCIÓN B]** Si el formato de los ficheros a recuperar **no es conocido o puede variar**__: * Declarar la columna como **oracle.jdbc.OracleBfile** private OracleBfile fichero; * Anotar el **get** de la columna con: @Column( name = "[NOMBRE_COLUMNA]", updatable = false, insertable = false ) @Type( type = "es.um.atica.hibernate.type.BFileType" ) public OracleBfile getFichero() { return fichero; } * Crear un método //Transient// para obtener el byte[]: //Ejemplo con columna 'fichero' @Transient public byte[] getFicheroBytes() throws SQLException { byte[] result = null; try { if ( this.fichero != null && this.fichero.fileExists() ) { this.fichero.openFile(); java.io.ByteArrayOutputStream bao = new java.io.ByteArrayOutputStream(); java.io.InputStream in = this.fichero.getBinaryStream(); byte[] buffer = new byte[1024]; int len = -1; while ( ( len = in.read( buffer, 0, buffer.length ) ) > -1 ) { bao.write( buffer, 0, len ); bao.flush(); } bao.close(); result = bao.toByteArray(); this.fichero.closeFile(); } } catch ( Exception ex ) { throw new SQLException( "Could not read OracleBfile:", ex ); } return result; } * Crear un método //Transient// para obtener el nombre del fichero: //Ejemplo con columna 'fichero' @Transient public String getFicheroName() throws SQLException { String result = null; if ( this.fichero != null && this.fichero.fileExists() ) { result = this.fichero.getName(); } return result; } \\ === 3. Manejador === __Ejemplo con columna byte[] en FundeWeb 2.0 (OPCIÓN A)__ //ejemplo simplificado con entidad 'f' y columna 'fichero' InputStream stream = new ByteArrayInputStream( f.getFichero() ); StreamedContent fileDownload = new DefaultStreamedContent( stream, "application/pdf", "miFichero.pdf"); \\ __Ejemplo con columna OracleBfile en FundeWeb 2.0 (OPCIÓN B)__ //ejemplo simplificado con entidad 'f' y columna 'fichero' InputStream stream = new ByteArrayInputStream( f.getFicheroBytes() ); String mimeType = java.net.URLConnection.guessContentTypeFromName( f.getFicheroName() ); StreamedContent fileDownload = new DefaultStreamedContent( stream, mimeType, f.getFicheroName() ); \\ Como se puede observar, la configuración de la OPCIÓN A es más simple. \\ Como contrapartida, tendremos que gestionar desde el manejador el nombre y el mimetype del fichero a descargar. \\ Esta configuración es **OPCIONAL** cuando el tipo de archivo apuntado es **fijo y conocido**. \\ \\ La configuración de la OPCIÓN B, no es tan directa como la anterior, pero permite recuperar desde base de datos tanto el nombre como la extensión del fichero apuntado por el BFILE.\\ Esta configuración es **OBLIGATORIA** cuando el tipo de archivo apuntado **puede variar**.\\ Esta configuración es **OPCIONAL** cuando el tipo de archivo apuntado es **fijo y conocido**. Se deja a criterio del programador usar una opción de mapeo u otra. === 4. Permisos a los directorios === Para poder acceder a los ficheros desde los diferentes entornos de nuestra aplicación habrá que solicitar, via **JIRA** a **SISTEMAS** (proyecto **BD - DJ-AT-SIST-BD**), \\ permisos de **lectura** para el usuario **JV_** de nuestra aplicación a los **directorios apuntados por los BFILEs**.\\ Pueden encontrarse los directorios apuntados haciendo una consulta a la tabla que contiene el BFILE. \\ El BFILE aparecerá con formato: bfilename('DIRECTORIO','NOMBRE_FICHERO'). \\ Ante cualquier duda al respecto, poneos en contacto con MNCS. ===== Referencias ===== [[https://wiki.um.es/wikis/programador/doku.php?id=plsql:pl_sql#lobs_tips | LOBs tips]] [[https://wiki.um.es/wikis/programador/doku.php?id=plsql:blob_a_bfile&s[]=bfile | PASO DE BLOBs A BFILEs.]] [[https://wiki.um.es/wikis/programador/doku.php?id=plsql:bfile_fundeweb&s[]=bfile | Trabajo con bfile]] ---- --- //[[ramon.ginel@ticarum.es|RAMON GINEL GEA]] 01/02/2021 13:19//