Encabezados, pie de pagina y conteo de paginas en iText 7

Estándar

Recientemente la librería iText ha liberado su nueva versión la 7.0.2 y en algo que honestamente espero no se haga costumbre (aunque hay mal precedente si recuerda el cambio de la versión 4 a la 5…) las clases y varios de los métodos han sido re escritos desde cero, ¿Como le afecta esto? pues si quiere hacer uso de la versión mas reciente toca hacer una reescritura significativa ya que la versión 5 y 7 no son compatibles entre si y no espere que los ejemplos previos le ayuden.

Esto es particularmente latoso si ya estaba creando encabezado y conteos de pagina como se había descrito en este blog previamente (para la versión 5 de iText), pero no desespere, aquí esta como hacerlo en iText 7

Documento pdf con encabezado y pie de pagina

Documento pdf con encabezado y pie de pagina

En esta entrada veremos como usar iText 7 y el nuevo modelo de eventos para crear un encabezado con un mensaje personalizable y un pie de pagina con el numero de pagina actual, para evitar confundirlo si no a usado iText antes y que esta entrada sea demasiado larga, no se haran comparaciones con la versión anterior y nos enfocaremos en como hacerlo en iText 7.

Agregando iText 7 a su proyecto

Configuración Maven de iText 7

Configuración Maven de iText 7

Para este ejemplo usaremos Maven para agregar las librerias al proyecto, puede usar ya sea el pom.xml o agregar la dependencia itext7-core via NetBeans en este ejemplo usaremos la versión 7.0.2.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>mx.hashSoft</groupId>
    <artifactId>iText7</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>7.0.2</version>
            <type>pom</type>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>
</project>

Eventos de documento

El ejemplo que usaremos para explicar el uso de iText 7 es bastante sencillo, crea un documento pdf el cual solo contendrá lineas y lineas de “Hola Mundo!” y que tendrá un encabezado con el mensaje “Departamento de Recursos Humanos” y un pie de pagina con el numero de pagina actual.

El pie de pagina y encabezado son creados por una clase que implementa la interfaz IEventHandler esta clase se agrega como manejador de evento al objecto documento y se indica cual evento manejara, de modo que se pueden tener múltiples clases manejando diferentes eventos en el mismo documento.

En este caso particular manejaremos el evento PdfDocumentEvent.END_PAGE el cual se activa cuando se llega al final de la pagina, en este punto agregamos el encabezado, pie de pagina y obtendremos el numero de pagina en el que vamos.

Canvas y rectángulos

Al ver el código de la clase EventoPagina seguramente notara que aparte de las tablas que contienen el texto que deseamos mostrar notara que se crean varios objectos Canvas y Rectangle estos cumplen una función muy simple ya que nos permiten colocar los objectos Table donde queramos, sin mover los demás elementos, el objeto Rectangle indica el área donde colocaremos la tabla y con el objecto Canvas lo dibujaremos en ese lugar.

Código

Ahora si vamos a lo bueno, para este ejemplo usaremos dos clases la ya mencionada EventoPagina la cual manejara el evento PdfDocumentEvent.END_PAGE e iText7 esta clase crea el documento Pdf y su contenido, ambas clases tienen comentarios que espero sean suficientes para hacer comprensible su función.

package mx.hashsoft.itext7;

import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Paragraph;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author david
 */
public class iText7 {

