diff --git a/src/main/java/com/potatocake/everymoment/controller/FileController.java b/src/main/java/com/potatocake/everymoment/controller/FileController.java index cb62468..d841829 100644 --- a/src/main/java/com/potatocake/everymoment/controller/FileController.java +++ b/src/main/java/com/potatocake/everymoment/controller/FileController.java @@ -1,12 +1,12 @@ package com.potatocake.everymoment.controller; import com.potatocake.everymoment.dto.SuccessResponse; -import com.potatocake.everymoment.dto.request.FileRequest; import com.potatocake.everymoment.dto.response.FileResponse; import com.potatocake.everymoment.security.MemberDetails; import com.potatocake.everymoment.service.FileService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -34,10 +34,12 @@ public class FileController { private final FileService fileService; @Operation(summary = "파일 목록 조회", description = "특정 일기의 파일 목록을 조회합니다.") - @ApiResponse(responseCode = "200", description = "파일 목록 조회 성공", content = @Content(schema = @Schema(implementation = FileResponse.class))) + @ApiResponse(responseCode = "200", description = "파일 목록 조회 성공", content = @Content(array = @ArraySchema(schema = @Schema(implementation = FileResponse.class)))) @GetMapping - public ResponseEntity> getFiles(@Parameter(description = "조회할 일기 ID", required = true) - @PathVariable Long diaryId) { + public ResponseEntity>> getFiles( + @Parameter(description = "조회할 일기 ID", required = true) + @PathVariable Long diaryId + ) { List files = fileService.getFiles(diaryId); return ResponseEntity.ok() @@ -53,11 +55,9 @@ public ResponseEntity uploadFiles( @Parameter(description = "인증된 사용자 정보", hidden = true) @AuthenticationPrincipal MemberDetails memberDetails, @Parameter(description = "업로드할 파일 목록", required = true) - @RequestPart List files, - @Parameter(description = "일기에 보일 파일 이름과 순서", required = true) - @RequestPart List info + @RequestPart List files ) { - fileService.uploadFiles(diaryId, memberDetails.getId(), files, info); + fileService.uploadFiles(diaryId, memberDetails.getId(), files); return ResponseEntity.ok() .body(SuccessResponse.ok()); @@ -72,11 +72,9 @@ public ResponseEntity updateFiles( @Parameter(description = "인증된 사용자 정보", hidden = true) @AuthenticationPrincipal MemberDetails memberDetails, @Parameter(description = "수정할 파일 목록", required = true) - @RequestPart List files, - @Parameter(description = "일기에 보일 파일 이름과 순서", required = true) - @RequestPart List info + @RequestPart List files ) { - fileService.updateFiles(diaryId, memberDetails.getId(), files, info); + fileService.updateFiles(diaryId, memberDetails.getId(), files); return ResponseEntity.ok() .body(SuccessResponse.ok()); diff --git a/src/main/java/com/potatocake/everymoment/dto/request/DiaryFilterRequest.java b/src/main/java/com/potatocake/everymoment/dto/request/DiaryFilterRequest.java index 720a07e..1f31183 100644 --- a/src/main/java/com/potatocake/everymoment/dto/request/DiaryFilterRequest.java +++ b/src/main/java/com/potatocake/everymoment/dto/request/DiaryFilterRequest.java @@ -27,10 +27,11 @@ public List getEmojis() { : Collections.emptyList(); } - public List getCategories() { + public List getCategories() { return (category != null && !category.isEmpty()) ? Arrays.stream(category.split(",")) - .map(Long::parseLong) + .map(String::trim) + .filter(s -> !s.isEmpty()) .collect(Collectors.toList()) : Collections.emptyList(); } diff --git a/src/main/java/com/potatocake/everymoment/dto/request/DiaryManualCreateRequest.java b/src/main/java/com/potatocake/everymoment/dto/request/DiaryManualCreateRequest.java index 849298a..9df2ed2 100644 --- a/src/main/java/com/potatocake/everymoment/dto/request/DiaryManualCreateRequest.java +++ b/src/main/java/com/potatocake/everymoment/dto/request/DiaryManualCreateRequest.java @@ -13,7 +13,5 @@ public class DiaryManualCreateRequest { private boolean isBookmark; private boolean isPublic; private String emoji; - private List file; private String content; } - diff --git a/src/main/java/com/potatocake/everymoment/dto/request/FileRequest.java b/src/main/java/com/potatocake/everymoment/dto/request/FileRequest.java deleted file mode 100644 index 9d22d27..0000000 --- a/src/main/java/com/potatocake/everymoment/dto/request/FileRequest.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.potatocake.everymoment.dto.request; - -import lombok.Getter; - -@Getter -public class FileRequest { - private String filename; - private int order; -} diff --git a/src/main/java/com/potatocake/everymoment/dto/response/FriendRequestResponse.java b/src/main/java/com/potatocake/everymoment/dto/response/FriendRequestResponse.java index 77f1771..45fe6d3 100644 --- a/src/main/java/com/potatocake/everymoment/dto/response/FriendRequestResponse.java +++ b/src/main/java/com/potatocake/everymoment/dto/response/FriendRequestResponse.java @@ -9,5 +9,7 @@ public class FriendRequestResponse { private Long id; private Long senderId; + private String nickname; + private String profileImageUrl; } diff --git a/src/main/java/com/potatocake/everymoment/entity/Diary.java b/src/main/java/com/potatocake/everymoment/entity/Diary.java index 23d7583..c60f671 100644 --- a/src/main/java/com/potatocake/everymoment/entity/Diary.java +++ b/src/main/java/com/potatocake/everymoment/entity/Diary.java @@ -1,5 +1,6 @@ package com.potatocake.everymoment.entity; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -9,6 +10,9 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.Lob; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.HashSet; +import java.util.Set; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -53,6 +57,9 @@ public class Diary extends BaseTimeEntity { @Builder.Default private boolean isPublic = false; + @OneToMany(mappedBy = "diary", cascade = CascadeType.ALL, orphanRemoval = true) + private Set diaryCategories = new HashSet<>(); + public void updateContent(String content) { if (content != null) { this.content = content; diff --git a/src/main/java/com/potatocake/everymoment/entity/DiaryCategory.java b/src/main/java/com/potatocake/everymoment/entity/DiaryCategory.java index 3a724d8..534c7dd 100644 --- a/src/main/java/com/potatocake/everymoment/entity/DiaryCategory.java +++ b/src/main/java/com/potatocake/everymoment/entity/DiaryCategory.java @@ -31,4 +31,13 @@ public class DiaryCategory { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(foreignKey = @ForeignKey(name = "fk_category_id"), nullable = false) private Category category; + + public void setDiary(Diary diary) { + this.diary = diary; + } + + public void setCategory(Category category) { + this.category = category; + } + } diff --git a/src/main/java/com/potatocake/everymoment/service/DiaryService.java b/src/main/java/com/potatocake/everymoment/service/DiaryService.java index 8293530..c4ac02a 100644 --- a/src/main/java/com/potatocake/everymoment/service/DiaryService.java +++ b/src/main/java/com/potatocake/everymoment/service/DiaryService.java @@ -100,7 +100,6 @@ public void createDiaryManual(Long memberId, DiaryManualCreateRequest diaryManua Member currentMember = memberRepository.findById(memberId) .orElseThrow(() -> new GlobalException(ErrorCode.MEMBER_NOT_FOUND)); - double longitude = diaryManualCreateRequest.getLocationPoint().getLongitude(); double latitude = diaryManualCreateRequest.getLocationPoint().getLatitude(); @@ -149,21 +148,21 @@ public MyDiariesResponse getMyDiaries(Long memberId, DiaryFilterRequest diaryFil Page diaryPage; - List categoryIds = diaryFilterRequest.getCategories(); + List categories = diaryFilterRequest.getCategories(); List emojis = diaryFilterRequest.getEmojis(); Specification spec = DiarySpecification.filterDiaries( diaryFilterRequest.getKeyword(), emojis, - categoryIds, + categories, diaryFilterRequest.getDate(), diaryFilterRequest.getFrom(), diaryFilterRequest.getUntil(), diaryFilterRequest.getIsBookmark()) .and((root, query, builder) -> builder.equal(root.get("member"), currentMember)); - diaryPage = diaryRepository.findAll(spec, PageRequest.of(diaryFilterRequest.getKey(), diaryFilterRequest.getSize())); - + diaryPage = diaryRepository.findAll(spec, + PageRequest.of(diaryFilterRequest.getKey(), diaryFilterRequest.getSize())); List diaryDTOs = diaryPage.getContent().stream() .map(this::convertToMyDiarySimpleResponseDto) diff --git a/src/main/java/com/potatocake/everymoment/service/DiarySpecification.java b/src/main/java/com/potatocake/everymoment/service/DiarySpecification.java index 3a9826d..95dd147 100644 --- a/src/main/java/com/potatocake/everymoment/service/DiarySpecification.java +++ b/src/main/java/com/potatocake/everymoment/service/DiarySpecification.java @@ -1,22 +1,23 @@ package com.potatocake.everymoment.service; +import com.potatocake.everymoment.entity.Category; import com.potatocake.everymoment.entity.Diary; import com.potatocake.everymoment.entity.DiaryCategory; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Join; +import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; +import java.time.LocalDate; import java.util.List; import org.springframework.data.jpa.domain.Specification; -import java.time.LocalDate; - public class DiarySpecification { public static Specification filterDiaries( - String keyword, List emojis, List categories, + String keyword, List emojis, List categories, LocalDate date, LocalDate from, LocalDate until, Boolean isBookmark) { return (Root root, CriteriaQuery query, CriteriaBuilder builder) -> { Predicate predicate = builder.conjunction(); @@ -29,15 +30,17 @@ public static Specification filterDiaries( } if (categories != null && !categories.isEmpty()) { - Join diaryCategoryJoin = root.join("diaryCategories"); - predicate = builder.and(predicate, diaryCategoryJoin.get("category").get("id").in(categories)); + Join diaryCategoryJoin = root.join("diaryCategories", JoinType.LEFT); + Join categoryJoin = diaryCategoryJoin.join("category", JoinType.LEFT); + predicate = builder.and(predicate, categoryJoin.get("categoryName").in(categories)); } LocalDate filterDate = (date != null) ? date : LocalDate.now(); predicate = builder.and(predicate, builder.equal(root.get("createAt").as(LocalDate.class), filterDate)); if (from != null && until != null) { - predicate = builder.and(predicate, builder.between(root.get("createAt"), from.atStartOfDay(), until.plusDays(1).atStartOfDay())); + predicate = builder.and(predicate, + builder.between(root.get("createAt"), from.atStartOfDay(), until.plusDays(1).atStartOfDay())); } if (isBookmark != null) { predicate = builder.and(predicate, builder.equal(root.get("isBookmark"), isBookmark)); diff --git a/src/main/java/com/potatocake/everymoment/service/FileService.java b/src/main/java/com/potatocake/everymoment/service/FileService.java index 771129e..a2b3bba 100644 --- a/src/main/java/com/potatocake/everymoment/service/FileService.java +++ b/src/main/java/com/potatocake/everymoment/service/FileService.java @@ -1,6 +1,5 @@ package com.potatocake.everymoment.service; -import com.potatocake.everymoment.dto.request.FileRequest; import com.potatocake.everymoment.dto.response.FileResponse; import com.potatocake.everymoment.entity.Diary; import com.potatocake.everymoment.entity.File; @@ -11,8 +10,6 @@ import com.potatocake.everymoment.util.S3FileUploader; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,29 +31,23 @@ public List getFiles(Long diaryId) { .toList(); } - public void uploadFiles(Long diaryId, Long memberId, List files, List infos) { + public void uploadFiles(Long diaryId, Long memberId, List files) { Diary diary = diaryRepository.findById(diaryId) .orElseThrow(() -> new GlobalException(ErrorCode.DIARY_NOT_FOUND)); diary.checkOwner(memberId); - Map fileMap = files.stream() - .collect(Collectors.toMap(MultipartFile::getOriginalFilename, f -> f, (f1, f2) -> f1)); - List fileEntities = new ArrayList<>(); - for (FileRequest info : infos) { - MultipartFile file = fileMap.get(info.getFilename()); - if (file == null) { - throw new GlobalException(ErrorCode.FILE_NOT_FOUND); - } + for (int i = 0; i < files.size(); i++) { + MultipartFile file = files.get(i); String url = uploader.uploadFile(file); File fileEntity = File.builder() .diary(diary) .imageUrl(url) - .order(info.getOrder()) + .order(i + 1) .build(); fileEntities.add(fileEntity); @@ -65,7 +56,7 @@ public void uploadFiles(Long diaryId, Long memberId, List files, fileRepository.saveAll(fileEntities); } - public void updateFiles(Long diaryId, Long memberId, List files, List infos) { + public void updateFiles(Long diaryId, Long memberId, List files) { Diary diary = diaryRepository.findById(diaryId) .orElseThrow(() -> new GlobalException(ErrorCode.DIARY_NOT_FOUND)); @@ -73,7 +64,7 @@ public void updateFiles(Long diaryId, Long memberId, List files, fileRepository.deleteByDiary(diary); - uploadFiles(diaryId, memberId, files, infos); + uploadFiles(diaryId, memberId, files); } } diff --git a/src/main/java/com/potatocake/everymoment/service/FriendDiaryService.java b/src/main/java/com/potatocake/everymoment/service/FriendDiaryService.java index fb83595..2afa0a4 100644 --- a/src/main/java/com/potatocake/everymoment/service/FriendDiaryService.java +++ b/src/main/java/com/potatocake/everymoment/service/FriendDiaryService.java @@ -53,20 +53,21 @@ public FriendDiariesResponse getFriendDiaries(Long memberId, DiaryFilterRequest Page diaryPage; // 카테고리와 이모지가 여러 개 전달될 수 있으므로 이를 리스트로 변환 - List categoryIds = diaryFilterRequest.getCategories(); + List categories = diaryFilterRequest.getCategories(); List emojis = diaryFilterRequest.getEmojis(); Specification spec = DiarySpecification.filterDiaries( diaryFilterRequest.getKeyword(), emojis, - categoryIds, + categories, diaryFilterRequest.getDate(), diaryFilterRequest.getFrom(), diaryFilterRequest.getUntil(), diaryFilterRequest.getIsBookmark()) .and((root, query, builder) -> root.get("member").in(friendIdList)); - diaryPage = diaryRepository.findAll(spec, PageRequest.of(diaryFilterRequest.getKey(), diaryFilterRequest.getSize())); + diaryPage = diaryRepository.findAll(spec, + PageRequest.of(diaryFilterRequest.getKey(), diaryFilterRequest.getSize())); List friendDiarySimpleResponseList = diaryPage.getContent().stream() .map(this::convertToFriendDiariesResponseDTO) diff --git a/src/main/java/com/potatocake/everymoment/service/FriendRequestService.java b/src/main/java/com/potatocake/everymoment/service/FriendRequestService.java index 0373b19..89f99a9 100644 --- a/src/main/java/com/potatocake/everymoment/service/FriendRequestService.java +++ b/src/main/java/com/potatocake/everymoment/service/FriendRequestService.java @@ -1,5 +1,6 @@ package com.potatocake.everymoment.service; +import static java.util.function.Function.identity; import static org.springframework.data.domain.Sort.Direction.DESC; import com.potatocake.everymoment.dto.response.FriendRequestPageRequest; @@ -14,6 +15,9 @@ import com.potatocake.everymoment.repository.MemberRepository; import com.potatocake.everymoment.util.PagingUtil; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.ScrollPosition; @@ -106,11 +110,27 @@ private Window fetchFriendRequestWindow(Long key, int size, Long } private List convertToFriendRequestResponses(List requests) { + Set senderIds = requests.stream() + .map(request -> request.getSender().getId()) + .collect(Collectors.toSet()); + + Map senderMap = memberRepository.findAllById(senderIds) + .stream() + .collect(Collectors.toMap(Member::getId, identity())); + return requests.stream() - .map(request -> FriendRequestResponse.builder() - .id(request.getId()) - .senderId(request.getSender().getId()) - .build()) + .map(request -> { + Member sender = senderMap.get(request.getSender().getId()); + if (sender == null) { + throw new GlobalException(ErrorCode.MEMBER_NOT_FOUND); + } + return FriendRequestResponse.builder() + .id(request.getId()) + .senderId(sender.getId()) + .nickname(sender.getNickname()) + .profileImageUrl(sender.getProfileImageUrl()) + .build(); + }) .toList(); }