jhipster angular primeNG file upload with entity as application/json

I was uploading some files along an entity in a jhipster generated app with the primeNG file upload component, but I was appending each field value in a new form data request parameter.

CursoResource.java

    @PostMapping("/cursos/archivos")
    @Timed
    public ResponseEntity<Curso> createCurso(@RequestPart(value = "titulo") String titulo, 
                                             @RequestPart(value = "descripcion") String descripcion,
                                             @RequestPart("archivos[]")MultipartFile[] archivos
    ) {
...
Curso curso = new Curso();
curso.setTitulo(titulo);
curso.setDescripcion(descripcion);
curso = this.cursoService.save(curso);
...
}

and in the client

curso-update.component.html

<p-fileUpload id="field_archivos" name="archivos[]" url="api/cursos/archivos" multiple="multiple"
                                  accept=".pdf,.doc,.docx,.xls,.xlsx"
                                  [maxFileSize]="3*1024*1024"                                  
                    (onBeforeSend)="onBeforeSend($event)">
                    </p-fileUpload>

curso-update.component.ts

    private onBeforeSend(event) {
        const token = this.localStorage.retrieve('authenticationToken') || this.sessionStorage.retrieve('authenticationToken');
        if (!!token) {
            event.xhr.setRequestHeader('Authorization', `Bearer  ${token}`);
        }
        event.formData.append('titulo', this.curso.titulo);
        event.formData.append('descripcion', this.curso.descripcion);
    }

but we can send the Entity serialized as JSON in a Blob inside our FormData using the correct Content-Type 'application/json'. With this we can include nested objects, add fields to our Entity -and we won't have to change the Resource Controller method signature with every new field-

curso-update.component.ts

    private onBeforeSend(event) {
        const token = this.localStorage.retrieve('authenticationToken') || this.sessionStorage.retrieve('authenticationToken');
        if (!!token) {
            event.xhr.setRequestHeader('Authorization', `Bearer  ${token}`);
        }
        event.formData.append('curso', new Blob([JSON.stringify(this.curso)], { type: 'application/json' }));
    }

change the Resource Controller accordingly

CursoResource.java

    @PostMapping("/cursos/archivos")
    @Timed
    public ResponseEntity createCurso(@Valid @RequestPart(value = "curso") Curso curso, 
                                             @RequestPart("archivos[]")MultipartFile[] archivos) {
...
Curso result = this.cursoService.save(curso);
...
}
Anuncios

primeng file upload angular i18n internationalization

primeNG doesn’t support i18n out of the box. But its components, like file upload, provide properties or templates to fit your needs.

In the case of file upload it has Label properties which we can use to translate

chooseLabel Label of the choose button.
uploadLabel Label of the upload button.
cancelLabel Label of the cancel button.

We have an app generated by jhipster which support internationalization through language files and directives. First we have to add the label translations in their respective files, in example

i18n/es/curso.json

{
    "cursosApp": {
        "curso" : {
            ...
            "upload": {
                "chooseLabel": "Seleccionar archivo"
            }
        }
    }
}

i18n/en/curso.json

{
    "cursosApp": {
        "curso" : {
            ...
            "upload": {
                "chooseLabel": "Choose file"
            }
        }
    }
}

and in your html

curso-update-component.html

<p-fileUpload id=...
[chooseLabel]="'cursosApp.curso.upload.chooseLabel' | translate">
</p-fileUpload>

notice the single quotes around labels

That’s it, now you can enable i18n in your primeNG components.

If you want to translate messages from your components, you could use the TranslateService as explained in this answer from stackoverflow.

sources:
https://forum.primefaces.org/viewtopic.php?t=51332
View story at Medium.com
https://github.com/jhipster/ng-jhipster/blob/master/src/language/jhi-translate.directive.ts
https://stackoverflow.com/questions/49513167/primeng-jhipster-insert-jhitranslation-in-growl-messages

Netbeans – Enable symbolic links in Payara (GlassFish) for your application

Screenshot from 2017-11-09 13-08-37

