Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public ResponseEntity<Integer> checkBookmark(@PathVariable final int websiteId){
**/
@GetMapping("/{memberId}/bookmarks")
public List<Bookmark> selectBookmarkList(@PathVariable final int memberId){
return bookmarkService.selectBookmarkList(memberId, "Oldest"); //JSON 형태로 객체 리스트 반환
return bookmarkService.selectBookmarkList(memberId, null, "Oldest", null, null); //JSON 형태로 객체 리스트 반환
}


Expand Down
12 changes: 4 additions & 8 deletions src/main/java/com/web/SearchWeb/bookmark/dao/BookmarkDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import com.web.SearchWeb.bookmark.dto.BookmarkCheckDto;
import com.web.SearchWeb.bookmark.dto.BookmarkDto;
import com.web.SearchWeb.bookmark.domain.BookmarkWebsite;
import com.web.SearchWeb.bookmark.dto.request.BookmarkSearchRequestDto;

import java.util.List;
import java.util.Map;

public interface BookmarkDao {
//북마크 확인
Expand All @@ -16,12 +16,8 @@ public interface BookmarkDao {
int checkBoardBookmark(BoardBookmarkCheckDto checkDto);
//북마크 단일 조회
Bookmark selectBookmark(int memberId, int bookmarkId);
//북마크 목록 조회 (시간)
List<Bookmark> selectBookmarkList(int memberId, String sort);
//북마크 목록 조회 (시간, 태그)
List<Bookmark> selectBookmarkListByTag(Map<String, Object> params);
//북마크 목록 조회 (검색어)
List<Bookmark> selectBookmarkListByQuery(int memberId, String tag, String sort, String query);
//북마크 목록 조회
List<Bookmark> selectBookmarkList(BookmarkSearchRequestDto searchRequest);
//북마크 추가
int insertBookmark(BookmarkDto bookmark);
//북마크 추가 (사용자 직접 추가)
Expand All @@ -39,7 +35,7 @@ public interface BookmarkDao {
//북마크-웹사이트 조회
List<BookmarkWebsite> selectBookmarkWebsite(int memberId);
//사용자 태그 목록 조회
List<String> selectTags(int memberId);
List<String> selectTags(int memberId, Long folderId);
//게시글 북마크 여부 확인
int isBookmarked(int boardId, int memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
import com.web.SearchWeb.bookmark.dto.BookmarkCheckDto;
import com.web.SearchWeb.bookmark.dto.BookmarkDto;
import com.web.SearchWeb.bookmark.domain.BookmarkWebsite;
import com.web.SearchWeb.bookmark.dto.request.BookmarkSearchRequestDto;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

@Repository
public class MybatisBookmarkDao implements BookmarkDao {
Expand All @@ -25,29 +25,11 @@ public MybatisBookmarkDao(SqlSession sqlSession) {


/**
* 북마크 목록 조회 (시간)
* 북마크 목록 조회
*/
@Override
public List<Bookmark> selectBookmarkList(int memberId, String sort) {
return mapper.selectBookmarkList(memberId, sort);
}


/**
* //북마크 목록 조회 (시간, 태그)
*/
@Override
public List<Bookmark> selectBookmarkListByTag(Map<String, Object> params) {
return mapper.selectBookmarkListByTag(params);
}


/**
* 북마크 목록 조회 (검색어)
*/
@Override
public List<Bookmark> selectBookmarkListByQuery(int memberId, String tag, String sort, String query) {
return mapper.selectBookmarkListByQuery(memberId, tag, sort, query);
public List<Bookmark> selectBookmarkList(BookmarkSearchRequestDto searchRequest) {
return mapper.selectBookmarkList(searchRequest);
}


Expand Down Expand Up @@ -153,8 +135,8 @@ public List<BookmarkWebsite> selectBookmarkWebsite(int memberId) {
* 사용자 태그 목록 조회
*/
@Override
public List<String> selectTags(int memberId) {
return mapper.selectTags(memberId);
public List<String> selectTags(int memberId, Long folderId) {
return mapper.selectTags(memberId, folderId);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class Bookmark {
private int member_memberId;
private int website_websiteId;
private int board_boardId;
private int folder_folderId;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

BookmarkDto와 타입 불일치를 수정하세요.

Bookmark.folder_folderIdint 타입이지만, BookmarkDto.folder_folderIdLong 타입입니다. 이 타입 불일치는 도메인-DTO 간 매핑 시 문제를 발생시킬 수 있습니다.

또한 primitive int는 null 값을 가질 수 없어 폴더가 할당되지 않은 상태를 표현하기 어렵습니다. Integer 타입 사용을 권장합니다.

필드명도 Java 명명 규칙에 맞게 folderId로 변경하는 것을 권장합니다.

🔎 제안하는 수정 사항
-    private int folder_folderId;
+    private Integer folderId;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private int folder_folderId;
private Integer folderId;
🤖 Prompt for AI Agents
In src/main/java/com/web/SearchWeb/bookmark/domain/Bookmark.java around line 16,
the field declaration uses a primitive and non-idiomatic name: "private int
folder_folderId"; change this to a nullable wrapper with a proper Java name to
match the DTO by renaming it to "private Long folderId" (or, if you prefer
Integer across layers, update DTO accordingly) and update the corresponding
getter/setter, any constructors, equals/hashCode, and mapping code to use the
new name and type so domain and BookmarkDto types and names are consistent and
null can be represented.

private String name;
private String description;
private String url;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class BookmarkDto {
private int member_memberId;
private int website_websiteId;
private int board_boardId;
private Long folder_folderId;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

필드 이름을 Java 명명 규칙에 맞게 수정하세요.

folder_folderId는 snake_case를 사용하고 있어 Java 명명 규칙에 맞지 않습니다. folderId로 변경하는 것을 권장합니다.

또한 Bookmark 도메인 엔티티와의 타입 불일치(int vs Long)가 있습니다. Bookmark.java에서 해당 필드를 Integer로 변경하면 일관성을 유지할 수 있습니다.

🔎 제안하는 수정 사항
-    private Long folder_folderId;
+    private Long folderId;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private Long folder_folderId;
private Long folderId;
🤖 Prompt for AI Agents
In src/main/java/com/web/SearchWeb/bookmark/dto/BookmarkDto.java around line 16,
rename the field folder_folderId to folderId to follow Java naming conventions
and make the DTO and entity types consistent by using Integer for the folderId
across both layers: change the DTO field type from Long to Integer (and update
its getters/setters, constructors, builders, and any JSON/property annotations),
and update the Bookmark domain entity to use Integer as well (or vice versa if
you prefer Long—just ensure both DTO and entity match); then update all usages,
mappings, and tests that reference the old name or type.

private String name;
private String description;
private String url;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.web.SearchWeb.bookmark.dto.request;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BookmarkSearchRequestDto {
private int memberId;
private String tag;
private String sort;
private String query;
private Long folderId;
}
Comment on lines +12 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

ID 타입 일관성을 검토하세요.

memberId는 primitive int로, folderId는 wrapper Long으로 선언되어 타입 일관성이 부족합니다.

folderIdLong인 이유는 null을 허용하여 "폴더 필터 없음"을 표현하기 위함으로 보입니다. 이것이 의도된 설계라면 문제없지만, 참고로 Bookmark 도메인에서는 folder_folderIdint로 선언되어 있어 타입 불일치가 발생합니다.

향후 유지보수를 위해 ID 타입 전략(primitive vs wrapper, int vs Long)을 프로젝트 전체적으로 일관되게 가져가는 것을 권장합니다.

🤖 Prompt for AI Agents
In
src/main/java/com/web/SearchWeb/bookmark/dto/request/BookmarkSearchRequestDto.java
around lines 12-18, the ID types are inconsistent (memberId is primitive int
while folderId is Long); change both ID fields to the same wrapper type (use
Integer for memberId and folderId instead of int/Long) to allow nullability and
maintain consistency with Bookmark domain types, then update any callers,
mappers or domain mappings to use Integer as the canonical ID type (or, if the
project decision is to use Long, change both to Long and align domain/repository
accordingly).

Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,8 @@ public interface BookmarkService {
int checkBoardBookmark(BoardBookmarkCheckDto checkDto);
//북마크 단일 조회
Bookmark selectBookmark(int memberId, int bookmarkId);
//북마크 목록 조회 (시간)
List<Bookmark> selectBookmarkList(int memberId, String sort);
//북마크 목록 조회 (시간, 태그)
List<Bookmark> selectBookmarkListByTag(int memberId, String tag, String sort);
//북마크 목록 조회 (검색어)
List<Bookmark> selectBookmarkListByQuery(int memberId, String tag, String sort, String query);
//북마크 목록 조회
List<Bookmark> selectBookmarkList(int memberId, String tag, String sort, String query, Long folderId);
//북마크 추가 (메인리스트에서 추가)
int insertBookmark(BookmarkDto bookmark);
//북마크 추가 (마이페이지에서 추가)
Expand All @@ -40,7 +36,7 @@ public interface BookmarkService {
//북마크-웹사이트 조회
List<BookmarkWebsite> selectBookmarkWebsite(int memberId);
//사용자 태그 목록 조회
List<String> selectTags(int memberId);
List<String> selectTags(int memberId, Long folderId);
//게시글 북마크 여부 확인
int isBookmarked(int boardId, int memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@
import com.web.SearchWeb.bookmark.dto.BookmarkCheckDto;
import com.web.SearchWeb.bookmark.dto.BookmarkDto;
import com.web.SearchWeb.bookmark.domain.BookmarkWebsite;
import com.web.SearchWeb.bookmark.dto.request.BookmarkSearchRequestDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class BookmarkServiceImpl implements BookmarkService {
Expand Down Expand Up @@ -52,33 +50,18 @@ public Bookmark selectBookmark(int memberId, int bookmarkId) {


/**
* 북마크 목록 조회 (시간)
*/
@Override
public List<Bookmark> selectBookmarkList(int memberId, String sort) {
return bookmarkDao.selectBookmarkList(memberId, sort);
}


/**
* 북마크 목록 조회 (시간, 태그)
*/
@Override
public List<Bookmark> selectBookmarkListByTag(int memberId, String tag, String sort) {
Map<String, Object> params = new HashMap<>();
params.put("member_memberId", memberId);
params.put("tag", tag);
params.put("sort", sort);
return bookmarkDao.selectBookmarkListByTag(params);
}


/**
* 북마크 목록 조회 (검색어)
* 북마크 목록 조회
*/
@Override
public List<Bookmark> selectBookmarkListByQuery(int memberId, String tag, String sort, String query) {
return bookmarkDao.selectBookmarkListByQuery(memberId, tag, sort, query);
public List<Bookmark> selectBookmarkList(int memberId, String tag, String sort, String query, Long folderId) {
BookmarkSearchRequestDto searchRequest = BookmarkSearchRequestDto.builder()
.memberId(memberId)
.tag(tag)
.sort(sort)
.query(query)
.folderId(folderId)
.build();
return bookmarkDao.selectBookmarkList(searchRequest);
}


Expand Down Expand Up @@ -159,8 +142,8 @@ public List<BookmarkWebsite> selectBookmarkWebsite(int memberId) {
* 사용자 태그 목록 조회
*/
@Override
public List<String> selectTags(int memberId) {
return bookmarkDao.selectTags(memberId);
public List<String> selectTags(int memberId, Long folderId) {
return bookmarkDao.selectTags(memberId, folderId);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package com.web.SearchWeb.folder.controller;

import com.web.SearchWeb.aop.OwnerCheck;
import com.web.SearchWeb.folder.dto.request.FolderCreateRequestDto;
import com.web.SearchWeb.folder.dto.request.FolderUpdateRequestDto;
import com.web.SearchWeb.folder.dto.response.FolderResponseDto;
import com.web.SearchWeb.folder.service.FolderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/**
* 코드 작성자:
* - 서진영(jin2304)
*
* 코드 설명:
* - 사용자의 폴더 관리 API (CRUD + 태그 조회).
* - 모든 요청은 OwnerCheck AOP를 통해 권한을 검증.
*
* 코드 주요 기능:
* - 폴더 생성
* - 폴더 단일 조회
* - 폴더 목록 조회
* - 폴더 수정
* - 폴더 삭제
* - 폴더 태그 목록 조회
*
* 코드 작성일:
* - 2025.12.31 ~ 2026.01.02
*/
@Controller
public class FolderController {

private final FolderService folderService;

@Autowired
public FolderController(FolderService folderService) {
this.folderService = folderService;
}


/**
* 폴더 생성
*/
@PostMapping("/myPage/{memberId}/folder")
@OwnerCheck(idParam = "memberId", service = "memberService")
public ResponseEntity<FolderResponseDto> insertFolder(@PathVariable final int memberId,
@RequestBody FolderCreateRequestDto folderCreateRequestDto) {
FolderResponseDto folder = folderService.insertFolder(memberId, folderCreateRequestDto);
return ResponseEntity.ok(folder);
}


/**
* 폴더 단일 조회
*/
@GetMapping("/myPage/{memberId}/folder/{folderId}")
@OwnerCheck(idParam = "memberId", service = "memberService")
public ResponseEntity<FolderResponseDto> getFolder(@PathVariable final int memberId,
@PathVariable final int folderId) {
FolderResponseDto folder = folderService.selectFolder(memberId, folderId);
return ResponseEntity.ok(folder);
}


/**
* 폴더 목록 조회
*/
@GetMapping("/myPage/{memberId}/folders")
@OwnerCheck(idParam = "memberId", service = "memberService")
public ResponseEntity<List<FolderResponseDto>> getFolders(@PathVariable final int memberId,
@RequestParam(required = false, defaultValue = "All") String tag,
@RequestParam(required = false, defaultValue = "Newest") String sort) {
List<FolderResponseDto> folders = folderService.selectFolderList(memberId, tag, sort);
return ResponseEntity.ok(folders);
}


/**
* 폴더 수정
*/
@PutMapping("/myPage/{memberId}/folder/{folderId}")
@OwnerCheck(idParam = "memberId", service = "memberService")
public ResponseEntity<Integer> updateFolder(@PathVariable final int memberId,
@PathVariable final int folderId,
@RequestBody FolderUpdateRequestDto folderUpdateRequestDto) {
int result = folderService.updateFolder(memberId, folderId, folderUpdateRequestDto);
return ResponseEntity.ok(result);
}
Comment on lines +86 to +93
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

@Valid 어노테이션 추가 필요

updateFolder@RequestBody에도 @Valid 어노테이션을 추가하여 입력 유효성 검증을 수행하세요.

🔎 제안된 수정
     public ResponseEntity<Integer> updateFolder(@PathVariable final int memberId,
                                                 @PathVariable final int folderId,
-                                                @RequestBody FolderUpdateRequestDto folderUpdateRequestDto) {
+                                                @RequestBody @Valid FolderUpdateRequestDto folderUpdateRequestDto) {
🤖 Prompt for AI Agents
In src/main/java/com/web/SearchWeb/folder/controller/FolderController.java
around lines 86 to 93, the @RequestBody parameter lacks validation; add the
@Valid annotation to the FolderUpdateRequestDto parameter (i.e., change the
method signature to accept @Valid @RequestBody FolderUpdateRequestDto) and
import the appropriate javax.validation.Valid or jakarta.validation.Valid
depending on your project, so Spring will perform bean validation on the
incoming payload.



/**
* 폴더 삭제
*/
@DeleteMapping("/myPage/{memberId}/folder/{folderId}")
@OwnerCheck(idParam = "memberId", service = "memberService")
public ResponseEntity<Integer> deleteFolder(@PathVariable final int memberId,
@PathVariable final int folderId) {
int result = folderService.deleteFolder(memberId, folderId);
return ResponseEntity.ok(result);
}


/**
* 폴더 태그 목록 조회
*/
@GetMapping("/myPage/{memberId}/folderTags")
@OwnerCheck(idParam = "memberId", service = "memberService")
public ResponseEntity<List<String>> getFolderTags(@PathVariable final int memberId) {
List<String> tags = folderService.selectFolderTags(memberId);
return ResponseEntity.ok(tags);
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/web/SearchWeb/folder/dao/FolderDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.web.SearchWeb.folder.dao;

import com.web.SearchWeb.folder.domain.Folder;
import com.web.SearchWeb.folder.dto.request.FolderSearchRequestDto;

import java.util.List;

public interface FolderDao {
// 폴더 생성
int insertFolder(Folder folder);
// 폴더 단일 조회
Folder selectFolder(int memberId, int folderId);
// 폴더 목록 조회
List<Folder> selectFolderList(FolderSearchRequestDto searchRequest);
// 폴더 수정
int updateFolder(Folder folder);
// 폴더 삭제
int deleteFolder(int memberId, int folderId);
// 폴더 태그 목록 조회
List<String> selectFolderTags(int memberId);
}
Loading