Skip to content

Commit 2cb5d16

Browse files
authored
Merge pull request #25 from Searchweb-Dev/feat/SW-45
Feat/sw 45 - 북마크 로직 리팩터링
2 parents 211371b + 7877f9b commit 2cb5d16

15 files changed

Lines changed: 620 additions & 227 deletions

File tree

src/main/java/com/web/SearchWeb/bookmark/controller/BookmarkApiController.java

Lines changed: 87 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.web.SearchWeb.bookmark.controller;
22

33

4+
import com.web.SearchWeb.bookmark.controller.dto.BookmarkRequests;
45
import com.web.SearchWeb.bookmark.domain.Bookmark;
5-
import com.web.SearchWeb.bookmark.dto.BookmarkDto;
66
import com.web.SearchWeb.bookmark.service.BookmarkService;
7+
import com.web.SearchWeb.config.ApiResponse;
78
import com.web.SearchWeb.member.dto.CustomOAuth2User;
89
import com.web.SearchWeb.member.dto.CustomUserDetails;
910
import org.springframework.beans.factory.annotation.Autowired;
@@ -14,9 +15,7 @@
1415
import org.springframework.security.oauth2.core.user.OAuth2User;
1516
import org.springframework.web.bind.annotation.*;
1617

17-
import java.util.HashMap;
1818
import java.util.List;
19-
import java.util.Map;
2019

2120

