Skip to content

Commit 96c0073

Browse files
authored
Merge pull request #23 from Searchweb-Dev/feat/SW-38
Feat/sw 38 - DB 마이그레이션 (MySQL → PostgreSQL)
2 parents 672cc2d + cd740a6 commit 96c0073

65 files changed

Lines changed: 2038 additions & 909 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ dependencies {
2828
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
2929
implementation 'org.springframework.boot:spring-boot-starter-web'
3030
implementation 'org.springframework.boot:spring-boot-starter-aop'
31+
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
3132
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
3233
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
3334
implementation 'org.springframework.boot:spring-boot-starter-validation'
3435
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
3536
implementation 'me.paulschwarz:spring-dotenv:4.0.0'
3637

3738
compileOnly 'org.projectlombok:lombok'
38-
runtimeOnly 'com.mysql:mysql-connector-j'
39+
runtimeOnly 'org.postgresql:postgresql'
3940
annotationProcessor 'org.projectlombok:lombok'
4041
testImplementation 'org.springframework.boot:spring-boot-starter-test'
4142
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3'

docker-compose.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
version: '3.8'
2+
3+
services:
4+
postgres:
5+
image: postgres:16
6+
container_name: searchweb-db
7+
environment:
8+
POSTGRES_DB: ${POSTGRES_DB}
9+
POSTGRES_USER: ${POSTGRES_USER}
10+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
11+
TZ: Asia/Seoul
12+
ports:
13+
- "5432:5432"
14+
volumes:
15+
- postgres_data:/var/lib/postgresql/data
16+
# - ./src/main/resources/db/init.sql:/docker-entrypoint-initdb.d/init.sql
17+
networks:
18+
- searchweb-network
19+
restart: always
20+
21+
networks:
22+
searchweb-network:
23+
driver: bridge
24+
25+
volumes:
26+
postgres_data:

src/main/java/com/web/SearchWeb/aop/OwnerCheckAspect.java

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
import java.util.Arrays;
1919
import java.util.Objects;
2020

21+
/**
22+
* OwnerCheckAspect
23+
*
24+
* 리소스 소유자 검증 AOP
25+
*/
2126
@Aspect
2227
@Slf4j(topic = "[OwnerCheckAspect]")
2328
@Component
@@ -34,14 +39,14 @@ public class OwnerCheckAspect {
3439
@Before("@annotation(ownerCheck)")
3540
public void validateOwner(JoinPoint joinPoint, OwnerCheck ownerCheck) {
3641
// 접근 검증 대상 리소스의 ID 추출
37-
Integer targetId = extractTargetIdFromParams(joinPoint, ownerCheck.idParam());
42+
Long targetId = extractTargetIdFromParams(joinPoint, ownerCheck.idParam());
3843

3944
// 현재 로그인한 사용자의 memberId 추출
4045
Authentication auth = validateAuthenticatedUser();
41-
Integer currentUserId = extractMemberId(auth);
46+
Long currentUserId = extractMemberId(auth);
4247

4348
// 서비스 이름에 따라 리소스 작성자 memberId 조회
44-
Integer ownerId = findOwnerIdByServiceName(ownerCheck.service(), targetId);
49+
Long ownerId = findOwnerIdByServiceName(ownerCheck.service(), targetId);
4550

4651
// 현재 사용자와 리소스 소유자 검증
4752
if (!Objects.equals(currentUserId, ownerId)) {
@@ -54,29 +59,30 @@ public void validateOwner(JoinPoint joinPoint, OwnerCheck ownerCheck) {
5459

5560

5661
/**
57-
* 접근 검증 대상이 되는 리소스의 ID를 파라미터 이름(idParam)을 통해 찾아 Integer로 반환
62+
* 접근 검증 대상이 되는 리소스의 ID를 파라미터 이름(idParam)을 통해 찾아 Long으로 반환
5863
* ex) @OwnerCheck(idParam = "boardId", ...) -> 메서드의 boardId 값을 찾아 사용
5964
*
6065
* @param joinPoint 현재 실행된 메서드의 실행 정보
6166
* @param idParam 검증 대상 리소스 ID의 파라미터 이름 (예: "boardId" 문자열)
6267
* @return 접근 검증 대상이 되는 리소스의 ID 값
6368
*/
64-
private Integer extractTargetIdFromParams(JoinPoint joinPoint, String idParam) {
69+
private Long extractTargetIdFromParams(JoinPoint joinPoint, String idParam) {
6570
Object[] args = joinPoint.getArgs(); // 메서드 실제 인자 값 배열
6671
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
6772
String[] paramNames = signature.getParameterNames(); // 메서드 파라미터 이름 배열
6873

6974
for (int i = 0; i < paramNames.length; i++) {
7075
if (paramNames[i].equals(idParam)) {
71-
return Integer.parseInt(args[i].toString());
76+
// Integer나 Long 모두 지원하도록 String으로 변환 후 parse
77+
return Long.parseLong(args[i].toString());
7278
}
7379
}
7480
log.error("{}' 파라미터를 찾을 수 없음. 실제 파라미터: {}", idParam, Arrays.toString(paramNames));
7581
throw new IllegalArgumentException("요청 파라미터에서 ID를 찾을 수 없습니다.");
7682
}
7783

7884

79-
// SecurityContext 에서 인증된 사용자 반한
85+
// SecurityContext 에서 인증된 사용자 반환
8086
private Authentication validateAuthenticatedUser() {
8187
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
8288
if (auth == null || !auth.isAuthenticated() || "anonymousUser".equals(auth.getPrincipal())) {
@@ -87,8 +93,8 @@ private Authentication validateAuthenticatedUser() {
8793
}
8894

8995

90-
// 인증 객체에서 현재 로그인한 사용자 memberId 추출
91-
private Integer extractMemberId(Authentication auth) {
96+
// 인증 객체에서 현재 로그인한 사용자 memberId 추출 (Long 반환)
97+
private Long extractMemberId(Authentication auth) {
9298
Object principal = auth.getPrincipal();
9399
if (principal instanceof CustomUserDetails u) return u.getMemberId();
94100
if (principal instanceof CustomOAuth2User u) return u.getMemberId();
@@ -98,11 +104,11 @@ private Integer extractMemberId(Authentication auth) {
98104

99105

100106
// 서비스 이름에 따라 해당 리소스의 작성자 조회
101-
private Integer findOwnerIdByServiceName(String service, Integer targetId) {
107+
private Long findOwnerIdByServiceName(String service, Long targetId) {
102108
return switch (service) {
103109
case "boardService" -> boardService.findMemberIdByBoardId(targetId);
104110
case "commentService" -> commentService.findMemberIdByCommentId(targetId);
105-
case "memberService" -> targetId;
111+
case "memberService" -> targetId; // memberService의 경우 targetId가 곧 memberId
106112
default -> {
107113
log.error("지원하지 않는 서비스명 '{}'", service);
108114
throw new IllegalArgumentException("지원하지 않는 서비스명입니다.");

src/main/java/com/web/SearchWeb/board/controller/BoardController.java

Lines changed: 34 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,9 @@
2525
import java.util.Map;
2626

2727
/**
28-
* 코드 작성자:
29-
* - 서진영(jin2304)
30-
*
31-
* 코드 설명:
32-
* - BoardController는 게시판 및 게시글 관련 기능을 처리하는 컨트롤러
33-
*
34-
* 코드 주요 기능:
35-
* - 게시글 등록, 게시글 목록 조회(검색어, 최신순/인기순), 게시글 단일(상세) 조회, 게시글 수정, 게시글 삭제
36-
* - 게시글 좋아요/북마크 추가 및 취소
37-
*
38-
* 코드 작성일:
39-
* - 2024.08.24 ~ 2024.09.05
28+
* BoardController (Legacy - PostgreSQL)
29+
*
30+
* 게시판 및 게시글 관련 기능을 처리하는 컨트롤러
4031
*/
4132
@Controller
4233
public class BoardController {
@@ -55,15 +46,6 @@ public BoardController(BoardService boardservice, MemberService memberservice, L
5546
}
5647

5748

58-
/**
59-
* 게시글 생성
60-
*/
61-
@PostMapping("/board/{memberId}/post")
62-
public String insertBoard(@PathVariable int memberId, BoardDto boardDto){
63-
int result = boardservice.insertBoard(memberId, boardDto);
64-
return "redirect:/board";
65-
}
66-
6749

6850

6951
/**
@@ -76,27 +58,20 @@ public String boardPage() {
7658

7759

7860
/**
79-
* 페이징된 게시글 목록 조회
80-
* - 검색어, 최신순/인기순, 게시글타입
81-
* - 스크롤 방식으로 페이징 지원
82-
* - 클라이언트(JS)에서 스크롤 이벤트 발생 시 요청
61+
* 게시글 생성
8362
*/
84-
@ResponseBody
85-
@GetMapping("api/boards")
86-
public Map<String, Object> getBoards(@RequestParam(defaultValue = "0") int page,
87-
@RequestParam(defaultValue = "10") int size,
88-
@RequestParam(defaultValue = "newest") String sort,
89-
@RequestParam(required = false) String query,
90-
@RequestParam(defaultValue = "all") String postType) {
91-
return boardservice.selectBoardPage(page, size, sort, query, postType);
63+
@PostMapping("/board/{memberId}/post")
64+
public String insertBoard(@PathVariable Long memberId, BoardDto boardDto){
65+
int result = boardservice.insertBoard(memberId, boardDto);
66+
return "redirect:/board";
9267
}
9368

9469

9570
/**
9671
* 게시글 단일 조회
9772
*/
9873
@GetMapping("/board/{boardId}")
99-
public String boardDetail(@PathVariable int boardId,@AuthenticationPrincipal Object currentUser, Model model){
74+
public String boardDetail(@PathVariable Long boardId, @AuthenticationPrincipal Object currentUser, Model model){
10075
Map<String, Object> boardData = boardservice.selectBoard(boardId);
10176
Board board = (Board) boardData.get("board");
10277
String[] hashtagsList = (String[]) boardData.get("hashtagsList");
@@ -106,7 +81,7 @@ public String boardDetail(@PathVariable int boardId,@AuthenticationPrincipal Obj
10681

10782
// 사용자가 로그인된 상태라면, 좋아요 여부를 확인하여 모델에 추가
10883
if (currentUser != null && !"anonymousUser".equals(currentUser)) {
109-
int memberId;
84+
Long memberId;
11085
if(currentUser instanceof UserDetails) {
11186
// 일반 로그인 사용자 처리
11287
memberId = ((CustomUserDetails) currentUser).getMemberId();
@@ -129,12 +104,29 @@ else if(currentUser instanceof OAuth2User) {
129104
}
130105

131106

107+
/**
108+
* 페이징된 게시글 목록 조회
109+
* - 검색어, 최신순/인기순, 게시글타입
110+
* - 스크롤 방식으로 페이징 지원
111+
* - 클라이언트(JS)에서 스크롤 이벤트 발생 시 요청
112+
*/
113+
@ResponseBody
114+
@GetMapping("api/boards")
115+
public Map<String, Object> getBoards(@RequestParam(defaultValue = "0") int page,
116+
@RequestParam(defaultValue = "10") int size,
117+
@RequestParam(defaultValue = "newest") String sort,
118+
@RequestParam(required = false) String query,
119+
@RequestParam(defaultValue = "all") String postType) {
120+
return boardservice.selectBoardPage(page, size, sort, query, postType);
121+
}
122+
123+
132124
/**
133125
* 게시글 수정
134126
*/
135127
@PostMapping("/board/{boardId}/update")
136128
@OwnerCheck(idParam = "boardId", service = "boardService")
137-
public String updateBoard(@PathVariable int boardId, BoardDto boardDto){
129+
public String updateBoard(@PathVariable Long boardId, BoardDto boardDto){
138130
boardservice.updateBoard(boardId, boardDto);
139131
return "redirect:/board/{boardId}";
140132
}
@@ -145,7 +137,7 @@ public String updateBoard(@PathVariable int boardId, BoardDto boardDto){
145137
*/
146138
@PostMapping("/board/{boardId}/delete")
147139
@OwnerCheck(idParam = "boardId", service = "boardService")
148-
public String deleteBoard(@PathVariable int boardId) {
140+
public String deleteBoard(@PathVariable Long boardId) {
149141
boardservice.deleteBoard(boardId);
150142
return "redirect:/board";
151143
}
@@ -156,7 +148,7 @@ public String deleteBoard(@PathVariable int boardId) {
156148
*/
157149
@PostMapping("/board/{boardId}/like")
158150
@ResponseBody
159-
public Map<String, Object> toggleLike(@PathVariable int boardId, @AuthenticationPrincipal Object currentUser) {
151+
public Map<String, Object> toggleLike(@PathVariable Long boardId, @AuthenticationPrincipal Object currentUser) {
160152

161153
Map<String, Object> response = new HashMap<>();
162154

@@ -168,7 +160,7 @@ public Map<String, Object> toggleLike(@PathVariable int boardId, @Authentication
168160
}
169161

170162
// 로그인 된 경우
171-
int memberId;
163+
Long memberId;
172164
if(currentUser instanceof UserDetails) {
173165
// 일반 로그인 사용자 처리
174166
memberId = ((CustomUserDetails) currentUser).getMemberId();
@@ -192,8 +184,8 @@ else if(currentUser instanceof OAuth2User) {
192184
*/
193185
@PostMapping(value ="/board/{boardId}/bookmark/{memberId}")
194186
public ResponseEntity<Map<String, Object>> toggleBookmark(
195-
@PathVariable final int boardId,
196-
@PathVariable final int memberId,
187+
@PathVariable final Long boardId,
188+
@PathVariable final Long memberId,
197189
@RequestBody BookmarkDto bookmarkDto,
198190
@AuthenticationPrincipal Object currentUser){
199191
Map<String, Object> response = new HashMap<>();
@@ -211,7 +203,7 @@ public ResponseEntity<Map<String, Object>> toggleBookmark(
211203

212204
if (bookmarkExists == 0) {
213205
// 북마크가 안 되어 있으면 북마크 추가
214-
bookmarkService.insertBookmarkForBoard(bookmarkDto);
206+
bookmarkService.insertBookmarkForBoard(boardId, bookmarkDto);
215207
boardservice.incrementBookmarkCount(boardId); // 북마크 추가 시 게시글의 북마크 수 증가
216208
response.put("action", "bookmarked");
217209
} else {

src/main/java/com/web/SearchWeb/board/dao/BoardDao.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
public interface BoardDao {
1111
//게시글 생성
12-
public int insertBoard(int memberId, BoardDto boardDto);
12+
public int insertBoard(Long memberId, BoardDto boardDto);
1313

1414
// 페이징된 게시글 목록 조회
1515
List<Board> selectBoardPage(@Param("offset") int offset,
@@ -22,35 +22,35 @@ List<Board> selectBoardPage(@Param("offset") int offset,
2222
int countBoardList(String query, String postType);
2323

2424
//게시글 목록 조회(회원번호로 조회)
25-
List<Board> selectBoardListByMemberId(int memberId);
25+
List<Board> selectBoardListByMemberId(Long memberId);
2626

2727
//게시글 단일 조회
28-
Board selectBoard(int boardId);
28+
Board selectBoard(Long boardId);
2929

3030
//게시글 수정
31-
int updateBoard(int boardId, BoardDto boardDto);
31+
int updateBoard(Long boardId, BoardDto boardDto);
3232

3333
//게시글 수정(회원정보 수정)
34-
int updateBoardProfile(int boardId, String job, String major);
34+
int updateBoardProfile(Long boardId, String job, String major);
3535

3636
//게시글 삭제
37-
int deleteBoard(int boardId);
37+
int deleteBoard(Long boardId);
3838

3939
//게시글 북마크 수 수정
40-
int updateBookmarkCount(int boardId, int bookmarkCount);
40+
int updateBookmarkCount(Long boardId, int bookmarkCount);
4141

4242
//게시글 조회수 증가
43-
int incrementViewCount(int boardId);
43+
int incrementViewCount(Long boardId);
4444

4545
//게시글 좋아요 증가
46-
int incrementLikeCount(int boardId);
46+
int incrementLikeCount(Long boardId);
4747

4848
//게시글 좋아요 감소
49-
int decrementLikeCount(int boardId);
49+
int decrementLikeCount(Long boardId);
5050

5151
//게시글 댓글 수 증가
52-
int incrementCommentCount(int boardId);
52+
int incrementCommentCount(Long boardId);
5353

5454
//게시글 댓글 수 감소
55-
int decrementCommentCount(int boardId);
55+
int decrementCommentCount(Long boardId);
5656
}

0 commit comments

Comments
 (0)