[Métodos] Cómo crear un Jar ejecutable desde la consola y en un IDE


Consola CMD


Para poder generar un jar a través de la consola de windows debemos:

  1. Contar con la variable JAVA_HOME
    • Esta debe apuntar al root de JDK de la versión que tengamos.
    • De dudar si esta configurada, o entre tantas a cual apunta, podemos escribir en la consola:
    • 1
      2
      echo %JAVA_HOME%
      C:\Programs File\Java\jdk1.8.0_112
      
    • La respuesta deberia de ser la ruta a la carpeta de java, de lo contrario mostraria el literal "%JAVA_HOME%"


  2. Escribir una clase java con un metodo main
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.blogspot.dar10comyr;
    
    import java.awt.FlowLayout;
    import java.awt.Frame;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    
    public class Principal {
    
        public static void main(String[] args) {
            JLabel etiqueta = new JLabel("Hola mundo");
            Frame marco = new JFrame("LegenDar10");
            marco.setLayout(new FlowLayout());
            marco.add(etiqueta);
            marco.setLocationRelativeTo(null);
            marco.setSize(250, 100);
            marco.setVisible(true);
        }
    }
    


  3. Compilar el archivo java para convertirlo en .class
    • Hay que llamar al archivo javac.exe y a nuestro archivo java, con lo cual podría llamar a la ruta absoluta de cada cual o aprovechando tener la variable global JAVA_HOME, podemos abrir la consola desde la barra de direcciones en la carpeta donde esta nuestra clase:
    • 1
      "%JAVA_HOME%/bin/javac.exe" Principal.java
      
    • Es importante notar que generalmente la carpeta Program File, lleva un espacio por lo que es mejor encerrar la ruta con las comillas dobles.
    • La primera parte de esta sentencia, llama al compilador del jdk, el archivo javac.exe
    • Y como primer parametro le pasa la clase java que deseamos compilar.


  4. Configurar Main-Class
    • Esto se logra a traves del archivo Manifest.txt, este se situa sobre el root del proyecto
    • 1
      2
      Main-Class: com.blogspot.dar10comyr.Principal
      
      
    • Es un simple archivo de texto, pero de suma importancia su nombre, contiene pares de clave-valor separada por los dos puntos.
    • La clave Main-Class, con sus correspondientes mayusculas, indica cual es la calse principal del proyecto que contiene el metodo main
    • El valor com.blogspot.dar10comyr.Pricnipal, indica la clase a través de su nombre con los paquetes a los que pertence y sin extención, ya que existe el .java, humanamente leible y el .class, un archivo binario.
    • Es muy importante! que este archivo termine con un salto de linea, ya que de lo contrario, no sabra cuando termina la primera declaracion


  5. Generar el jar
    • suponiendo que la estructura de nuestro proyecto es:
      1
      2
      3
      C:/Proyecto/Manifest.tx
      C:/Proyecto/com/blogspot/dar10comyr/Pricipal.java
      C:/Proyecto/com/blogspot/dar10comyr/Pricipal.class
      
    • Llamaremos a través de la variable global JAVA_HOME, al archivo jar.exe
    • Con los puntos de entrada-cvfm, donde:
      • -c indica que creará un nuevo archivo, el .jar
      • -v nos brinda la información detalla del proceso
      • -f le da el nombre al jar, en nuestro caso Saludos.jar
      • -m indica que daremos la información del 'manifest.txt'
    1
    "%JAVA_HOME%/bin/jar.exe" -cvfm Saludos.jar manifest.txt com/blogspot/dar10comyr/Principal.class
    
    • Luego de la point-entry, le damos un nombre al jar, la ubicacion del manifest y de las clases


Ya por ultimo, desde la misma consola llamamos al archivo jar o dando dobel click, el resultado será:

[Métodos] Generar tabla en PDF con xstream y xls en Java