    static public void main(String[] args) {
        try {
            // Creamos el escritor del archivo pdf
            PdfWriter pdfWriter = new PdfWriter("./ejemplo_itext7.pdf");
            // Creamos el documento PDF que se almacenara via el escritor
            PdfDocument pdfDoc = new PdfDocument(pdfWriter);
            // Creamos el documento pdf en si, con pagina tamaño letra
            Document doc = new Document(pdfDoc, PageSize.LETTER);
            // Creamos el manejador de evento de pagina, el cual agregara
            // el encabezado y pie de pagina
            EventoPagina evento = new EventoPagina(doc);

            // Indicamos que el manejador se encargara del evento END_PAGE
            pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, evento);
            
            // Establecemos los margenes
            doc.setMargins(75, 36, 75, 36);

            // Creamos el contenido, por motivos de ejemplo es solo Hola Mundo!
            // una y otra vez
            for (int i = 0; i < 450; i++) {
                doc.add(new Paragraph("Hola Mundo!"));
            }

            // Cerramos el documento
            doc.close();

        } catch (FileNotFoundException ex) {
            Logger.getLogger(iText7.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
package mx.hashsoft.itext7;

import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Table;

/**
 *
 * @author david
 */
public class EventoPagina implements IEventHandler {

    private final Document documento;

    public EventoPagina(Document doc) {
        documento = doc;
    }
    
    /**
     * Crea el rectangulo donde pondremos el encabezado
     * @param docEvent Evento de documento
     * @return Area donde colocaremos el encabezado
     */
    private Rectangle crearRectanguloEncabezado(PdfDocumentEvent docEvent) {
        PdfDocument pdfDoc = docEvent.getDocument();
        PdfPage page = docEvent.getPage();        
        
        float xEncabezado = pdfDoc.getDefaultPageSize().getX() + documento.getLeftMargin();
        float yEncabezado = pdfDoc.getDefaultPageSize().getTop() - documento.getTopMargin();
        float anchoEncabezado = page.getPageSize().getWidth() - 72;
        float altoEncabezado = 50F;

        Rectangle rectanguloEncabezado = new Rectangle(xEncabezado, yEncabezado, anchoEncabezado, altoEncabezado);
        
        return rectanguloEncabezado;        
    }
    
    /**
     * Crea el rectangulo donde pondremos el pie de pagina
     * @param docEvent Evento del documento
     * @return Area donde colocaremos el pie de pagina
     */
    private Rectangle crearRectanguloPie(PdfDocumentEvent docEvent) {
        PdfDocument pdfDoc = docEvent.getDocument();
        PdfPage page = docEvent.getPage();
        
        float xPie = pdfDoc.getDefaultPageSize().getX() + documento.getLeftMargin();
        float yPie = pdfDoc.getDefaultPageSize().getBottom() ;
        float anchoPie = page.getPageSize().getWidth() - 72;
        float altoPie = 50F;

        Rectangle rectanguloPie = new Rectangle(xPie, yPie, anchoPie, altoPie);
        
        return rectanguloPie;
    }
    
    /**
     * Crea la tabla que contendra el mensaje del encabezado
     * @param mensaje Mensaje que desplegaremos
     * @return Tabla con el mensaje de encabezado
     */
    private Table crearTablaEncabezado(String mensaje) {
        float[] anchos = {1F};
        Table tablaEncabezado = new Table(anchos);
        tablaEncabezado.setWidth(527F);

        tablaEncabezado.addCell(mensaje);
        
        return tablaEncabezado;
    }
    
    /**
     * Crea la tabla de pie de pagina, con el numero de pagina
     * @param docEvent Evento del documento
     * @return Pie de pagina con el numero de pagina
     */
    private Table crearTablaPie(PdfDocumentEvent docEvent) {
        PdfPage page = docEvent.getPage();
        float[] anchos = {1F};
        Table tablaPie = new Table(anchos);
        tablaPie.setWidth(527F);
        Integer pageNum = docEvent.getDocument().getPageNumber(page);
        
        tablaPie.addCell("Pagina " + pageNum);
        
        return tablaPie;
    }
    

    /**
     * Manejador del evento de cambio de pagina, agrega el encabezado y pie de pagina
     * @param event Evento de pagina
     */
    @Override
    public void handleEvent(Event event) {
        PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
        PdfDocument pdfDoc = docEvent.getDocument();
        PdfPage page = docEvent.getPage();
        PdfCanvas canvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);        
        
        Table tablaEncabezado = this.crearTablaEncabezado("Departamento de Recursos Humanos");
        Rectangle rectanguloEncabezado = this.crearRectanguloEncabezado(docEvent);        
        Canvas canvasEncabezado = new Canvas(canvas, pdfDoc, rectanguloEncabezado);        
        canvasEncabezado.add(tablaEncabezado);      

        Table tablaNumeracion = this.crearTablaPie(docEvent);
        Rectangle rectanguloPie = this.crearRectanguloPie(docEvent);
        Canvas canvasPie = new Canvas(canvas, pdfDoc, rectanguloPie);        
        canvasPie.add(tablaNumeracion);
    }
}

Espero que esta entrada halla sido de utilidad y nos vemos en la próxima :).

Maven para principiantes

Estándar
Maven para principiantes

Maven para principiantes

 

Transcript

Maven para principiantes

Panel 1

¿Buscando una sistema para realizar un proyecto con el minimo
de herramientas?

Maven es la opción

Una herramienta de software para la gestión y construcción de
proyectos Java creada por Jason van Zyl, de Sonatype, en 2002

Panel 2

Para comenzar, cree su entorno de trabajo con el comando

Panel 3

mvn archetype:generate -DgroupId=mx.hashCode.test -DartifactId=MavenCommand -DinteractiveMode=false

Hash: Que generara el directorio del proyecto conteniendo.

Panel 4

El archivo pom.xml es donde indicara como construir el
proyecto.

Hash: Y usando los comandos mvn compile mvn test

Hash: Compilara o realizara las pruebas al proyecto

Panel 5

Y si su proyecto necesita librerias extras Maven puede descargarlas
automaticamente

Panel 6

Agregarlas a su proyecto

Y estas se quedan en el caché de modo que puede usarlas sin conexión a
Internet

Panel 7

Para agregar librerias, agrege a su archivo pom.xml, en la sección de
dependencias.

<dependencies>
   <dependency>
      <groupId>idGrupo</groupId>
      <artifactId>IdArtefacto</artifactId>
      <version>verLibreria</version>
   </dependency>
</dependencies>

Los valores de idGrupo, idArtefacto y verLibreria para la libreria que
necesite se pueden hallar en https://mvnrepository.com/

Panel 8

Y tenemos el proyecto listo

Panel 9

No

Aun falta crear el .jar ejecutable

Panel 10

Para esto agrege en la seccion de su archivo pom.xml

<plugins>
   <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <version>3.0.0</version>
      <configuration>
         <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
         </descriptorRefs>
         <archive>
            <manifest>
               <mainClass>clasePrincipal</mainClass>
            </manifest>
         </archive>
      </configuration>
      <executions>
         <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
               <goal>single</goal>
            </goals>
         </execution>
      </executions>
   </plugin>
</plugins>

Panel 11

Hecho esto usamos mvn package..

Y lo tenemos un .jar ejecutable

Panel 12

Y no solo ejecutable con el plugin que usamos todas las dependencias
estan dentro del .jar

¿Y donde esta el .jar?

Panel 13

Lo hallará en la carpeta target del proyecto

Creando archivos Excel en Java, Un ejemplo MÁS práctico

Estándar

En un comentario se me mencionó algo que ya sospechaba, que el ejemplo que puse en la entrada Creando archivos Excel desde Java con Apache POI es demasiado simple y no particularmente práctico :P, por lo que llegó el momento de corregir eso con un ejemplo que muestre algunos de los “detalles” con los que hay que lidiar al momento de usar las librerías Apache POI.

Para este ejemplo haremos algo más elaborado, simularemos un reporte anual que nos presenta el siguiente formato:

