From df98dfe38e0a81f08b096d8120041bab61f6e266 Mon Sep 17 00:00:00 2001 From: Vincent Guillet Date: Wed, 3 Dec 2025 14:22:47 +0100 Subject: [PATCH] Refactor PrestashopClient to enhance image upload handling and improve error logging --- .../service/prestashop/PrestashopClient.java | 70 +++++++++++++------ 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/api/src/main/java/fr/gameovergne/api/service/prestashop/PrestashopClient.java b/api/src/main/java/fr/gameovergne/api/service/prestashop/PrestashopClient.java index ed9605b..9f1eb42 100644 --- a/api/src/main/java/fr/gameovergne/api/service/prestashop/PrestashopClient.java +++ b/api/src/main/java/fr/gameovergne/api/service/prestashop/PrestashopClient.java @@ -2,13 +2,11 @@ package fr.gameovergne.api.service.prestashop; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestClient; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestClientResponseException; @@ -239,42 +237,70 @@ public class PrestashopClient { String rawQuery, MultipartFile imageFile) { try { - StringBuilder url = new StringBuilder(baseUrl) + // 1) URL complète vers Presta + StringBuilder urlBuilder = new StringBuilder(baseUrl) .append("/images/products/") .append(productId); if (rawQuery != null && !rawQuery.isBlank()) { - url.append("?").append(rawQuery); + urlBuilder.append("?").append(rawQuery); } + String url = urlBuilder.toString(); - // Corps multipart avec un champ "image" comme demandé par PrestaShop - MultiValueMap body = new LinkedMultiValueMap<>(); + byte[] bytes = imageFile.getBytes(); - ByteArrayResource imageResource = new ByteArrayResource(imageFile.getBytes()) { - @Override - public String getFilename() { - // PrestaShop veut un filename, même si ce n'est pas critique - return imageFile.getOriginalFilename() != null - ? imageFile.getOriginalFilename() - : "image.jpg"; + // 2) Headers de la PART "image" + HttpHeaders partHeaders = new HttpHeaders(); + + MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM; + if (imageFile.getContentType() != null && !imageFile.getContentType().isBlank()) { + try { + mediaType = MediaType.parseMediaType(imageFile.getContentType()); + } catch (Exception ignored) { + // on garde OCTET_STREAM } - }; + } + partHeaders.setContentType(mediaType); - body.add("image", imageResource); // 👈 IMPORTANT : le nom du champ = "image" + // Content-Disposition: form-data; name="image"; filename="xxx.jpg" + ContentDisposition disposition = ContentDisposition + .builder("form-data") + .name("image") + .filename(imageFile.getOriginalFilename()) + .build(); + partHeaders.setContentDisposition(disposition); + + // 3) Entity de la PART (équivalent ByteArrayContent en C#) + HttpEntity imagePart = new HttpEntity<>(bytes, partHeaders); + + // 4) Corps multipart : clé "image" + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("image", imagePart); log.info("[PrestaShop] POST (image multipart) {} (size={} bytes, contentType={})", - url, imageFile.getSize(), imageFile.getContentType()); + url, bytes.length, mediaType); - return client - .post() - .uri(url.toString()) + // 5) Appel Presta via RestClient + return client.post() + .uri(url) .contentType(MediaType.MULTIPART_FORM_DATA) .body(body) .retrieve() .toEntity(String.class); + } catch (HttpClientErrorException e) { + // on log ce que renvoie Presta et on renvoie tel quel au front + log.error("[PrestaShop] POST image error {} : {}", + e.getStatusCode().value(), e.getResponseBodyAsString()); + return ResponseEntity + .status(e.getStatusCode()) + .contentType(MediaType.APPLICATION_XML) + .body(e.getResponseBodyAsString()); } catch (IOException e) { - throw new RuntimeException("Erreur lors de la lecture du fichier image", e); + log.error("[PrestaShop] Erreur lecture fichier image", e); + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Erreur lecture image côté API"); } } } \ No newline at end of file