ImageConversionRestController.java
package org.imageconverter.controller;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.imageconverter.util.controllers.imageconverter.ImageConverterConst.REST_URL;
import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.imageconverter.application.ImageConversionService;
import org.imageconverter.domain.conversion.ExecutionType;
import org.imageconverter.domain.conversion.ImageConversion;
import org.imageconverter.util.controllers.imageconverter.ImageConversionPostResponse;
import org.imageconverter.util.controllers.imageconverter.ImageConversionResponse;
import org.imageconverter.util.controllers.imageconverter.ImageConverterRequest;
import org.imageconverter.util.controllers.imageconverter.ImageConverterRequestArea;
import org.imageconverter.util.controllers.imageconverter.ImageConverterRequestInterface;
import org.imageconverter.util.logging.Loggable;
import org.imageconverter.util.openapi.imageconverter.ImageConverterRestGetByIdOpenApi;
import org.imageconverter.util.openapi.imageconverter.ImageConverterRestGetOpenApi;
import org.imageconverter.util.openapi.imageconverter.ImageConverterRestPostAreaOpenApi;
import org.imageconverter.util.openapi.imageconverter.ImageConverterRestPostOpenApi;
import org.imageconverter.util.openapi.imagetype.ImageTypeRestDeleteOpenApi;
import org.springdoc.core.converters.models.PageableAsQueryParam;
import org.springframework.context.annotation.Description;
import org.springframework.core.io.InputStreamResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.turkraft.springfilter.boot.Filter;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* Image converter http rest.
*
* @author Fernando Romulo da Silva
*/
@SecurityRequirement(name = "BASIC")
@Tag( //
name = "Image Convert", //
description = """
Image Convert API - If something went wrong, please put 'trace' (for all Http methods)
at the end of the call to receive the stackStrace.
Ex: http://127.0.0.1:8080/image-converter/rest/images/convert?trace=true
""" //
)
//
@Loggable
@RestController
@Description("Controller for image converstion API")
@RequestMapping(REST_URL)
public class ImageConversionRestController {
private final ImageConversionService imageConversionService;
/**
* Default constructor.
*
* @param imageConversionService The image convert service
*/
ImageConversionRestController(final ImageConversionService imageConversionService) {
super();
this.imageConversionService = imageConversionService;
}
/**
* Get a conversion already done.
*
* @param id The image conversion's id
* @return A {@link ImageConversionResponse} object
* @exception ElementNotFoundException if a element with id not found
*/
@ImageConverterRestGetByIdOpenApi
//
@ResponseStatus(OK)
@GetMapping(value = "/{id:[\\d]*}", produces = APPLICATION_JSON_VALUE)
public ImageConversionResponse getById( //
@Parameter(name = "id", description = "The image conversion id's", required = true, example = "3") //
@PathVariable(name = "id", required = true) //
final Long id) {
return imageConversionService.findById(id);
}
/**
* Get conversions by filter.
*
* @param filter A object {@link Specification} that specific the filter the search
* @param page A object {@link Pageable} that page the result
* @return A {@link List} or a empty list
*/
@PageableAsQueryParam
@ImageConverterRestGetOpenApi
//
@ResponseStatus(OK)
@GetMapping(produces = APPLICATION_JSON_VALUE)
public Page<ImageConversionResponse> getByFilter( //
@Parameter(name = "filter", description = "Search's filter", required = true, example = "?filter=fileName:'image.png'") //
@Filter //
final Specification<ImageConversion> filter, //
//
@PageableDefault(value = 10, page = 0) //
final Pageable page) {
return imageConversionService.findBySpecification(filter, page);
}
/**
* Convert a image file on text.
*
* @param file The image to convert
* @return A {@link ImageConversionResponse} object with response.
*/
@ImageConverterRestPostOpenApi
//
@ResponseStatus(CREATED)
@PostMapping(consumes = { MULTIPART_FORM_DATA_VALUE }, produces = APPLICATION_JSON_VALUE)
public ImageConversionPostResponse convert( //
@Parameter(description = "The Image to be uploaded", content = @Content(mediaType = MULTIPART_FORM_DATA_VALUE), required = true, example = "image.bmp") //
@RequestPart(name = "file", required = true) //
final MultipartFile file,
//
final HttpServletRequest request, final HttpServletResponse response) {
final var bytes = extractBytes(file);
final var executionType = extractExecutionType(request);
final var result = imageConversionService.convert(new ImageConverterRequest(file.getOriginalFilename(), bytes, executionType));
response.addHeader("Location", REST_URL + "/" + result.id());
return new ImageConversionPostResponse(result.text());
}
/**
* Convert a image file with area on text.
*
* @param file The image to convert
* @param xAxis The image's x coordinate
* @param yAxis The image's y coordinate
* @param width The image's width in pixels
* @param height The image's height in pixels
* @return A {@link ImageConversionResponse} object with response.
*/
@ImageConverterRestPostAreaOpenApi
//
@ResponseStatus(CREATED)
@PostMapping(value = "/area", consumes = { MULTIPART_FORM_DATA_VALUE }, produces = APPLICATION_JSON_VALUE)
public ImageConversionPostResponse convertWithArea( //
@Parameter(description = "The Image to be uploaded", content = @Content(mediaType = MULTIPART_FORM_DATA_VALUE), required = true, example = "image.bmp") //
@RequestPart(name = "file", required = true) //
final MultipartFile file, //
//
@Parameter(description = "The vertical position", required = true, example = "3") //
@RequestParam(required = true) //
final Integer xAxis, //
//
@Parameter(description = "The horizontal position", required = true, example = "4") //
@RequestParam(required = true) //
final Integer yAxis, //
//
@Parameter(description = "The width size's area", required = true, example = "56") //
@RequestParam(required = true) //
final Integer width, //
//
@Parameter(description = "The height's size area ", required = true, example = "345") //
@RequestParam(required = true) //
final Integer height,
//
final HttpServletRequest request, final HttpServletResponse response) {
final var executionType = extractExecutionType(request);
final byte[] bytes = extractBytes(file);
final var result = imageConversionService.convert(new ImageConverterRequestArea(file.getOriginalFilename(), bytes, executionType, xAxis, yAxis, width, height));
response.addHeader("Location", REST_URL + "/" + result.id());
return new ImageConversionPostResponse(result.text());
}
/**
* Convert multiple images file on text.
*
* @param files The images' collection to convert
* @return A list of {@link ImageConversionResponse} with each response.
*/
@ImageConverterRestPostOpenApi
//
@ResponseStatus(CREATED)
@PostMapping(value = "/multiple", consumes = { MULTIPART_FORM_DATA_VALUE }, produces = APPLICATION_JSON_VALUE)
public List<ImageConversionPostResponse> convert( //
@Parameter(description = "The Images to be uploaded", content = @Content(mediaType = MULTIPART_FORM_DATA_VALUE), required = true, example = "image1.bmp, image2.png") //
@RequestPart(name = "files", required = true) //
final MultipartFile[] files, //
//
final HttpServletRequest request, //
final HttpServletResponse response) {
final var executionType = extractExecutionType(request);
final var listRequest = new ArrayList<ImageConverterRequestInterface>();
for (final var file : files) {
listRequest.add(new ImageConverterRequest(file.getOriginalFilename(), extractBytes(file), executionType));
}
final var result = imageConversionService.convert(listRequest);
response.addHeader("Location", result.stream().map(rst -> REST_URL + "/" + rst.id()).collect(joining(";")));
return result.stream().map(rst -> new ImageConversionPostResponse(rst.text())).toList();
}
/**
* Delete a image conversion.
*
* @param id The conversion id
*/
@ImageTypeRestDeleteOpenApi
//
@ResponseStatus(NO_CONTENT)
@DeleteMapping("/{id:[\\d]*}")
public void delete( //
//
@Parameter(description = "The conversion id's", example = "1000") //
@PathVariable(name = "id", required = true) //
final Long id) {
imageConversionService.deleteImageConversion(id);
}
/**
* Create a CSV file using filter.
*
* @param filter A object {@link Specification} that specific the filter the search
* @return A Csv file
*/
@ResponseStatus(OK)
@GetMapping(value = "/export", produces = "txt/csv")
public ResponseEntity<InputStreamResource> downloadImageConversionCsv( //
@Parameter(name = "filter", description = "Search's filter", required = true, example = "?filter=fileName:'image.png'") //
@Filter //
final Specification<ImageConversion> filter ) {
final var bytes = imageConversionService.findBySpecificationToCsv(filter);
final var body = new InputStreamResource(new ByteArrayInputStream(bytes));
return ResponseEntity.ok()
.header(CONTENT_DISPOSITION, "attachment; filename=convertions.csv")
.contentType(MediaType.parseMediaType("txt/csv"))
.body(body);
}
private byte[] extractBytes(final MultipartFile file) {
byte[] bytes;
try {
bytes = file.getBytes();
} catch (final IOException e) {
bytes = new byte[0];
}
return bytes;
}
private ExecutionType extractExecutionType(final HttpServletRequest request) {
final var executionTypeHeader = Optional.ofNullable(request.getHeader("Execution-Type")).orElse(EMPTY);
return ExecutionType.from(executionTypeHeader);
}
}