  • La primera columna nos debe mostrar los nombres de los doce meses del año
  • La primera fila debe mostrar la numeración del 1 al 31 de modo que sepamos a qué día corresponde cada valor
  • Las filas 2 en adelante nos deben mostrar los porcentajes de cada día de ese mes

Y para que quede más claro veamos como se verá el resultado.

 

2016-08-24 (1)

Como se vería nuestro reporte

Antes de pasar al código recuerde agregar las librerías de Apache POI a su proyecto, pues de lo contrario no tendrá las clases necesarias y no compilara, dicho esto vamos al código, espero que los comentarios dejen en claro que hace cada sección.

package ejemploexcel;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;

import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

/**
 *
 * @author David
 */
public class EjemploExcel {

    /**
     * Programa de ejemplo para la creacion de un archivo de excel
     * 
     * El programa simulara un reporte anual mostrando los porcentajes de cada
     * dia del año (simulados via numeros aleatorios) en el formato:
     * 
     * <nombre mes> <dia 1> <dia 2> <dia 3>...
     * 
     * Cada fila tendra el largo correspondiente a los dias de dicho posicion
     * 
     * @param args
     */
    public static void main(String[] args) {
        // Creamos nuestro libro de excel
        HSSFWorkbook workbook = new HSSFWorkbook();
        
        // Creamos una hoja de calculo llama "Reporte" en dicho libro de excel
        HSSFSheet sheet = workbook.createSheet("Reporte");
        
        // Un arreglo con los nombres de los meses del año
        String[] meses = {"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"};
        // Un arreglo con la duración de cada mes
        Integer[] diasMes = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        
        // Creamos un formato para las celdas
        HSSFCellStyle style = workbook.createCellStyle();        
        // Especificamente que *siempre* muestre dos digitos enteros y dos decimales
        style.setDataFormat(workbook.createDataFormat().getFormat("00.00"));
        
        // En la primera fila ponemos el numero del dia
        Row encabezado = sheet.createRow(0);
        // i empieza en 1 para alinear el numero de dias con los datos ya que
        // la columna 0 se usara para el nombre del posicion
        for (int i = 1; i < 32; i++) {
            Cell celda = encabezado.createCell(i);
            celda.setCellValue(i);
        }
        
        
        // Este ciclo ira creando las *filas*, una por cada mes del año
        // la variable posicion indicara en que fila nos encontramos, mientras que mes
        // selecionara el nombre del mes.
        // posicion comienza en 1 para compensar que ya usarmos la fila 0 para
        // poner los dias
        for(int posicion = 1, mes=0; mes < meses.length; posicion++, mes++) {
            // Creamos una fila en la posicion indicada por el contador del ciclo
            Row fila = sheet.createRow(posicion);
            
            // Creamos la celda para el nombre del mes, en la primera posicion de la fila
            Cell celdaMes = fila.createCell(0);
            // Indicamos que valor debe tener
            celdaMes.setCellValue(meses[mes]);
            
            // Este ciclo ira llenando las *celdas* en la fila que acabamos de
            // crear, llenando solo el numero de celdas indicado por el numero
            // de dias
            
            // Empezamos en 1 y le sumamos 1 a los dias del posicion para compensar
            // que la celda 0 la usamos para el nombre del posicion
            
            for (int dia = 1; dia < diasMes[mes] + 1; dia++) {
                // Creamos una celda en posicion indicada de la fila en la que
                // estamos trabajando
                Cell celda = fila.createCell(dia);
                // Indicamos el formato que la celda usara
                celda.setCellStyle(style);
                // Creamos el porcentaje de ese dia
                Double porcentaje = Math.random() * 100;
                // Almacenamos el porcentaje en la celda del dia
                celda.setCellValue(porcentaje);                
                
            }  
            // Al momento que el ciclo de otra vuelta el valor de posicion se incrementara
            // de modo que al crear una nueva fila, esta estara ubicada en la
            // *siguiente* fila y no sobre escribira la que hemos creado
        }
        
        // Ahora almacenaremos el archivo en disco
        try {
            File archivo = new File("ejemplo.xls");
            FileOutputStream out = new FileOutputStream(archivo);
            workbook.write(out);
            out.close();
        } catch (IOException e) {
            System.err.println("ERROR AL CREAR EL ARCHIVO!");
            e.printStackTrace();
        }
        
        System.out.println("Reporte generado");
        
    }
    
}

La caida de Struts

Estándar
2016_08_12_struts_fall

Hubo Complicaciones…

Pues si, intentar usar la nueva versión de Struts dio demasiada lata, así que de aquí en adelante los tutoriales de aplicaciones web serán con Spring MVC

Panel 1
Parecia simple, hacer unos ejemplos con Struts 2.5 para e blog..

Hash: ¡¿Que diablos paso?!, ¡Faltan jars!, ¿¡Xwork-core!?, ¡Tomcat 8 NO soportado!, ¿¡Java 8 no soportado?!

Pero hubo complicaciones

Panel 2
Hash: ¿Hm?

Panel 3
Al parecer la nueva version de Struts tiene ciertos “detalles”

Panel 4
Que seria mejor evitar
Hash: ¡YA ESTUVO!, ¡NOS CAMBIAMOS DE FRAMEWORK!

Panel 5
¡Nos pasamos a Spring MVC!

Pooling de Conexiones a base de datos con C3P0 y Java

Estándar

Un pool de conexiones a base de datos es una forma de llevar un control de las mismas de modo que al desocupar una conexión, en lugar de cerrar la conexión la tengamos a la mano y se entregue al siguiente objeto que necesite una conexión.

Si bien esto puede sonar innecesario debe de recordar que crear una conexión a base de datos es una de las operaciones mas pesadas que puede efectuar y que las conexiones expiran automáticamente después de un tiempo sin uso, ambas cosas que pueden afectar el rendimiento o estabilidad de su aplicación.

Ahí es donde entra el pool de conexiones ya que este se encargara de reducir el numero de veces que necesite crear una nueva conexión y en caso que esta expire crea una nueva si es necesario.

Pool de conexiones C3P0

Uno de los pools de conexiones mas populares actualmente es el C3P0 proporcionado por Machinery For Change, Inc, este le proporciona todas las funcionalidades esperadas a la vez que se integra con gran facilidad a otros frameworks de Java.

Debido a su popularidad y sencillez de uso nos enfocaremos en como hacer uso de este pool en particular.

Obtener las librerías de c3P0.

Vaya a la pagina oficial del proyecto: http://www.mchange.com/projects/c3p0/ o directamente al repositorio en SourceForge y descargue la versión mas reciente.

En el archivo .zip que descargo vaya a la carpeta lib y extraiga los archivos c3p0-0.9.5.2.jar, c3p0-oracle-thin-extras-0.9.5.2.jar y mchange-commons-java-0.2.11.jar con estos ya podrá usar el pool en su proyecto.

A su vez necesitara de la librería para usar conexiones a base de datos, agregue esta a su proyecto como se ve en la figura 2.

2016-04-18

Figura 1 – Librerías de C3P0.

2016-04-18 (1)

Figura 2 – Librerías del proyecto.

Estos archivos .jar pueden agregarse a un proyecto como ya lo hemos hecho con anterioridad.

Uso del pool C3P0 en un programa.

En el ejemplo que se utilizara para demostrar el uso del pool seguramente notará un par de cosas un tanto inusuales, específicamente que obtendremos el pool de conexiones vía un método getInstance en lugar de un constructor, obtendremos las conexiones desde el pool  y que haremos un uso constante del método close del objeto conexión.

El uso del getInstance es por una razón muy sencilla, haciendo el pool un objeto estático y obteniendo este vía el getInstance podemos tener el *mismo* pool disponible en todo el programa sin necesidad de estar pasando ese objeto a cada una de las clases, se los digo por experiencia, tener que agregar un parámetro extra a cada constructor y crear los getter y setter necesarios se vuelve aburrido de inmediato.

El obtener las conexiones desde el pool es necesario para poder obtener los beneficios de este, fuera de eso se comportan de manera usual por lo que no necesita modificar cómo realiza sus consultas.

Con respecto a llamar el método close esto es necesario para indicar al pool que ya no estamos usando esa conexión, de modo que esté disponible para cuando se solicite, es *vital* que recuerde llamar al método close o que use la estructura try-with-resources proporcionada por Java, ya que el no hacer esto puede trabar su aplicación, ese caso se verá en el ejemplo.

Ejemplo.

El ejemplo que se presentará es muy sencillo, pero presenta los detalles de como crear la clase para manejar el pool  y cómo usar esta en un programa de una forma que, espero, sea lo más legible y sencilla de entender posible.

El ejemplo consistirá en dos clases, una que crea y configura el pool y otra desde la cual realizaremos una serie de consultas a la tabla de base de datos que se ve en la figura 3.

2016-04-20 (2)

Figura 3 – Tabla a presentar.

package c3p0ejemplo;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.SQLException;
import java.sql.Connection;

public class PoolC3P0 {
 // Notara que el pool es un miembro *estatico* esto es para evitar duplicidad
 private static PoolC3P0 datasource;
 // Esta es la fuente de datos que conecta con la base de datos
 private final ComboPooledDataSource cpds;

