diff --git a/src/main/java/com/krylov/refound/controller/PostController.java b/src/main/java/com/krylov/refound/controller/PostController.java index 411476c..4edf1dc 100644 --- a/src/main/java/com/krylov/refound/controller/PostController.java +++ b/src/main/java/com/krylov/refound/controller/PostController.java @@ -1,13 +1,16 @@ package com.krylov.refound.controller; +import com.fasterxml.jackson.core.JsonProcessingException; import com.krylov.refound.dto.PostRequest; import com.krylov.refound.dto.PostResponse; import com.krylov.refound.dto.StatusUpdateRequest; import com.krylov.refound.enums.PostType; import com.krylov.refound.service.PostService; +import java.util.Arrays; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.http.MediaType; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.DeleteMapping; @@ -31,11 +34,13 @@ import org.springframework.web.multipart.MultipartFile; public class PostController { private final PostService service; + private final ObjectMapper objectMapper; @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public PostRequest create(@ModelAttribute PostRequest request, @RequestPart(value = "image", required = false) MultipartFile image) { + public PostRequest create(@ModelAttribute PostRequest request, + @RequestParam(value = "images", required = false) List images) { log.info(request.toString()); - return service.create(request, image); + return service.create(request, images); } @GetMapping @@ -44,7 +49,7 @@ public class PostController { } @GetMapping("/{id}") - public List getById(@PathVariable Long id) { + public List getById(@PathVariable Long id) { return service.getById(id); } @@ -59,8 +64,8 @@ public class PostController { @RequestParam(required = false) String description, @RequestParam(required = false) String category, @RequestParam(required = false) String phone, - @RequestParam(value = "image", required = false) MultipartFile image - ) { + @RequestParam(value = "images", required = false) List images, + @RequestParam(value = "existingImages", required = false) String existingImagesJson) { PostRequest request = new PostRequest(); request.setType(PostType.from(type)); request.setTitle(title); @@ -70,8 +75,15 @@ public class PostController { request.setLatitude(latitude); request.setLongitude(longitude); request.setAddress(address); + List existingUrls; + try { + existingUrls = existingImagesJson != null ? Arrays.asList( + objectMapper.readValue(existingImagesJson, String[].class)) : List.of(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } - return service.update(id, request, image); + return service.update(id, request, images, existingUrls); } @DeleteMapping("/{id}") @@ -80,7 +92,8 @@ public class PostController { } @PatchMapping("/{id}/status") - public PostResponse updateStatus(@PathVariable Long id, @RequestBody StatusUpdateRequest request) { + public PostResponse updateStatus(@PathVariable Long id, + @RequestBody StatusUpdateRequest request) { return service.updateStatus(id, request.getStatus()); } } diff --git a/src/main/java/com/krylov/refound/service/PostService.java b/src/main/java/com/krylov/refound/service/PostService.java index 7223795..7e6f782 100644 --- a/src/main/java/com/krylov/refound/service/PostService.java +++ b/src/main/java/com/krylov/refound/service/PostService.java @@ -44,7 +44,7 @@ public class PostService { private final UserService userService; private final FavoriteRepository favoriteRepository; - public PostRequest create(PostRequest request, MultipartFile image) { + public PostRequest create(PostRequest request, List images) { Post post = mapper.toEntity(request); post.setCreatedAt(LocalDateTime.now()); @@ -52,21 +52,32 @@ public class PostService { post.setUser(userService.getCurrentUser()); // присваиваем текущего пользователя repository.save(post); // сначала сохраняем post, чтобы получить id - if (image != null && !image.isEmpty()) { - String filename = UUID.randomUUID() + "_" + image.getOriginalFilename(); + if (images != null && !images.isEmpty()) { Path uploadDir = Paths.get("uploads"); - try { Files.createDirectories(uploadDir); - Files.copy(image.getInputStream(), uploadDir.resolve(filename)); } catch (IOException e) { - throw new RuntimeException("Не удалось сохранить файл: " + filename, e); + throw new RuntimeException("Не удалось создать директорию загрузки", e); } - Image img = new Image(); - img.setUrl("/uploads/" + filename); - img.setPost(post); - imageRepository.save(img); + for (MultipartFile image : images) { + if (image == null || image.isEmpty()) { + continue; + } + + String filename = UUID.randomUUID() + "_" + image.getOriginalFilename(); + + try { + Files.copy(image.getInputStream(), uploadDir.resolve(filename)); + } catch (IOException e) { + throw new RuntimeException("Не удалось сохранить файл: " + filename, e); + } + + Image img = new Image(); + img.setUrl("/uploads/" + filename); + img.setPost(post); + imageRepository.save(img); + } } return request; @@ -146,8 +157,7 @@ public class PostService { .toList(); } - public PostResponse update(Long id, PostRequest request, MultipartFile image) { - + public PostResponse update(Long id, PostRequest request, List images, List existingUrls) { Post post = repository.findById(id) .orElseThrow(() -> new ApiException( ErrorCode.NOT_FOUND, @@ -162,41 +172,59 @@ public class PostService { } post.setPhone(request.getPhone()); post.setType(request.getType()); - if (request.getLatitude() != null && request.getLongitude() != null){ + + if (request.getLatitude() != null && request.getLongitude() != null) { post.setLatitude(request.getLatitude()); post.setLongitude(request.getLongitude()); - String address = nominatimService.getAddress(request.getLatitude().toString(), request.getLongitude().toString()); + String address = nominatimService.getAddress( + request.getLatitude().toString(), request.getLongitude().toString()); post.setCity(address); } else { post.setCity(request.getAddress()); } - if (image != null && !image.isEmpty()) { - // удаляем старые картинки с диска - post.getImages().forEach(img -> { - try { - Files.deleteIfExists(Paths.get("." + img.getUrl())); - } catch (IOException e) { - log.warn("Не удалось удалить файл: {}", img.getUrl()); - } - }); - // очищаем список (orphanRemoval = true удалит из БД) - post.getImages().clear(); + List keepUrls = existingUrls != null ? existingUrls : List.of(); - // сохраняем новую картинку - String filename = UUID.randomUUID() + "_" + image.getOriginalFilename(); + // удаляем те картинки, которых нет среди "оставленных" с фронта + List toRemove = post.getImages().stream() + .filter(img -> !keepUrls.contains(img.getUrl())) + .toList(); + + toRemove.forEach(img -> { + try { + Files.deleteIfExists(Paths.get("." + img.getUrl())); + } catch (IOException e) { + log.warn("Не удалось удалить файл: {}", img.getUrl()); + } + }); + + post.getImages().removeAll(toRemove); // orphanRemoval = true удалит из БД + + // добавляем новые загруженные файлы + if (images != null && !images.isEmpty()) { Path uploadDir = Paths.get("uploads"); try { Files.createDirectories(uploadDir); - Files.copy(image.getInputStream(), uploadDir.resolve(filename)); } catch (IOException e) { - throw new RuntimeException("Не удалось сохранить файл: " + filename, e); + throw new RuntimeException("Не удалось создать директорию загрузки", e); } - Image img = new Image(); - img.setUrl("/uploads/" + filename); - img.setPost(post); - post.getImages().add(img); + for (MultipartFile image : images) { + if (image == null || image.isEmpty()) { + continue; + } + String filename = UUID.randomUUID() + "_" + image.getOriginalFilename(); + try { + Files.copy(image.getInputStream(), uploadDir.resolve(filename)); + } catch (IOException e) { + throw new RuntimeException("Не удалось сохранить файл: " + filename, e); + } + + Image img = new Image(); + img.setUrl("/uploads/" + filename); + img.setPost(post); + post.getImages().add(img); + } } Post updated = repository.save(post);