Imaginemos que contamos con un xml de la siguiente manera:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<list>
  <juego>
    <nombre>Rise Of The Tomb Raider</nombre>
    <desarrolladora>Square Enix</desarrolladora>
    <distribuidora>Crystal Dinamics</distribuidora>
    <plataformas>PC, PS4, XBOX ONE XBOX 360</plataformas>
    <genero>Accion Aventura </genero>
    <fechaLanzamiento>2015-11-10 03:00:00.0 UTC</fechaLanzamiento>
  </juego>
  <juego>
    <nombre>Far Cry Primal</nombre>
    <desarrolladora>Ubisoft Montreal</desarrolladora>
    <distribuidora>Ubisoft</distribuidora>
    <plataformas>PC, PS4, XBOX ONE</plataformas>
    <genero>Accion Aventura Mundo Abierto </genero>
    <fechaLanzamiento>2016-02-23 03:00:00.0 UTC</fechaLanzamiento>
  </juego>
  <juego>
    <nombre>Resident Evil 7 BioHazard</nombre>
    <desarrolladora>Capcom</desarrolladora>
    <distribuidora>Capcom</distribuidora>
    <plataformas>PC, PS4, XBOX ONE</plataformas>
    <genero>Survival Horror</genero>
    <fechaLanzamiento>2017-01-24 03:00:00.0 UTC</fechaLanzamiento>
  </juego>
</list>

Entonces la idea seria poder generar un tabla, similar a las HTML, para poder asemejar cada etiqueta juego como un columna de nuestra tabla.
La sintaxis a usar para una tabla es:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<fo:table border="solid">
    <!-- declarar aqui las columnas que sean necesarias -->
    <fo:table-column column-width="30mm" />
    <!-- declaramos un cabecera -->
    <fo:table-header>
        <fo:table-row>
            <fo:table-cell>
                <fo:block font-weight="bold">Titulo de la columna</fo:block>
            </fo:table-cell>
        </fo:table-row>
    </fo:table-header>
    <!-- declaramos el cuerpo de la tabla -->
    <fo:table-body>
        <fo:table-row>
            <fo:table-cell>
                <fo:block>
                    <xsl:text>contenido de la celda</xsl:text>
                </fo:block>
            </fo:table-cell>
        </fo:table-row>
    </fo:table-body>
</fo:table>

    Es muy importante respetar la secuencia de etiqueta
  • <table-body></table-body>
  • <table-row></table-row>
  • <table-cell></table-cell>
  • <fo-block></fo-block>
  • Ya que de lo contrario, el transformador no entenderá y no generará el reporte

Para poder iterar sobre todas las etiquetas 'juego' vamos a hacer uso del tag <xsl:for-each select="list/juego">, 'seleccionando' a list y por cada juego:

1
2
3
<xsl:for-each select="/">
    <!-- aqui se repite por cada elemento -->
</xsl:for-each>