 /**
  * Crea el constructor del pool, notara que este constructor es privado
  * esto con el fin de que podamos controlar cuando se crea el pool
  * @throws IOException
  * @throws SQLException
  * @throws PropertyVetoException
  */
 private PoolC3P0() throws IOException, SQLException, PropertyVetoException {
  // Configuramos la conexion a base de datos
  // Creamos la fuente de datos
  cpds = new ComboPooledDataSource();
  // Que driver de base de datos usaremos
  cpds.setDriverClass("com.mysql.jdbc.Driver");
  // La url de la base de datos a la que nos conectaremos
  cpds.setJdbcUrl("jdbc:mysql://127.0.0.1/");
  // Usuario de esa base de datos
  cpds.setUser("usuario");
  // Contraseña de la base de datos
  cpds.setPassword("contrasena");

  // Configuramos el pool
  // Numero de conexiones con las que iniciara el pool
  cpds.setInitialPoolSize(0);
  // Minimo de conexiones que tendra el pool
  cpds.setMinPoolSize(0);
  // Numero de conexiones a crear cada incremento
  cpds.setAcquireIncrement(1);
  // Maximo numero de conexiones
  cpds.setMaxPoolSize(5);
  // Maximo de consultas
  cpds.setMaxStatements(180);
  // Maximo numero de reintentos para conectar a base de datos
  cpds.setAcquireRetryAttempts(2);
  // Que se genere una excepcion si no se puede conectar
  cpds.setBreakAfterAcquireFailure(true);
 }

 /**
  * Nos regresa la instancia actual del pool, en caso que no halla una instancia
  * crea una nueva y la regresa
  * @return
  * @throws IOException
  * @throws SQLException
  * @throws PropertyVetoException
  */
 public static PoolC3P0 getInstance() throws IOException, SQLException, PropertyVetoException {

  if (datasource == null) {
   datasource = new PoolC3P0();
   return datasource;
  } else {
   return datasource;
  }
 }

 /**
  * Este metodo nos regresa una conexion a base de datos, esta la podemos
  * usar como una conexion usual
  * @return Conexion a base de datos
  * @throws SQLException
  */
 public Connection getConnection() throws SQLException {
  return this.cpds.getConnection();
 }

}
package c3p0ejemplo;

import java.beans.PropertyVetoException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class C3P0Ejemplo {

 /**
  * @param args the command line arguments
  */
 public static void main(String[] args) {
  try {
   // Obtenemos el pool de conexiones
   PoolC3P0 pool = PoolC3P0.getInstance();

   for (int i = 0; i < 10; i++) {
    // Solicitamos una conexion al pool
    Connection cx = pool.getConnection();
    // Creamos nuestro objecto de consulta
    Statement consulta = cx.createStatement();
    // La consulta que ejecutaremos
    String sql = "SELECT * FROM pruebas.prueba";
    // Obtenemos los datos
    ResultSet data = consulta.executeQuery(sql);
    data.next();

    Integer puerto = data.getInt("puerto_serial");
    Integer impresora = data.getInt("puerto_impresora");
    Integer red = data.getInt("puerto_red");
    Integer scaner = data.getInt("puerto_escaner");

    // Los presentamos en pantalla
    System.out.println("Vuelta numero " + i);
    System.out.println("Puerto " + puerto);
    System.out.println("Impresora " + impresora);
    System.out.println("Red " + red);
    System.out.println("Escaner " + scaner);
    System.out.println("");
    System.out.println("");

    // Cerramos la conexion, esto es vital, de no hacerlo el pool creara una nueva conexion
    // pero al cerrar liberamos esa conexion para que el pool la reuse
    cx.close();

    // Un retrazo de 10 segundos para poder ver las conexiones en MySQL Workbench
    Thread.sleep(5000);
   }

  } catch (IOException ex) {
   System.out.println("Error de entrada salida");
  } catch (SQLException ex) {
   System.out.println("Error de conexion a base de datos");
  } catch (PropertyVetoException ex) {
   System.out.println("Error de propiedades");
  } catch (InterruptedException ex) {
   System.out.println("Error de interrupcion de proceso");
  }

 }

}

Ya que ejecute el programa vera que el programa abre una conexión, consulta, presenta los datos, realiza una espera y cierra la conexión, el resultado se vera como la figura 4.

2016-04-20 (1)

Figura 4 – Salida del programa

Como ve el ejemplo pide y cierra conexiones a cada vuelta, mientras el programa se ejecuta acceda a la administración de conexiones de usuario en workbench, notara que la conexión que usamos (identificada por el usuario “usuario”) nunca cambia, no importa cuantas conexiones abramos o cerremos solo se esta usando una como vemos en la figura 5.

2016-04-20 (3)

Figura 5 – Conexiones del usuario

Como un extra modifique la tabla mientras corre el programa y vera que los datos presentados cambian en forma acorde.

Espero que la entrada fuera útil y nos vemos en la próxima.

Coloreando las celdas, filas y columnas de una tabla JTable en Java

Estándar

Debido que una tabla de datos puede llegar a ser visualmente tediosa, dificil de seguir debido a su tamaño o que deseé resaltar ciertos valores significativos es posible que necesite colorear ciertas celdas, filas, columnas o cualquier combinación de estas en forma especifica, aqui presentaremos como.

TableCellRenderer
Cada objecto JTable cuenta con un objecto una clase que implemente la interfaz TableCellRenderer, mismo que se encarga de controlar como se renderiza cada celda que componga la JTable via el metodo getTableCellRendererComponent, como seguro ya dedujo, si deseamos controlar los colores de las celdas de la tabla necesitamos una clase que implemente la interfaz TableCellRederer y defina el método getTableCellRendererComponent para que haga lo que necesitamos, no se asuste por complejo que esto suene (y que algunos de esos metodos tienen una cantidad extrañamente larga de argumentos) esto es muy sencillo y lo veremos a continuación.

Implementando la interfaz TableCellRenderer.
Esta interfaz es muy sencilla, solo agrege implements TableCellRenderer despues del nombre de la clase y agrege el método getTableCellRendererComponent, como se ve en el código a continuación.

package colortable;

import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;

/**
 *
 * @author darta_000
 */
public class Resaltador implements TableCellRenderer {
    private Integer fila;
    public static final DefaultTableCellRenderer DEFAULT_RENDERER = new DefaultTableCellRenderer();
    
