diff --git a/src/main/java/com/favoriteplace/app/controller/PostController.java b/src/main/java/com/favoriteplace/app/controller/PostController.java index 0bf982a..eb7f90c 100644 --- a/src/main/java/com/favoriteplace/app/controller/PostController.java +++ b/src/main/java/com/favoriteplace/app/controller/PostController.java @@ -125,8 +125,7 @@ public ResponseEntity modifyPost( Member member = securityUtil.getUser(); postCommandService.modifyPost(postId, data, images, member); return new ResponseEntity<>( - PostResponseDto.SuccessResponseDto.builder().message("게시글이 수정되었습니다.").build(), - HttpStatus.OK + HttpStatus.NO_CONTENT ); } } diff --git a/src/main/java/com/favoriteplace/app/domain/community/GuestBook.java b/src/main/java/com/favoriteplace/app/domain/community/GuestBook.java index 801456e..b03279c 100644 --- a/src/main/java/com/favoriteplace/app/domain/community/GuestBook.java +++ b/src/main/java/com/favoriteplace/app/domain/community/GuestBook.java @@ -1,23 +1,29 @@ package com.favoriteplace.app.domain.community; +import static jakarta.persistence.FetchType.LAZY; +import static jakarta.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; + import com.favoriteplace.app.domain.Image; import com.favoriteplace.app.domain.Member; import com.favoriteplace.app.domain.common.BaseTimeEntity; import com.favoriteplace.app.domain.travel.Pilgrimage; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.ArrayList; -import java.util.List; - -import static jakarta.persistence.FetchType.LAZY; -import static jakarta.persistence.GenerationType.IDENTITY; -import static lombok.AccessLevel.PRIVATE; -import static lombok.AccessLevel.PROTECTED; - @Getter @Builder @NoArgsConstructor(access = PROTECTED) @@ -87,4 +93,14 @@ public void addComment(Comment comment){ this.comments.add(comment); } + public void addImages(List imageUrls){ + for(String imageUrl:imageUrls){ + Image newImage = Image.builder() + .guestBook(this) + .url(imageUrl) + .build(); + this.images.add(newImage); + } + } + } diff --git a/src/main/java/com/favoriteplace/app/domain/community/Post.java b/src/main/java/com/favoriteplace/app/domain/community/Post.java index ac84e1f..71eda17 100644 --- a/src/main/java/com/favoriteplace/app/domain/community/Post.java +++ b/src/main/java/com/favoriteplace/app/domain/community/Post.java @@ -1,22 +1,28 @@ package com.favoriteplace.app.domain.community; +import static jakarta.persistence.FetchType.LAZY; +import static jakarta.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PRIVATE; +import static lombok.AccessLevel.PROTECTED; + import com.favoriteplace.app.domain.Image; import com.favoriteplace.app.domain.Member; import com.favoriteplace.app.domain.common.BaseTimeEntity; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.ArrayList; -import java.util.List; - -import static jakarta.persistence.FetchType.LAZY; -import static jakarta.persistence.GenerationType.IDENTITY; -import static lombok.AccessLevel.PRIVATE; -import static lombok.AccessLevel.PROTECTED; - @Getter @Builder @NoArgsConstructor(access = PROTECTED) @@ -74,4 +80,14 @@ public void disconnectImages(){ this.images = new ArrayList<>(); } + public void addImages(List imageUrls){ + for(String imageUrl:imageUrls){ + Image newImage = Image.builder() + .post(this) + .url(imageUrl) + .build(); + this.images.add(newImage); + } + } + } diff --git a/src/main/java/com/favoriteplace/app/domain/enums/ItemType.java b/src/main/java/com/favoriteplace/app/domain/enums/ItemType.java index 962ebae..1fd54f4 100644 --- a/src/main/java/com/favoriteplace/app/domain/enums/ItemType.java +++ b/src/main/java/com/favoriteplace/app/domain/enums/ItemType.java @@ -1,6 +1,5 @@ package com.favoriteplace.app.domain.enums; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/favoriteplace/app/service/MemberService.java b/src/main/java/com/favoriteplace/app/service/MemberService.java index c30da63..004e07b 100644 --- a/src/main/java/com/favoriteplace/app/service/MemberService.java +++ b/src/main/java/com/favoriteplace/app/service/MemberService.java @@ -1,5 +1,10 @@ package com.favoriteplace.app.service; +import static com.favoriteplace.global.exception.ErrorCode.NOT_SIGNUP_WITH_KAKAO; +import static com.favoriteplace.global.exception.ErrorCode.TOKEN_NOT_VALID; +import static com.favoriteplace.global.exception.ErrorCode.USER_ALREADY_EXISTS; +import static com.favoriteplace.global.exception.ErrorCode.USER_NOT_FOUND; + import com.favoriteplace.app.domain.Member; import com.favoriteplace.app.domain.item.Item; import com.favoriteplace.app.dto.UserInfoResponseDto; @@ -12,13 +17,13 @@ import com.favoriteplace.app.repository.ItemRepository; import com.favoriteplace.app.repository.MemberRepository; import com.favoriteplace.global.exception.RestApiException; -import com.favoriteplace.global.gcpImage.UploadImage; import com.favoriteplace.global.s3Image.AmazonS3ImageManager; import com.favoriteplace.global.security.kakao.KakaoClient; import com.favoriteplace.global.security.provider.JwtTokenProvider; import com.favoriteplace.global.util.SecurityUtil; - +import java.io.IOException; import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import lombok.RequiredArgsConstructor; @@ -29,11 +34,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import java.io.IOException; -import java.util.List; - -import static com.favoriteplace.global.exception.ErrorCode.*; - @Service @Transactional(readOnly = true) @RequiredArgsConstructor diff --git a/src/main/java/com/favoriteplace/app/service/community/GuestBookCommandService.java b/src/main/java/com/favoriteplace/app/service/community/GuestBookCommandService.java index acf108b..2c2c3e7 100644 --- a/src/main/java/com/favoriteplace/app/service/community/GuestBookCommandService.java +++ b/src/main/java/com/favoriteplace/app/service/community/GuestBookCommandService.java @@ -1,7 +1,6 @@ package com.favoriteplace.app.service.community; import com.favoriteplace.app.converter.PointHistoryConverter; -import com.favoriteplace.app.domain.Image; import com.favoriteplace.app.domain.Member; import com.favoriteplace.app.domain.community.GuestBook; import com.favoriteplace.app.domain.community.HashTag; @@ -10,23 +9,26 @@ import com.favoriteplace.app.domain.travel.VisitedPilgrimage; import com.favoriteplace.app.dto.community.GuestBookRequestDto; import com.favoriteplace.app.dto.community.PostResponseDto; -import com.favoriteplace.app.repository.*; +import com.favoriteplace.app.repository.GuestBookRepository; +import com.favoriteplace.app.repository.HashtagRepository; +import com.favoriteplace.app.repository.ImageRepository; +import com.favoriteplace.app.repository.LikedPostRepository; +import com.favoriteplace.app.repository.PilgrimageRepository; +import com.favoriteplace.app.repository.PointHistoryRepository; +import com.favoriteplace.app.repository.VisitedPilgrimageRepository; import com.favoriteplace.global.exception.ErrorCode; import com.favoriteplace.global.exception.RestApiException; -import com.favoriteplace.global.gcpImage.ConvertUuidToUrl; import com.favoriteplace.global.gcpImage.UploadImage; +import com.favoriteplace.global.s3Image.AmazonS3ImageManager; +import java.io.IOException; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; - @Service @Slf4j @RequiredArgsConstructor @@ -39,6 +41,7 @@ public class GuestBookCommandService { private final HashtagRepository hashtagRepository; private final VisitedPilgrimageRepository visitedPilgrimageRepository; private final PointHistoryRepository pointHistoryRepository; + private final AmazonS3ImageManager amazonS3ImageManager; /** * 성지순례 인증글 수정 @@ -53,15 +56,23 @@ public void modifyGuestBook(Member member, Long guestbookId, GuestBookRequestDto checkAuthOfGuestBook(member, guestBook); Optional.ofNullable(data.getTitle()).ifPresent(guestBook::setTitle); Optional.ofNullable(data.getContent()).ifPresent(guestBook::setContent); + guestBook.getHashTags().clear(); //기존에 있던 hashtag 제거 guestBook.getImages().clear(); //기존에 있던 이미지 제거 imageRepository.deleteByGuestBookId(guestbookId); + List hashtags = data.getHashtags(); if(!hashtags.isEmpty()){ hashtags.forEach(hashtag -> guestBook.setHashTag(HashTag.builder().tagName(hashtag).build())); } - if(images != null && !images.isEmpty()){setImageList(guestBook, images);} - guestBookRepository.save(guestBook); + + // 새로운 이미지 등록 + try{ + List imageUrls = amazonS3ImageManager.uploadMultiImages(images); + guestBook.addImages(imageUrls); + }catch (IOException e){ + log.info("[guestBook image] image 없음"); + } } /** @@ -77,36 +88,31 @@ public void deleteGuestBook(Member member, Long guestbookId) { guestBookRepository.deleteById(guestbookId); } - /** - * 이미지가 여러개일 때, 이미지 처리하는 로직 (새로운 이미지 저장) - * @param guestBook - * @param images - * @throws IOException - */ - private void setImageList(GuestBook guestBook, List images) throws IOException { - List> futures = new ArrayList<>(); - for(MultipartFile image:images){ - if(image != null && !image.isEmpty()){ - CompletableFuture future = CompletableFuture.runAsync(() -> { - try { - String uuid = uploadImage.uploadImageToCloud(image); - Image newImage = Image.builder().url(ConvertUuidToUrl.convertUuidToUrl(uuid)).build(); - guestBook.setImage(newImage); - } catch (IOException e) { - throw new RestApiException(ErrorCode.IMAGE_CANNOT_UPLOAD); - } - }); - futures.add(future); - } -// if(!image.isEmpty()){ -// String uuid = uploadImage.uploadImageToCloud(image); -// Image newImage = Image.builder().url(ConvertUuidToUrl.convertUuidToUrl(uuid)).build(); -// guestBook.setImage(newImage); +// /** +// * 이미지가 여러개일 때, 이미지 처리하는 로직 (새로운 이미지 저장) +// * @param guestBook +// * @param images +// * @throws IOException +// */ +// private void setImageList(GuestBook guestBook, List images) throws IOException { +// List> futures = new ArrayList<>(); +// for(MultipartFile image:images){ +// if(image != null && !image.isEmpty()){ +// CompletableFuture future = CompletableFuture.runAsync(() -> { +// try { +// String uuid = uploadImage.uploadImageToCloud(image); +// Image newImage = Image.builder().url(ConvertUuidToUrl.convertUuidToUrl(uuid)).build(); +// guestBook.setImage(newImage); +// } catch (IOException e) { +// throw new RestApiException(ErrorCode.IMAGE_CANNOT_UPLOAD); +// } +// }); +// futures.add(future); // } - } - // 작업 다 끝날때 까지 기다림 - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - } +// } +// // 작업 다 끝날때 까지 기다림 +// CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); +// } /** * 성지순례 인증글의 작성자가 맞는지 판단하는 함수 @@ -149,12 +155,21 @@ public PostResponseDto.SuccessResponseDto postGuestBook(Member member, Long pilg newGuestBook.setHashTag(newHashTag); }); - if (images != null && !images.isEmpty()) { - setImageList(newGuestBook, images); +// if (images != null && !images.isEmpty()) { +// setImageList(newGuestBook, images); +// } + // 새로운 이미지 등록 + try{ + List imageUrls = amazonS3ImageManager.uploadMultiImages(images); + newGuestBook.addImages(imageUrls); + }catch (IOException e){ + log.info("[guestBook image] image 없음"); } log.info("success image upload"); + successPostAndPointProcess(member, pilgrimage); log.info("success point update"); + return PostResponseDto.SuccessResponseDto.builder().message("인증글 작성에 성공했습니다.").build(); } diff --git a/src/main/java/com/favoriteplace/app/service/community/PostCommandService.java b/src/main/java/com/favoriteplace/app/service/community/PostCommandService.java index e5481f9..16622de 100644 --- a/src/main/java/com/favoriteplace/app/service/community/PostCommandService.java +++ b/src/main/java/com/favoriteplace/app/service/community/PostCommandService.java @@ -1,6 +1,5 @@ package com.favoriteplace.app.service.community; -import com.favoriteplace.app.domain.Image; import com.favoriteplace.app.domain.Member; import com.favoriteplace.app.domain.community.Post; import com.favoriteplace.app.dto.community.PostRequestDto; @@ -9,27 +8,26 @@ import com.favoriteplace.app.repository.PostRepository; import com.favoriteplace.global.exception.ErrorCode; import com.favoriteplace.global.exception.RestApiException; -import com.favoriteplace.global.gcpImage.ConvertUuidToUrl; -import com.favoriteplace.global.gcpImage.UploadImage; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - +import com.favoriteplace.global.s3Image.AmazonS3ImageManager; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; @Service @RequiredArgsConstructor +@Slf4j public class PostCommandService { - private final UploadImage uploadImage; private final PostRepository postRepository; private final LikedPostRepository likedPostRepository; private final ImageRepository imageRepository; + private final AmazonS3ImageManager amazonS3ImageManager; /** * 자유게시글 작성 @@ -44,45 +42,16 @@ public Long createPost(PostRequestDto data, List images, Member m .images(new ArrayList<>()) .content(data.getContent()).likeCount(0L).view(0L) .build(); - if(images != null && !images.isEmpty()){ - newPost.getImages().addAll(setImageList(newPost, images)); - } - Post post = postRepository.save(newPost); - return post.getId(); - } - /** - * 이미지가 여러개일 때, 이미지 처리하는 로직 - * @param images - * @throws IOException - */ - @Transactional - public List setImageList(Post post, List images) throws IOException { - //이미지 업로드 관련 - List> futures = new ArrayList<>(); - - for(MultipartFile image: images){ - if(image != null && !image.isEmpty()){ - /* - String uuid = uploadImage.uploadImageToCloud(image); - Image newImage = Image.builder().url(ConvertUuidToUrl.convertUuidToUrl(uuid)).post(post).build(); - imagesForPost.add(newImage);*/ - CompletableFuture future = CompletableFuture.supplyAsync(() -> { - try { - String uuid = uploadImage.uploadImageToCloud(image); - return Image.builder().url(ConvertUuidToUrl.convertUuidToUrl(uuid)).post(post).build(); - } catch (IOException e) { - throw new RestApiException(ErrorCode.IMAGE_CANNOT_UPLOAD); - } - }); - futures.add(future); - } + try{ + List imageUrls = amazonS3ImageManager.uploadMultiImages(images); + newPost.addImages(imageUrls); + }catch (IOException e){ + log.info("[post image] image 없음"); } - // 모든 작업이 완료될 때까지 기다림 - return futures.stream() - .map(CompletableFuture::join) - .collect(Collectors.toList()); + Post post = postRepository.save(newPost); + return post.getId(); } /** @@ -109,13 +78,19 @@ public void modifyPost(long postId, PostRequestDto data, List ima checkAuthOfGuestBook(member, post); Optional.ofNullable(data.getTitle()).ifPresent(post::setTitle); Optional.ofNullable(data.getContent()).ifPresent(post::setContent); + //기존의 이미지 삭제 필요 post.getImages().clear(); imageRepository.deleteByPostId(post.getId()); - if(images != null && !images.isEmpty()){ - post.getImages().addAll(setImageList(post, images)); + + // 새로운 이미지 등록 + try{ + List imageUrls = amazonS3ImageManager.uploadMultiImages(images); + post.addImages(imageUrls); + }catch (IOException e){ + log.info("[post image] image 없음"); } - postRepository.save(post); + } /** diff --git a/src/main/java/com/favoriteplace/global/s3Image/AmazonS3ImageManager.java b/src/main/java/com/favoriteplace/global/s3Image/AmazonS3ImageManager.java index 2ea12ca..1e4a0ad 100644 --- a/src/main/java/com/favoriteplace/global/s3Image/AmazonS3ImageManager.java +++ b/src/main/java/com/favoriteplace/global/s3Image/AmazonS3ImageManager.java @@ -55,6 +55,18 @@ public CompletableFuture upload(MultipartFile multipartFile) throws IOEx return futures; } + public List uploadMultiImages(List images) throws IOException{ + List> futures = new ArrayList<>(); + for(MultipartFile file:images){ + futures.add(upload(file)); + } + List imageUrls = new ArrayList<>(); + futures.forEach( + future -> imageUrls.add(future.join()) + ); + return imageUrls; + } + private String upload(File uploadFile, String s3FileName) { String fileName = s3Config.getFilePath()+ "/" + s3FileName + uploadFile.getName(); String uploadImageUrl = putS3(uploadFile, fileName);