El XSL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:output method="xml" indent="yes" />
    <xsl:template match="/">
        <fo:root>
            <fo:layout-master-set>
                <fo:simple-page-master master-name="A4-portrait" page-height="29.7cm" page-width="21.0cm"
                    margin="1cm">
                    <fo:region-body />
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="A4-portrait">
                <fo:flow flow-name="xsl-region-body">

                    <fo:table border="solid">
                        <fo:table-column column-width="30mm" />
                        <fo:table-column column-width="30mm" />
                        <fo:table-column column-width="30mm" />
                        <fo:table-column column-width="35mm" />
                        <fo:table-column column-width="35mm" />
                        <fo:table-column column-width="30mm" />
                        <fo:table-header>
                            <fo:table-row>
                                <fo:table-cell>
                                    <fo:block font-weight="bold">Juego</fo:block>
                                </fo:table-cell>
                                <fo:table-cell>
                                    <fo:block font-weight="bold">Desarrolladora</fo:block>
                                </fo:table-cell>
                                <fo:table-cell>
                                    <fo:block font-weight="bold">Distribuidora</fo:block>
                                </fo:table-cell>
                                <fo:table-cell>
                                    <fo:block font-weight="bold">Fecha de Lanzamiento</fo:block>
                                </fo:table-cell>
                                <fo:table-cell>
                                    <fo:block font-weight="bold">Genero</fo:block>
                                </fo:table-cell>
                                <fo:table-cell>
                                    <fo:block font-weight="bold">Plataforma</fo:block>
                                </fo:table-cell>
                            </fo:table-row>
                        </fo:table-header>
                        <fo:table-body>
                            <xsl:for-each select="list/juego">
                                <fo:table-row>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="nombre" />
                                        </fo:block>
                                    </fo:table-cell>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="desarrolladora" />
                                        </fo:block>
                                    </fo:table-cell>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="distribuidora" />
                                        </fo:block>
                                    </fo:table-cell>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="fechaLanzamiento" />
                                        </fo:block>
                                    </fo:table-cell>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="genero" />
                                        </fo:block>
                                    </fo:table-cell>
                                    <fo:table-cell>
                                        <fo:block>
                                            <xsl:value-of select="plataformas" />
                                        </fo:block>
                                    </fo:table-cell>
                                </fo:table-row>
                            </xsl:for-each>
                        </fo:table-body>
                    </fo:table>

                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
</xsl:stylesheet>



Clase de ayuda con el método de transformacion


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package dar10;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringReader;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

public class FopHelper {

    public void xmlString2Pdf(String xml, String xslPath, String pdfPath) throws IOException, FOPException, TransformerException{
        FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

        OutputStream out;
        out = new FileOutputStream(pdfPath);

        try {
            Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

            // Ubicacion del archivo XSL
            File xsltFile = new File(xslPath);
            Source xslSource = new StreamSource(xsltFile);
            // Setup XSLT
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(xslSource);

            // Resulting SAX events (the generated FO) must be piped through to FOP
            Result res = new SAXResult(fop.getDefaultHandler());

            // Se convierte a 'Source' el xml
            StringReader reader = new StringReader(xml);
            Source xmlSource = new StreamSource(reader);

            // se crea el PDF
            transformer.transform(xmlSource, res);
        } finally {
            out.close();
        }
    }

    public void xmlFile2Pdf(String xmlPath, String xslPath, String pdfPath) throws IOException, FOPException, TransformerException{
        FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
        FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

        OutputStream out;
        out = new FileOutputStream(pdfPath);

        try {
            Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

            // Ubicacion del archivo XSL
            File xsltFile = new File(xslPath);
            Source xslSource = new StreamSource(xsltFile);
            // Setup XSLT
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(xslSource);

            // Resulting SAX events (the generated FO) must be piped through to FOP
            Result res = new SAXResult(fop.getDefaultHandler());

            // Se convierte a 'Source' el xml
            File xmlFile= new File(xmlPath);
            Source xmlSource = new StreamSource(xmlFile);

            // se crea el PDF
            transformer.transform(xmlSource, res);
        } finally {
            out.close();
        }
    }

}



La llamada


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public static String xmlPath = "src//dar10//juegos.xml";
public static String xslPath = "src//dar10//template.xsl";
public static String pdfPath = "src//dar10//resultado.pdf";

public static void main(String...Legendar10){
    FopHelper fopHelper = new FopHelper();
    try {
        fopHelper.xmlFile2Pdf(xmlPath, xslPath, pdfPath);
    } catch (FOPException | IOException | TransformerException e) {
        e.printStackTrace();
    }
}



El resultado


[Métodos] Generar PDF con xls en Java - Hola Mundo


Apache FOP, de sus siglas en inglés Formatting Objects Processor, el equivalente en español de Procesador de formato de objetos, es un formateador de impresión a través de archivos XSL formatting objects (XMLFO)
Según el mismo framework es capaz de imprimir en muchisimos formatos:
  • PDF, el mas típico y más usado
  • ASCII, PostScript, Direct printer output (PCL), AFP, RTF, Java2D/AWT, menos usuales