    /**
     * Creamos el resaltador indicando que fila se coloreara por defecto
     * @param row 
     */
    public Resaltador(Integer row){
        fila = row;
    }
    
    /**
     * Colorea la celda si pertenece a la fila indicada, esta funcion es llamada internamente por la tabla
     * que use esta clase como renderizados
     * @param table Tabla
     * @param value Valor de la celda
     * @param isSelected Celda selecionada
     * @param hasFocus Celta tiene el foco
     * @param row Fila de la celda
     * @param column Columna de la celda
     * @return Celda de la tabla
     */    
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        // Obtenemos la celda que se esta renderizando
        Component c = DEFAULT_RENDERER.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        // Si la celda esta en la fila indicada y no esta seleccionada se coloreara de este modo        
        if (fila.compareTo(row) == 0 && isSelected == false) {
            c.setBackground(Color.decode("#FF88FF"));
            c.setForeground(Color.BLACK);
        // Si la celda esta en la fila indicada y esta seleccionada se coloreara de este modo
        } else if (fila.compareTo(row) == 0 && isSelected == true) {
            c.setBackground(Color.RED);
            c.setForeground(Color.WHITE);
        // Si la celda no esta en la fila indicada y esta seleccionada se coloreara de este modo
        } else if (fila.compareTo(row) != 0 && isSelected == true) {
            c.setBackground(Color.BLUE);
            c.setForeground(Color.WHITE);
        // En los demas casos se coloreara de este modo
        } else {
            c.setBackground(Color.WHITE);
            c.setForeground(Color.BLACK);
        }
        // Regresamos la celda para que se agrege a la tabla
        return c;
    }