2221
/**
@@ -34,142 +33,161 @@ public BookmarkApiController(BookmarkService bookmarkService) {
3433
this.bookmarkService = bookmarkService;
3534
}
3635

37-
/**
38-
* 북마크 확인
39-
*/
40-
@GetMapping("/check")
41-
public ResponseEntity<Boolean> checkBookmark(@AuthenticationPrincipal Object currentUser, @RequestParam String url) {
42-
// 로그인 되지 않은 경우
43-
if (currentUser == null || "anonymousUser".equals(currentUser)) {
44-
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
45-
}
46-
47-
Long memberId = getMemberId(currentUser);
48-
49-
// 북마크 존재 여부 확인
50-
boolean exists = bookmarkService.checkBookmarkExistsByUrl(memberId, url);
51-
return ResponseEntity.ok(exists);
52-
}
53-
54-
5536
/**
5637
* 북마크 추가
5738
*/
5839
@PostMapping
59-
public ResponseEntity<Map<String, Object>> insertBookmark(
40+
public ResponseEntity<ApiResponse<Long>> insertBookmark(
6041
@AuthenticationPrincipal Object currentUser,
61-
@RequestBody BookmarkDto bookmarkDto,
62-
@RequestParam String url) {
63-
64-
Map<String, Object> response = new HashMap<>();
65-
42+
@RequestBody BookmarkRequests.CreateDto request) {
43+
44+
// TODO: AOP 처리
6645
// 로그인 되지 않은 경우
6746
if (currentUser == null || "anonymousUser".equals(currentUser)) {
68-
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
47+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
6948
}
7049

7150
Long memberId = getMemberId(currentUser);
7251
if (memberId == null) {
73-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(response);
52+
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
7453
}
7554

76-
bookmarkDto.setCreatedByMemberId(memberId);
77-
int result = bookmarkService.insertBookmark(bookmarkDto, url);
78-
response.put("success", result > 0);
79-
return ResponseEntity.ok(response);
55+
Long bookmarkId = bookmarkService.insertBookmark(
56+
memberId,
57+
request.url,
58+
request.memberFolderId,
59+
request.displayTitle,
60+
request.note,
61+
request.primaryCategoryId,
62+
request.tags
63+
);
64+
65+
return ResponseEntity
66+
.status(HttpStatus.CREATED)
67+
.body(ApiResponse.success(bookmarkId));
8068
}
8169

8270

8371
/**
84-
* 북마크 목록 조회
72+
* 북마크 단일 조회
8573
*/
86-
@GetMapping
87-
public ResponseEntity<List<Bookmark>> selectBookmarkList(
74+
@GetMapping("/{bookmarkId}")
75+
public ResponseEntity<ApiResponse<Bookmark>> selectBookmark(
8876
@AuthenticationPrincipal Object currentUser,
89-
@RequestParam(required = false) Long folderId,
90-
@RequestParam(defaultValue = "Newest") String sort,
91-
@RequestParam(required = false) String query,
92-
@RequestParam(required = false) Long categoryId) {
93-
77+
@PathVariable Long bookmarkId) {
78+
79+
// TODO: AOP 처리
9480
// 로그인 되지 않은 경우
9581
if (currentUser == null || "anonymousUser".equals(currentUser)) {
9682
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
9783
}
98-
84+
9985
Long memberId = getMemberId(currentUser);
10086
if (memberId == null) {
10187
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
10288
}
103-
104-
List<Bookmark> bookmarks = bookmarkService.selectBookmarkList(memberId, folderId, sort, query, categoryId);
105-
return ResponseEntity.ok(bookmarks);
89+
90+
Bookmark bookmark = bookmarkService.selectBookmark(memberId, bookmarkId);
91+
return ResponseEntity.ok(ApiResponse.success(bookmark));
10692
}
10793

10894

10995
/**
110-
* 북마크 단일 조회
96+
* 북마크 목록 조회
11197
*/
112-
@GetMapping("/{bookmarkId}")
113-
public ResponseEntity<Bookmark> selectBookmark(
98+
@GetMapping
99+
public ResponseEntity<ApiResponse<List<Bookmark>>> selectBookmarkList(
114100
@AuthenticationPrincipal Object currentUser,
115-
@PathVariable Long bookmarkId) {
116-
101+
@ModelAttribute BookmarkRequests.SearchDto searchDto) {
102+
103+
// TODO: AOP 처리
117104
// 로그인 되지 않은 경우
118105
if (currentUser == null || "anonymousUser".equals(currentUser)) {
119106
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
120107
}
121-
108+
122109
Long memberId = getMemberId(currentUser);
123110
if (memberId == null) {
124111
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
125112
}
126-
127-
Bookmark bookmark = bookmarkService.selectBookmark(memberId, bookmarkId);
128-
return ResponseEntity.ok(bookmark);
113+
114+
List<Bookmark> bookmarks = bookmarkService.selectBookmarkList(searchDto.toCommand(memberId));
115+
return ResponseEntity.ok(ApiResponse.success(bookmarks));
129116
}
130117

131118

132119
/**
133120
* 북마크 수정
134121
*/
135122
@PutMapping("/{bookmarkId}")
136-
public ResponseEntity<Map<String, Object>> updateBookmark(
123+
public ResponseEntity<ApiResponse<Long>> updateBookmark(
137124
@AuthenticationPrincipal Object currentUser,
138125
@PathVariable Long bookmarkId,
139-
@RequestBody BookmarkDto bookmarkDto) {
126+
@RequestBody BookmarkRequests.UpdateDto request) {
140127

141-
Map<String, Object> response = new HashMap<>();
128+
// TODO: AOP 처리
129+
// 로그인 되지 않은 경우
130+
if (currentUser == null || "anonymousUser".equals(currentUser)) {
131+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
132+
}
142133

143134
Long memberId = getMemberId(currentUser);
144135
if (memberId == null) {
145-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(response);
136+
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
146137
}
147138

148-
bookmarkDto.setCreatedByMemberId(memberId);
149-
int result = bookmarkService.updateBookmark(bookmarkDto, bookmarkId);
150-
response.put("success", result > 0);
151-
return ResponseEntity.ok(response);
139+
Long updatedBookmarkId = bookmarkService.updateBookmark(
140+
memberId,
141+
bookmarkId,
142+
request.memberFolderId,
143+
request.displayTitle,
144+
request.note,
145+
request.primaryCategoryId,
146+
request.tags
147+
);
148+
return ResponseEntity.ok(ApiResponse.success(updatedBookmarkId));
152149
}
153150

154151

155152
/**
156153
* 북마크 삭제
157154
*/
158155
@DeleteMapping("/{bookmarkId}")
159-
public ResponseEntity<Map<String, Object>> deleteBookmark(
156+
public ResponseEntity<ApiResponse<Long>> deleteBookmark(
160157
@AuthenticationPrincipal Object currentUser,
161158
@PathVariable Long bookmarkId) {
162159

163-
Map<String, Object> response = new HashMap<>();
164-
160+
// TODO: AOP 처리
161+
// 로그인 되지 않은 경우
162+
if (currentUser == null || "anonymousUser".equals(currentUser)) {
163+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
164+
}
165+
165166
Long memberId = getMemberId(currentUser);
166167
if (memberId == null) {
167-
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(response);
168+
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
168169
}
169170

170-
int result = bookmarkService.deleteBookmark(memberId, bookmarkId);
171-
response.put("success", result > 0);
172-
return ResponseEntity.ok(response);
171+
Long deletedId = bookmarkService.deleteBookmark(memberId, bookmarkId);
172+
return ResponseEntity.ok(ApiResponse.success(deletedId));
173+
}
174+
175+
176+
/**
177+
* 북마크 확인
178+
*/
179+
@GetMapping("/check")
180+
public ResponseEntity<Boolean> checkBookmark(@AuthenticationPrincipal Object currentUser, @RequestParam String url) {
181+
// 로그인 되지 않은 경우
182+
if (currentUser == null || "anonymousUser".equals(currentUser)) {
183+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
184+
}
185+
186+
Long memberId = getMemberId(currentUser);
187+
188+
// 북마크 존재 여부 확인
189+
boolean exists = bookmarkService.checkBookmarkExistsByUrl(memberId, url);
190+
return ResponseEntity.ok(exists);
173191
}
174192

175193

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.web.SearchWeb.bookmark.controller.dto;
2+
3+
import com.web.SearchWeb.bookmark.service.command.BookmarkSearchCommand;
4+
5+
import lombok.AllArgsConstructor;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
/**
10+
* Bookmark Controller 전용 Request DTO
11+
* - Controller에서만 사용하며, Service 계층에는 개별 파라미터로 전달
12+
*/
13+
public class BookmarkRequests {
14+
15+
/**
16+
* 북마크 생성 요청 Dto
17+
*/
18+
public static class CreateDto {
19+
public Long bookmarkId; // 북마크 ID (PK, Insert 시 생성된 키 저장용)
20+
public Long memberFolderId; // 폴더 ID (null이면 기본 폴더)
21+
public String displayTitle; // 표시 제목
22+
public String url; // 저장할 URL
23+
public String note; // 메모
24+
public Long primaryCategoryId; // 카테고리 ID
25+
public Long createdByMemberId; // 저장한 회원
26+
public String tags; // 태그 문자열 (공백/콤마 구분)
27+
}
28+
29+
30+
/**
31+
* 북마크 목록 조회 요청 Dto (Search Params)
32+
*/
33+
@Data
34+
@NoArgsConstructor
35+
@AllArgsConstructor
36+
public static class SearchDto {
37+
public Long folderId;
38+
public String sort = "Newest"; // 기본값 설정
39+
public String query;
40+
public Long categoryId;
41+
42+
public BookmarkSearchCommand toCommand(Long memberId) {
43+
return BookmarkSearchCommand.builder()
44+
.memberId(memberId)
45+
.folderId(this.folderId)
46+
.sort(this.sort)
47+
.query(this.query)
48+
.categoryId(this.categoryId)
49+
.build();
50+
}
51+
}
52+
53+
54+
/**
55+
* 북마크 수정 요청 Dto
56+
*/
57+
@Data
58+
@NoArgsConstructor
59+
@AllArgsConstructor
60+
public static class UpdateDto {
61+
public Long memberFolderId; // 폴더 ID
62+
public String displayTitle; // 표시 제목
63+
public String note; // 메모
64+
public Long primaryCategoryId; // 카테고리 ID
65+
public String tags; // 태그 문자열 (공백/콤마 구분)
66+
}
67+
68+
}

src/main/java/com/web/SearchWeb/bookmark/dao/BookmarkDao.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,48 @@
22

33
import com.web.SearchWeb.bookmark.domain.Bookmark;
44
import com.web.SearchWeb.bookmark.domain.Link;
5-
import com.web.SearchWeb.bookmark.dto.BookmarkDto;
6-
import com.web.SearchWeb.bookmark.dto.request.BookmarkSearchRequestDto;
5+
import com.web.SearchWeb.bookmark.dto.MemberTagResultDto;
6+
import com.web.SearchWeb.bookmark.service.command.BookmarkSearchCommand;
77

88
import java.util.List;
99

1010
public interface BookmarkDao {
11-
//북마크 링크 중복 확인 (동일 폴더에 동일 링크)
12-
int checkBookmarkExists(Long memberId, Long folderId, Long linkId);
13-
1411
//북마크 추가
15-
int insertBookmark(BookmarkDto bookmark, Long linkId);
12+
int insertBookmark(Bookmark bookmark);
1613

1714
//북마크 단일 조회
1815
Bookmark selectBookmark(Long memberId, Long bookmarkId);
1916

2017
//북마크 목록 조회
21-
List<Bookmark> selectBookmarkList(BookmarkSearchRequestDto searchRequest);
18+
List<Bookmark> selectBookmarkList(BookmarkSearchCommand searchCommand);
2219

2320
//북마크 수정
24-
int updateBookmark(BookmarkDto bookmarkDto, Long bookmarkId);
25-
21+
int updateBookmark(Bookmark bookmark);
22+
2623
//북마크 삭제
2724
int deleteBookmark(Long memberId, Long bookmarkId);
2825

26+
//북마크 태그 연결 삭제
27+
int deleteBookmarkTags(Long bookmarkId, Long memberId);
28+
2929
//북마크 삭제 (Link ID 기반 - soft delete)
3030
int deleteBookmarkByLink(Long memberId, Long linkId);
3131

32-
//링크 조회 (canonical_url로)
33-
Link selectLinkByCanonicalUrl(String canonicalUrl);
32+
//북마크 링크 중복 확인 (동일 폴더에 동일 링크)
33+
int checkBookmarkExists(Long memberId, Long folderId, Long linkId);
34+
35+
//링크 조회 (url로)
36+
Link selectLinkByUrl(String url);
3437

3538
//링크 추가 (link 테이블)
3639
int insertLink(Link link);
3740

3841
//URL 기반 북마크 존재 여부 확인 (Board Bridge용)
3942
int checkBookmarkExistsByUrl(Long memberId, String url);
43+
44+
// 태그 등록 및 조회 (Insert & Select)
45+
List<MemberTagResultDto> insertAndSelectTags(Long memberId, List<String> tagNames);
46+
47+
// 북마크-태그 연결 일괄 추가 (Bulk Insert)
48+
int insertBookmarkTags(Long bookmarkId, List<Long> tagIds);
4049
}

0 commit comments

Comments
 (0)