Skip to content

Commit dfe6cf8

Browse files
committed
Merge remote-tracking branch 'origin/refactor/facade' into develop
2 parents 9fa39ba + 8634d16 commit dfe6cf8

File tree

5 files changed

+218
-138
lines changed

5 files changed

+218
-138
lines changed

src/main/java/com/example/log4u/domain/diary/controller/DiaryController.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import com.example.log4u.domain.diary.SortType;
1919
import com.example.log4u.domain.diary.dto.DiaryRequestDto;
2020
import com.example.log4u.domain.diary.dto.DiaryResponseDto;
21-
import com.example.log4u.domain.diary.service.DiaryService;
21+
import com.example.log4u.domain.diary.facade.DiaryFacade;
2222

2323
import jakarta.validation.Valid;
2424
import lombok.RequiredArgsConstructor;
@@ -30,7 +30,7 @@
3030
@Slf4j
3131
public class DiaryController {
3232

33-
private final DiaryService diaryService;
33+
private final DiaryFacade diaryFacade;
3434

3535
@GetMapping("/users/{userId}")
3636
public ResponseEntity<PageResponse<DiaryResponseDto>> getDiariesByUserId(
@@ -39,7 +39,7 @@ public ResponseEntity<PageResponse<DiaryResponseDto>> getDiariesByUserId(
3939
@RequestParam(required = false) Long cursorId,
4040
@RequestParam(defaultValue = "12") int size
4141
) {
42-
PageResponse<DiaryResponseDto> response = diaryService.getDiariesByCursor(customOAuth2User.getUserId(),
42+
PageResponse<DiaryResponseDto> response = diaryFacade.getDiariesByCursor(customOAuth2User.getUserId(),
4343
targetUserId, cursorId, size);
4444

4545
return ResponseEntity.ok(response);
@@ -50,7 +50,7 @@ public ResponseEntity<Void> createDiary(
5050
@AuthenticationPrincipal CustomOAuth2User customOAuth2User,
5151
@Valid @RequestBody DiaryRequestDto request
5252
) {
53-
diaryService.saveDiary(customOAuth2User.getUserId(), request);
53+
diaryFacade.createDiary(customOAuth2User.getUserId(), request);
5454
return ResponseEntity.status(HttpStatus.CREATED).build();
5555
}
5656

@@ -63,7 +63,7 @@ public ResponseEntity<PageResponse<DiaryResponseDto>> searchDiaries(
6363
@RequestParam(defaultValue = "6") int size
6464
) {
6565
return ResponseEntity.ok(
66-
diaryService.searchDiariesByCursor(keyword, sort, cursorId, size)
66+
diaryFacade.searchDiariesByCursor(keyword, sort, cursorId, size)
6767
);
6868
}
6969

@@ -72,7 +72,7 @@ public ResponseEntity<DiaryResponseDto> getDiary(
7272
@AuthenticationPrincipal CustomOAuth2User customOAuth2User,
7373
@PathVariable Long diaryId
7474
) {
75-
DiaryResponseDto diary = diaryService.getDiary(customOAuth2User.getUserId(), diaryId);
75+
DiaryResponseDto diary = diaryFacade.getDiary(customOAuth2User.getUserId(), diaryId);
7676
return ResponseEntity.ok(diary);
7777
}
7878

@@ -82,16 +82,16 @@ public ResponseEntity<Void> modifyDiary(
8282
@PathVariable Long diaryId,
8383
@Valid @RequestBody DiaryRequestDto request
8484
) {
85-
diaryService.updateDiary(customOAuth2User.getUserId(), diaryId, request);
85+
diaryFacade.updateDiary(customOAuth2User.getUserId(), diaryId, request);
8686
return ResponseEntity.ok().build();
8787
}
8888

8989
@DeleteMapping("/{diaryId}")
90-
public ResponseEntity<?> deleteDiary(
90+
public ResponseEntity<Void> deleteDiary(
9191
@AuthenticationPrincipal CustomOAuth2User customOAuth2User,
9292
@PathVariable Long diaryId
9393
) {
94-
diaryService.deleteDiary(customOAuth2User.getUserId(), diaryId);
94+
diaryFacade.deleteDiary(customOAuth2User.getUserId(), diaryId);
9595
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
9696
}
9797
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package com.example.log4u.domain.diary.facade;
2+
3+
import java.util.List;
4+
5+
import org.springframework.data.domain.Slice;
6+
import org.springframework.stereotype.Component;
7+
8+
import com.example.log4u.common.dto.PageResponse;
9+
import com.example.log4u.domain.diary.SortType;
10+
import com.example.log4u.domain.diary.dto.DiaryRequestDto;
11+
import com.example.log4u.domain.diary.dto.DiaryResponseDto;
12+
import com.example.log4u.domain.diary.entity.Diary;
13+
import com.example.log4u.domain.diary.service.DiaryService;
14+
import com.example.log4u.domain.like.service.LikeService;
15+
import com.example.log4u.domain.map.service.MapService;
16+
import com.example.log4u.domain.media.entity.Media;
17+
import com.example.log4u.domain.media.service.MediaService;
18+
19+
import lombok.RequiredArgsConstructor;
20+
21+
@Component
22+
@RequiredArgsConstructor
23+
public class DiaryFacade {
24+
25+
private final DiaryService diaryService;
26+
private final MediaService mediaService;
27+
private final MapService mapService;
28+
private final LikeService likeService;
29+
30+
/**
31+
* 다이어리 생성 use case
32+
* <ul><li>호출 과정</li></ul>
33+
* 1. mediaService: 섬네일 이미지 url 생성<br>
34+
* 2. diaryService: 다이어리 생성<br>
35+
* 2. mediaService: 해당 다이어리의 이미지 저장<br>
36+
* 3. mapService: 해당 구역 카운트 증가
37+
* */
38+
public void createDiary(Long userId, DiaryRequestDto request) {
39+
String thumbnailUrl = mediaService.extractThumbnailUrl(request.mediaList());
40+
Diary diary = diaryService.saveDiary(userId, request, thumbnailUrl);
41+
mediaService.saveMedia(diary.getDiaryId(), request.mediaList());
42+
mapService.increaseRegionDiaryCount(request.location().latitude(), request.location().longitude());
43+
}
44+
45+
/**
46+
* 다이어리 삭제 use case
47+
* <ul><li>호출 과정</li></ul>
48+
* 1. diaryService: 다이어리 검증
49+
* 2. mediaService: 해당 다이어리 이미지 삭제<br>
50+
* 3. diaryService: 다이어리 삭제<br>
51+
* */
52+
public void deleteDiary(Long userId, Long diaryId) {
53+
Diary diary = diaryService.getDiaryAfterValidateOwnership(userId, diaryId);
54+
mediaService.deleteMediaByDiaryId(diaryId);
55+
diaryService.deleteDiary(diary);
56+
}
57+
58+
/**
59+
* 다이어리 수정 use case
60+
* <ul><li>호출 과정</li></ul>
61+
* 1. diaryService: 다이어리 검증<br>
62+
* 2. mediaService: 해당 다이어리 이미지 삭제<br>
63+
* 3. diaryService: 다이어리 수정
64+
* */
65+
public void updateDiary(Long userId, Long diaryId, DiaryRequestDto request) {
66+
Diary diary = diaryService.getDiaryAfterValidateOwnership(userId, diaryId);
67+
if (request.mediaList() != null) {
68+
mediaService.updateMediaByDiaryId(diary.getDiaryId(), request.mediaList());
69+
}
70+
String newThumbnailUrl = mediaService.extractThumbnailUrl(request.mediaList());
71+
diaryService.updateDiary(diary, request, newThumbnailUrl);
72+
}
73+
74+
/**
75+
* 다이어리 단건 조회 use case
76+
* <ul><li>호출 과정</li></ul>
77+
* 1. diaryService: 공개 범위 검증 후 다이어리 조회<br>
78+
* 2. likeService: 좋아요 기록 조회<br>
79+
* 3. mediaService: 해당 다이어리의 이미지 조회<br>
80+
* 4. 모든 정보 조합 후 dto 변환 해 반환
81+
* */
82+
public DiaryResponseDto getDiary(Long userId, Long diaryId) {
83+
Diary diary = diaryService.getDiaryAfterValidateAccess(userId, diaryId);
84+
boolean isLiked = likeService.isLiked(userId, diaryId);
85+
List<Media> media = mediaService.getMediaByDiaryId(diary.getDiaryId());
86+
return DiaryResponseDto.of(diary, media, isLiked);
87+
}
88+
89+
/**
90+
* 다이어리 목록 조회 By UserId use case
91+
* <ul><li>호출 과정</li></ul>
92+
* 1. diaryService : DiaryResponseDto Slice 객체 조회<br>
93+
* 2. nextCursor 정보 생성<br>
94+
* 3. PageResponse 조합 후 반환
95+
* */
96+
public PageResponse<DiaryResponseDto> getDiariesByCursor(
97+
Long userId,
98+
Long targetUserId,
99+
Long cursorId,
100+
int size
101+
) {
102+
Slice<DiaryResponseDto> dtoSlice = diaryService.getDiaryResponseDtoSlice(userId, targetUserId, cursorId, size);
103+
// 다음 커서 ID 계산
104+
Long nextCursor = !dtoSlice.isEmpty() ? dtoSlice.getContent().getLast().diaryId() : null;
105+
return PageResponse.of(dtoSlice, nextCursor);
106+
}
107+
108+
/**
109+
* 다이어리 검색 목록 조회 By Cursor use case
110+
* <ul><li>호출 과정</li></ul>
111+
* 1. diaryService : DiaryResponseDto Slice 객체 조회<br>
112+
* 2. nextCursor 정보 생성<br>
113+
* 3. PageResponse 조합 후 반환<br>
114+
* */
115+
public PageResponse<DiaryResponseDto> searchDiariesByCursor(
116+
String keyword,
117+
SortType sort,
118+
Long cursorId,
119+
int size
120+
) {
121+
Slice<DiaryResponseDto> dtoSlice = diaryService.searchDiariesByCursor(keyword, sort, cursorId, size);
122+
// 다음 커서 ID 계산
123+
Long nextCursor = !dtoSlice.isEmpty() ? dtoSlice.getContent().getLast().diaryId() : null;
124+
return PageResponse.of(dtoSlice, nextCursor);
125+
}
126+
127+
}

src/main/java/com/example/log4u/domain/diary/service/DiaryService.java

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import com.example.log4u.domain.diary.repository.DiaryRepository;
2323
import com.example.log4u.domain.follow.repository.FollowRepository;
2424
import com.example.log4u.domain.like.repository.LikeRepository;
25-
import com.example.log4u.domain.map.service.MapService;
2625
import com.example.log4u.domain.media.entity.Media;
2726
import com.example.log4u.domain.media.service.MediaService;
2827

@@ -37,23 +36,17 @@ public class DiaryService {
3736
private final DiaryRepository diaryRepository;
3837
private final FollowRepository followRepository;
3938
private final MediaService mediaService;
40-
private final MapService mapService;
4139
private final LikeRepository likeRepository;
4240

4341
// 다이어리 생성
4442
@Transactional
45-
public void saveDiary(Long userId, DiaryRequestDto request) {
46-
String thumbnailUrl = mediaService.extractThumbnailUrl(request.mediaList());
47-
Diary diary = diaryRepository.save(
48-
DiaryRequestDto.toEntity(userId, request, thumbnailUrl)
49-
);
50-
mediaService.saveMedia(diary.getDiaryId(), request.mediaList());
51-
mapService.increaseRegionDiaryCount(request.location().latitude(), request.location().longitude());
43+
public Diary saveDiary(Long userId, DiaryRequestDto request, String thumbnailUrl) {
44+
return diaryRepository.save(DiaryRequestDto.toEntity(userId, request, thumbnailUrl));
5245
}
5346

5447
// 다이어리 검색
5548
@Transactional(readOnly = true)
56-
public PageResponse<DiaryResponseDto> searchDiariesByCursor(
49+
public Slice<DiaryResponseDto> searchDiariesByCursor(
5750
String keyword,
5851
SortType sort,
5952
Long cursorId,
@@ -66,17 +59,12 @@ public PageResponse<DiaryResponseDto> searchDiariesByCursor(
6659
cursorId != null ? cursorId : Long.MAX_VALUE,
6760
PageRequest.of(0, size)
6861
);
69-
70-
Slice<DiaryResponseDto> dtoSlice = mapToDtoSlice(diaries);
71-
72-
// 다음 커서 ID 계산
73-
Long nextCursor = !dtoSlice.isEmpty() ? dtoSlice.getContent().getLast().diaryId() : null;
74-
75-
return PageResponse.of(dtoSlice, nextCursor);
62+
return mapToDtoSlice(diaries);
7663
}
7764

7865
// 다이어리 상세 조회
7966
@Transactional(readOnly = true)
67+
@Deprecated(since = "파사드 패턴 도입으로 인해 불필요해짐", forRemoval = false)
8068
public DiaryResponseDto getDiary(Long userId, Long diaryId) {
8169
Diary diary = findDiaryOrThrow(diaryId);
8270

@@ -89,43 +77,27 @@ public DiaryResponseDto getDiary(Long userId, Long diaryId) {
8977

9078
// 다이어리 목록 (프로필 페이지)
9179
@Transactional(readOnly = true)
92-
public PageResponse<DiaryResponseDto> getDiariesByCursor(Long userId, Long targetUserId, Long cursorId, int size) {
80+
public Slice<DiaryResponseDto> getDiaryResponseDtoSlice(Long userId, Long targetUserId, Long cursorId, int size) {
9381
List<VisibilityType> visibilities = determineAccessibleVisibilities(userId, targetUserId);
94-
9582
Slice<Diary> diaries = diaryRepository.findByUserIdAndVisibilityInAndCursorId(
9683
targetUserId,
9784
visibilities,
9885
cursorId != null ? cursorId : Long.MAX_VALUE,
9986
PageRequest.of(0, size)
10087
);
101-
102-
Slice<DiaryResponseDto> dtoSlice = mapToDtoSlice(diaries);
103-
104-
Long nextCursor = !dtoSlice.isEmpty() ? dtoSlice.getContent().getLast().diaryId() : null;
105-
106-
return PageResponse.of(dtoSlice, nextCursor);
88+
return mapToDtoSlice(diaries);
10789
}
10890

10991
// 다이어리 수정
11092
@Transactional
111-
public void updateDiary(Long userId, Long diaryId, DiaryRequestDto request) {
112-
Diary diary = findDiaryOrThrow(diaryId);
113-
validateOwner(diary, userId);
114-
115-
if (request.mediaList() != null) {
116-
mediaService.updateMediaByDiaryId(diary.getDiaryId(), request.mediaList());
117-
}
118-
119-
String newThumbnailUrl = mediaService.extractThumbnailUrl(request.mediaList());
93+
public void updateDiary(Diary diary, DiaryRequestDto request, String newThumbnailUrl) {
12094
diary.update(request, newThumbnailUrl);
95+
diaryRepository.save(diary);
12196
}
12297

12398
// 다이어리 삭제
12499
@Transactional
125-
public void deleteDiary(Long userId, Long diaryId) {
126-
Diary diary = findDiaryOrThrow(diaryId);
127-
validateOwner(diary, userId);
128-
mediaService.deleteMediaByDiaryId(diaryId);
100+
public void deleteDiary(Diary diary) {
129101
diaryRepository.delete(diary);
130102
}
131103

@@ -173,7 +145,7 @@ private void validateOwner(Diary diary, Long userId) {
173145
}
174146
}
175147

176-
// 다이어리 목록 조회 시 권한 체크
148+
// 다이어리 목록 조회 시 권한 체크(공개 정책)
177149
private List<VisibilityType> determineAccessibleVisibilities(Long userId, Long targetUserId) {
178150
if (userId.equals(targetUserId)) {
179151
return List.of(VisibilityType.PUBLIC, VisibilityType.PRIVATE, VisibilityType.FOLLOWER);
@@ -186,6 +158,20 @@ private List<VisibilityType> determineAccessibleVisibilities(Long userId, Long t
186158
return List.of(VisibilityType.PUBLIC);
187159
}
188160

161+
// 파사드 패턴에서 사용할 검증 로직(소유 검증)
162+
public Diary getDiaryAfterValidateOwnership(Long diaryId, Long userId) {
163+
Diary diary = findDiaryOrThrow(diaryId);
164+
validateOwner(diary, userId);
165+
return diary;
166+
}
167+
168+
// 파사드 패턴에서 사용할 검증 로직(공개 범위 검증)
169+
public Diary getDiaryAfterValidateAccess(Long diaryId, Long userId) {
170+
Diary diary = findDiaryOrThrow(diaryId);
171+
validateDiaryAccess(diary, userId);
172+
return diary;
173+
}
174+
189175
// 다이어리 상세 조회 시 권한 체크
190176
private void validateDiaryAccess(Diary diary, Long userId) {
191177
if (diary.getVisibility() == VisibilityType.PRIVATE) {

src/main/java/com/example/log4u/domain/like/service/LikeService.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.example.log4u.domain.like.service;
22

3-
import java.util.Optional;
4-
53
import org.springframework.stereotype.Service;
64
import org.springframework.transaction.annotation.Transactional;
75

@@ -52,4 +50,9 @@ private void validateDuplicateLike(Long userId, Long diaryId) {
5250
throw new DuplicateLikeException();
5351
}
5452
}
53+
54+
// 파사드 패턴에서 사용할 함수
55+
public boolean isLiked(Long userId, Long diaryId) {
56+
return likeRepository.existsByUserIdAndDiaryId(userId, diaryId);
57+
}
5558
}

0 commit comments

Comments
 (0)