    /**
     * @return the fila
     */
    public Integer getFila() {
        return fila;
    }

    /**
     * @param fila the fila to set
     */
    public void setFila(Integer fila) {
        this.fila = fila;
    }
}

Notara que el método getTableCellRendererComponent tiene varios argumentos que hace cada uno se describe a continuación:

  • JTable table – La tabla sobre la que opera el metodo
  • Object value – El valor a presentar en esa celda
  • boolean isSelected – Le indicara si esa celda esta seleccionada
  • boolean hasFocus – Le indica si esa celda tiene el foco de edición
  • int row – Indica el numero de fila en que se encuentra la celda
  • int colum – Indica el numero de columna en que se encuntra la celda.

Antes que se pregunte donde va a sacar esos parametros recuerde que esa función es usada internamente por el JTable, esos argumentos estan ahi para que pueda identificar si una celda debe de ser rendereizada en forma especial, como vimos en la clase que creamos previamente

Ejemplo
Para este ejemplo haremos algo sencillo, crearemos una tabla, la cual llenaremos con datos, via una entrada de texto diremos que fila queremos colorear y con un boton refrescaremos la tabla

package colortable;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;

/**
 *
 * @author darta_000
 */
public class ColorTable extends JFrame implements ActionListener {

    private final JTable tabla;
    private final JScrollPane barras;
    private final DefaultTableModel modelo;
    private final JTextField entrada;
    private final JButton boton;
    private final String[] columnas = {"Indice", "Dato"};
    Resaltador resaltado;

    /**
     * Crea la ventana con la tabla
     */
    public ColorTable() {
        entrada = new JTextField();
        boton = new JButton("Resaltar");
        modelo = new DefaultTableModel();
        tabla = new JTable();
        barras = new JScrollPane(tabla);
        resaltado = new Resaltador(0);

        // Detalles de la ventana
        this.setTitle("Tabla Color");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLayout(new BorderLayout());

        // Establecemos el modelo de la tabla.
        modelo.setColumnIdentifiers(columnas);
        tabla.setModel(modelo);

        //Colocamos los elementos en su lugar
        this.getContentPane().add(barras, BorderLayout.CENTER);
        this.getContentPane().add(entrada, BorderLayout.NORTH);
        this.getContentPane().add(boton, BorderLayout.SOUTH);

        // El evento del boton
        boton.addActionListener(this);

        // Iniciamos el valor del texto
        entrada.setText("0");

        // Indicamos como sera el resaltado de la tabla
        tabla.setDefaultRenderer(Object.class , resaltado);

    }