To enable symbolic links in Payara you just have to go to the admin console (http://localhost:4848 or inside netbeans open it in the Services window | Servers | Payara right click it and select ‘open admin console’) and click Configuration | server-config | Virtual Servers | server, then under Additional Properties, click Add Property and enter allowLinking as name and true as value as shown in the image above.

Symbolic links do not work with war deployments, they only work with exploded wars (if you add a symbolic link inside a war, the files from the target dir will be copied inside the war -compressed file-)
The good news is that Netbeans runs your app as an exploded war (folder). The folder path is usually {project}/build/web, to find out the folder which it uses for your app just open the Payara admin console and go to the Applications section and click your app, then look for the attribute ‘Location’
Go to that location and create whatever symbolic link your app needs, for example

cd {project}/build/web
ln -s /usr/share/docs docs

then you can access all the resources inside that folder like so

http://localhost:8080/project/docs

In production, you’ll have to deploy your app as an exploded war and have the same symbolic link created in the server

sources:
http://www.stpe.se/2008/07/enable-symbolic-links-in-glassfish/

Linux – Copiar un archivo demasiado grande a una memoria usb (fat32)

El tamaño máximo de un archivo que puedes almacenar en una USB (fat32) es de 2Gb (o 4Gb si estas utilizando LFS).

Si quieres copiar un archivo con un tamaño mayor, en linux, puedes hacerlo mediante el comando split, por ejemplo

split -b 2048 image.iso

que nos producirá una serie de archivos

image.isoaa
image.isoab
image.isoac
...

Después para juntarlos utilizamos el comando cat

cat image.iso* > ~/image.iso

El comando anterior no nos muestra un avance del progreso. Para ver el progreso podemos utilizar el comando pv, para instalarlo ejecuta sudo apt-get install pv y lo utilizas de la siguiente manera

cat image.iso* | pv -s $(du -cb image.iso* | grep total | awk '{print $1}') > ~/image.iso

Fuentes:
http://unix.stackexchange.com/questions/24630/whats-the-best-way-to-join-files-again-after-splitting-them
http://www.catonmat.net/blog/unix-utilities-pipe-viewer/
http://en.wikipedia.org/wiki/File_Allocation_Table#FAT32
http://unix.stackexchange.com/questions/41550/find-the-total-size-of-certain-files-within-a-directory-branch

Java – Convertir una página específica de un TIFF multipágina a JPG

Para la digitalización de documentos utilizamos escáneres que producen archivos TIFF, estos permiten almacenar varias imágenes en el mismo archivo. Estas imágenes se guardan en una base de datos para su posterior consulta.

Para poder desplegar estas imágenes en una aplicación web, necesitamos convertirlas a un formato estándar para la web (JPG, PNG ó GIF). Esto se puede lograr utilizando la librería image magick. Para usarla en Java existen 2 opciones: JMagick e im4java. Decidí utilizar im4java debido a los riesgos de usar JNI en una aplicación web (http://im4java.sourceforge.net/docs/faq.html)

Lo primero es agregar la dependencia de im4java a nuestro proyecto, archivo pom.xml si usas maven o agregar el jar a tu build path.

   <dependency>
      <groupId>org.im4java</groupId>
      <artifactId>im4java</artifactId>
      <version>1.4.0</version>
   </dependency>

Utilizamos un arreglo de bytes para cargar la imágen desde la base de datos y lo pasamos como un stream a la librería im4java para seleccionar la página que deseamos convertir al formato jpg.

    public byte[] getPagina(Integer pagina) throws Exception{
        byte[] imgPagina = null;
        byte[] imagen = loadImageFromDatabase();
        try{
        IMOperation op = new IMOperation();
        op.addImage(String.format("-[%d]", pagina - 1)); // read from stdin and specify page number with 1-based index
        op.addImage("jpg:-");               // write to stdout in jpg-format
        ByteArrayInputStream fis = new ByteArrayInputStream(imagen);
        ByteArrayOutputStream fos = new ByteArrayOutputStream();
        // Pipe pipe = new Pipe(fis,fos);
        Pipe pipeIn  = new Pipe(fis,null);
        Pipe pipeOut = new Pipe(null,fos);
        // set up command
        ConvertCmd convert = new ConvertCmd();
        convert.setInputProvider(pipeIn);
        convert.setOutputConsumer(pipeOut);
        convert.run(op);
        imgPagina = fos.toByteArray();
        }catch(Exception e){
            throw new Exception(
                    "Error al obtener la imágen de la página " + pagina, e);
        }
        return imgPagina;
    }

este método lo podemos utilizar en un servicio web/servlet para servir la imágen a través de una url

    @GET
    @Path("documento/{id}/imagen/pagina/{numero}")
    @Produces("image/jpeg")
    public Response getPaginaPromocion(@PathParam("id")Integer id, @PathParam("numero")Integer numero){
        Response response = null;
        try{
            Documento doc = Documento.get(id);
            response = Response.ok(doc.getPagina(numero), "image/jpeg").build();
        }catch(Exception e){
            String error = String.format("Error al obtener la página %d del documento %s", numero, id);
            log.error(error, e);
            response = Response.serverError().entity(String.format("{\"response\": {\"status\": -1, \"data\": \"%s\"}}", error)).build();
        }
        return response;
    }

Fuentes:

http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=16615#p61020
http://stackoverflow.com/questions/4809314/imagemagick-is-converting-only-the-first-page-of-the-pdf
http://im4java.sourceforge.net/docs/dev-guide.html#piping
http://stackoverflow.com/questions/2091454/byte-to-inputstream-or-outputstream
http://im4java.sourceforge.net/api/

Linux – Comprimir un archivo PDF

Para el registro de errores y tareas utilizamos bugzilla. Cuando me asignan una tarea mediante un oficio, adjunto el documento digitalizado. La mayoría de veces no tengo problemas, pero el día de ayer me arrojó un error debido al tamaño del archivo PDF.

Buscando una forma de reducir el tamaño del PDF (digitalizado mediante CamScanner con una iPad) me encontré este post. La forma que me pareció más sencilla y efectiva fue mediante ghostscript.

Primero asegurate de tener instalado ghostscript

sudo apt-get install ghostscript

Simplemente crea un archivo llamado shrinkpdf.sh en tu carpeta ~/bin o cualquiera que se encuentre en el path con el siguiente contenido.

    #!/bin/sh
    dpi=72
    if [ $# -lt 2 ]
    then
       echo "usage: $0 input output [dpi]"
       exit 1
    fi
    if [ $# -gt 2 ]
    then
       dpi=$3
    fi
    echo "Shrinking document..."
    gs  -q -dNOPAUSE -dBATCH -dSAFER \
        -sDEVICE=pdfwrite \
        -dCompatibilityLevel=1.3 \
        -dPDFSETTINGS=/screen \
        -dEmbedAllFonts=true \
        -dSubsetFonts=true \
        -dColorImageDownsampleType=/Bicubic \
        -dColorImageResolution=$dpi \
        -dGrayImageDownsampleType=/Bicubic \
        -dGrayImageResolution=$dpi \
        -dMonoImageDownsampleType=/Bicubic \
        -dMonoImageResolution=$dpi \
        -sOutputFile=$2 \
         $1

hazlo ejecutable con el comando

chmod a+x ~/bin/shrinkpdf.sh

finalmente utilizalo para comprimir cualquier archivo PDF de la siguiente forma

shrinkpdf.sh ~/input.pdf ~/output.pdf 150

El último parámetro le indica la resolución que va a utilizar. 150 dpi en el ejemplo, el cual produce una buena calidad de las imágenes. Puedes omitir este parámetro y por default utilizará una resolución de 72 dpi que produce archivos mucho más pequeños pero pierde calidad.

Ubuntu – Instalar fuentes

Necesitaba hacer un reporte con un tipo de letra que no viene instalado en Ubuntu por default, así que investigando un poco encontré que hay varias ubicaciones donde puedes copiar el archivo de la fuente. Estas ubicaciones están definidas en el archivo /etc/fonts/fonts.conf. Por default incluye /usr/share/fonts, /usr/local/share/fonts y /home//.fonts (dónde es tu nombre de usuario).

Lo más fácil es crear la carpeta .fonts, si no existe, en tu carpeta de usuario.

mkdir ~/.fonts

Luego copia ahí las fuentes que deseas instalar.

Finalmente ejecuta el comando

sudo fc-cache -f -v

para actualizar la lista de fuentes disponibles, luego cierra y abre los programas dónde deseas utilizar la fuente o reinicia tu máquina y listo!

Fuentes:
https://wiki.ubuntu.com/Fonts#Manually