no

Building a rest service that returns a byte array image

This tutorial will not delve into angular nor will we discuss what a directive is. We will not try to explain what a rest web service is. In...

This tutorial will not delve into angular nor will we discuss what a directive is. We will not try to explain what a rest web service is. Instead we will provide a demonstration via actual code, how we can consume a rest service from angular that returns an array of byte and display it as an image. We will also provide a default image in case the web service fails to return a valid image.
There are many ways to do it, but I chose a directive because of its simplicity.

Here's the directive code:

import {Directive, OnInit, Input} from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import {HttpClient} from '@angular/common/http';
import { DomSanitizer, } from '@angular/platform-browser';
import { environment } from 'environments/environment';

import { Logger } from "angular2-logger/core";

/**
 * Usage:
 * 
 * <img [image-loader]="object.id" [file]="file" imageType="VENDOR_PROFILE" />
 */
@Directive({
    selector: '[image-loader]',
    host: {
        '[src]': 'sanitizer.bypassSecurityTrustUrl(imageData)'
    }
})
export class ImageLoaderDirective implements OnInit {

    url: string;
    apiUrl: string
    imageData: any;
    @Input('image-loader') vendorId: number;
    @Input('imageType') imageType: string;

    constructor(private http: HttpClient, private sanitizer: DomSanitizer, private logger: Logger) {
        this.apiUrl = environment.apiUrl;
    }

    ngOnInit() {
        this.imageData = 'assets/images/missing-image.jpg';

        if (this.vendorId && this.imageType) {
            if (this.imageType == 'VENDOR_PROFILE') {
                this.url = environment.imageType[this.imageType].replace("{id}", "" + this.vendorId);
            }

            this.url = this.apiUrl + this.url
            this.http.get<any>(this.url)
                .subscribe(
                data => {
                    let mimeType = data.mimeType;
                    this.imageData = 'data:' + mimeType + ';base64,' + data.imageContent;
                },
                (err: HttpErrorResponse) => {
                    if (err.status != 200) {
                        if (this.imageType == 'VENDOR_PROFILE') {
                            this.imageData = 'assets/images/missing-vendor-profile.jpg';
                        } else {
                         this.imageData = 'assets/images/missing-image.jpg';    
                        }
                        if (err.error instanceof Error) {
                            // A client-side or network error occurred. Handle it accordingly.
                            console.log('Error fetching image:', err.error.message);
                        } else {
                            // normally this happens if the object returned is not of json format
                            // this can cause quite the trouble
                            console.log(`Error fetching image: code=${err.status}, message=${err.error}`);
                        }
                    }
                }
                );
        }

    }
}

Sample usage is defined at the top of the code. What it does is it accepts an id and imageType as parameters. We use the id to get the image from the rest service; imageType is used to construct different url depending on its value. This is so we can reused this directive.

The rest service:

// rest interface
@GET
@Path("/{id}/profileImage")
Response profileImage(@PathParam("id") Long id);

// implementing rest class
@Override
public Response profileImage(Long id) {
 Response.ResponseBuilder responseBuilder = null;

 try {
  responseBuilder = Response.ok();
  responseBuilder.entity(vendorApi.profileImage(id, httpServletResponse));

 } catch (Exception e) {
  responseBuilder = processException(e);
 }

 Response response = responseBuilder.build();
 log.debug("RESPONSE={}", response.getEntity());
 return response;
}

// get the image
public ImageDto profileImage(Long id, HttpServletResponse response) {
 Vendor vendor = vendorRepository.findById(id);
 if (vendor == null || StringUtils.isBlank(vendor.getProfileImageFile())) {
  throw new EntityDoesNotExistsException(Vendor.class, id);
 }

 File file = new File(getAppRootDir() + File.separator + id + File.separator + vendor.getProfileImageFile());
 if (!file.exists()) {
  throw new FileDoesNotExistsException("File does not exists: " + file.getPath());
 }

 try {
  String encodeImage = Base64.getEncoder().withoutPadding().encodeToString(Files.readAllBytes(file.toPath()));
  ImageDto imageDto = new ImageDto();
  imageDto.setImageContent(encodeImage);
  imageDto.setMimeType(ImageUtils.probeMimeType(file));

  return imageDto;
 } catch (IOException e) {
  throw new BusinessApiException("Error fetching file: " + file.getName() + ". " + e.getMessage());
 }
}
The last method accepts the object id, and use it to query the object that contains the filename of the image. We get the image path and convert it to byte[] using Base64 class. Note that we use a dto to store the byte[] and mimeType, this will let us return the information as json, instead of just returning a byte[], which often caused problem. Also note that we send the mimeType, we need it when displaying the image.

Related

javaee-rest 4512153973485633469

Post a Comment Default Comments

item