    /**
     * Limpia y agrega los datos en la tabla
     */
    private void agregarDatos() {
        String[] datos = {"CERO", "Uno", "Dos", "Tres", "Cuatro", "Cinco", "Seis", "Siete", "Ocho", "Nueve", "Diez", "Once"};

        modelo.setRowCount(0);

        for (int i = 0; i < datos.length; i++) {
            Object[] row = {i, datos[i]};
            modelo.addRow(row);
        }
    }

    /**
     * Muestra la ventana en pantalla
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        ColorTable color = new ColorTable();

        color.pack();
        color.setVisible(true);
    }

    /**
     * Lo que se realiza cuando se presiona el boton
     * @param e Evento
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        Integer fila;
        try {
            fila = Integer.parseInt(entrada.getText());
        } catch (NumberFormatException ex) {
            fila = 0;
        }

        resaltado.setFila(fila);

        this.agregarDatos();
    }
}

Al momento de ejecutar el programa vera algo como en la figura 1.

01_inicio

Figura 1 – Programa recien iniciado.

Presione el boton resaltar y vera que la fila cero se colorea.

02_color_0

Figura 2 – Fila cero coloreada.

Escriba el numero de alguna fila en la entrada de texto, presione el boton y vera como esa fila se colorea, cambie el numero y vera otra fila cambiar.

03_nueve

Figura 3 – Cambiando la fila coloreada.

El coloreado puede ser cambiando dinamicamente, y esto se aplicara cada vez que se actualice la tabla.

Escribiendo codigo en WordPress.com

Estándar

Desde que comencé a poner tutoriales aqui en wordpress.com me di cuenta que ocurrian un par de cosas extrañas al momento de escribir el código fuente.Las comillas “” no son las comillas que uno veria en el editor de texto normal sino esas comillas que abren y cierran mas comunes de ver en un *procesador* de texto, esas se ven muy bien pero tienen el problema de que si las copia al entorno de desarollo vera un monton de errores y devera de remplazar todas las comillas, ademas que el uso de los caracteres < y > en los xml tiende a causar problemas de renderizado (ya que son caracteres reservados de xml y html) y ademas que no usa uan fuente con espaciado regular, lo que puede hacer que leer el código sea un poco confuso.

2016-02-28

Figura 1 – Errores de comillas.

Y si bien hay formas de prevenir eso (los entornos <pre> y <code>) al final son innecesarios ya que wordpress.com le proporciona de las etiquetas [ code ]  [ /code] las cuales le permiten indicar al wordpress.com que el texto contenido entre esas dos debe de ser considereado codigo fuente, con el resaltado de sintaxis correcto para ese lenguaje, numeración de lineas, poner el titulo de ese código e incluso permitir minimizar el código para que no ocupe demasiado espacio, a continuación veremos como usar esa etiqueta.

La etiqueta [ code]

La sintaxis de la etiqueta code es la siguiente:

[ code language="java" title="HolaMundo.java"]
public class HolaMundo {
   static public void main(String[] args) {
      System.out.println("Hola Mundo!");
   }
}
[/code]

Es bastante intuitivo colocamos nuestro código entre las etiquetas y en la etiqueta que abre indicamos que lenguaje es el código (puede ver que lenguajes estan soportados en el enlace en el area de referencias) y el titulo que ese código tendra en el.

Notara que puse un espacio entre el corchete [ y la palabra code, esto es necesario para poder *mostrar*  esa etiqueta en wordpress.com, recuerde ignorar eso ya que aplique lo mencionado en esta entrada, ya sin ese espaciado el ejemplo anterior se ve de la siguiente manera:

public class HolaMundo {
   static public void main(String[] args) {
      System.out.println("Hola Mundo!");
   }
}

Notara el coloreado de sintaxis adecuado, numeración de lineas y que si copia eso al entorno las comillas se copian correctamente.

Esto tambien es util con los archivos xml de modo que el código

[ code language="xml" title="Ejemplo.xml"]
<xml>
<data> ANDROIDE </data>
</xml>
[/code]

Aparecera como
<xml>
<data> ANDROIDE </data>
</xml>

Esto es muy util para corregir lo antes mencionado con los caracteres < y >

 

Referencias:

Lenguajes soportados: https://en.support.wordpress.com/code/posting-source-code/