Esquema

El esquema básico es se toman tanto el xml como string que genero con xstream, dado en un webservice como desde un archivo, junto al xsl para ser procesados en java a través de apache FOP para generar un pdf(sigla del inglés Portable Document Format, «formato de documento portátil»)



Método

  • Declara 2 objetos FOPFactory y de éste instancia FOUserAgent que servirá para crear el FOP
  • También declara un OutputStream con el path de salida donde se creara el archivo
  • Estos los usa para instancia el objeto FOP junto a una constante que indica que será del tipo PDF
  • Con el path del archivo xsl crea un File y a partir de este un StreamSource que hereda de Source
  • Se crea un TransformerFactory para que junto al xsl instancie un Transformer que procece el xml
  • Declara un objeto Result instanciando un SAXResutl a partir del objeto 'fop'
  • Crea un Source, instanciando StreamSource pero esta vez a partir de un StringReader ya que se trata esta vez de un xml como String.
    Este paso puede cambiar instanciando el streamsource con un objeto file con el path del archivo xml, de igual manera que se hace con xsl.
  • Y el ultimo paso de esta receta mágica, es que el objeto Transformer transforme la fuente del xml junto con el resultado para crear el PDF

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static String xml = "<valor>Mundo</valor>";
public static String xslPath = "src//dar10//template.xsl";
public static String pdfPath = "src//dar10//resultado.pdf";

public static void main(String...Legendar10) throws IOException, FOPException, TransformerException{
    //Setea el agente para el FOP
    FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
    FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

    OutputStream out = new FileOutputStream(pdfPath);

    try {
        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

        // Ubicacion del archivo XSL
        File xsltFile = new File(xslPath);
        Source xslSource = new StreamSource(xsltFile);
        // Transformer a partir del xslt
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer(xslSource);

        // Resulting SAX events (the generated FO) must be piped through to FOP
        Result res = new SAXResult(fop.getDefaultHandler());

        // Se convierte a 'Source' el xml
        StringReader reader = new StringReader(xml);
        Source xmlSource = new StreamSource(reader);

        // se crea el PDF
        transformer.transform(xmlSource, res);
    } finally {
        out.close();
    }
}

En este caso esta todo contendio en un método main que ejecuta el proceso java. Se crea del proyecto un solo paquete que lo he llamado 'dar10' y los 3 string declarados como estaticos que representan el xml, la ubicacion del xsl, y la ubicacion de destino (que son el mismo paquete dentro del proyecto)

Añadir dependencias en el pom/classpath


1
2
3
4
5
<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.10</version>
</dependency>


El XSL (Transformador)


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <fo:root>
      <fo:layout-master-set>
        <fo:simple-page-master master-name="A4-portrait"
              page-height="29.7cm" page-width="21.0cm" margin="2cm">
          <fo:region-body/>
        </fo:simple-page-master>
      </fo:layout-master-set>
      <fo:page-sequence master-reference="A4-portrait">
        <fo:flow flow-name="xsl-region-body">
          <fo:block>
            Hola, <xsl:value-of select="valor"/>!
          </fo:block>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>
</xsl:stylesheet>

El xsl declara en su etiquetas:
  • la version de stylesheet
  • que la fuente de datos será xml
  • que el root del xml empieza en "/" y es a partir de lo que contengan intermente estas etiquetas, aunque nuestro xml solo contiene un tag
  • tmabién declara un layout por defecto y al 'Documento' con las dimensiones de la pagina (A4) y un cuerpo (body)
  • en las etiquetas siguientes declara 'page-sequence' y 'flow' haciendo referencias las anterior mencionadas
  • Y aqui comienza lo bueno, simplemente declara un fo:block, como un contenedor 'div'
  • y buscará con xsl:value-of dentro del root que estemos posicionados ("/") el valor contenido por las etiquetas 'valor'


El resultado: