From 678255a8e1c75a49643c7a197e6e656b20de0217 Mon Sep 17 00:00:00 2001 From: JYP Date: Sun, 1 Dec 2024 20:43:27 +0900 Subject: [PATCH 01/10] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=A9=94=EC=9D=BC/?= =?UTF-8?q?=EC=86=8C=EC=85=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=9D=91=EB=8B=B5=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20(#103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/AuthController.java | 38 +++++++++---------- .../controller/KakaoOAuth2Controller.java | 36 ++++++++---------- .../oauth2/service/KakaoOAuth2Service.java | 1 + .../member/service/AuthService.java | 29 +++++++------- .../member/servcie/AuthServiceTest.java | 2 +- 5 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/zero/bwtableback/member/controller/AuthController.java b/src/main/java/com/zero/bwtableback/member/controller/AuthController.java index d0b5ee22..7e607bda 100644 --- a/src/main/java/com/zero/bwtableback/member/controller/AuthController.java +++ b/src/main/java/com/zero/bwtableback/member/controller/AuthController.java @@ -93,31 +93,27 @@ public ResponseEntity signUp(@Valid @RequestBody SignUpReqDto signU public ResponseEntity login(@RequestBody EmailLoginReqDto loginReqDto, HttpServletRequest request, HttpServletResponse response) { - MemberDto memberDto = authService.authenticateMember(loginReqDto); try { - String accessToken = getJwtFromRequest(request); - - // 액세스 토큰이 유효한 경우 - if (StringUtils.hasText(accessToken) && tokenProvider.validateAccessToken(accessToken)) { - // 기존의 액세스 토큰과 사용자 정보를 반환 - return ResponseEntity.ok(authService.handleExistingToken(accessToken)); + MemberDto authenticatedMember = authService.authenticateMember(loginReqDto); + String accessToken = tokenProvider.extractToken(request); + + if (StringUtils.hasText(accessToken)) { + if (tokenProvider.validateAccessToken(accessToken)) { + // 유효한 토큰이 있는 경우, 기존 토큰 정보 반환 + return ResponseEntity.ok(authService.handleExistingToken(accessToken)); + } else { + // 토큰이 만료된 경우, 401 에러 반환 + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("토큰이 만료되었습니다."); + } + } else { + // 토큰이 없는 경우, 새로운 로그인 프로세스 진행 + return ResponseEntity.ok(authService.login(authenticatedMember, request, response)); } - // 액세스 토큰이 없거나 유효하지 않은 경우, 새로운 로그인 처리 - LoginResDto loginResDto = authService.login(memberDto, request, response); - return ResponseEntity.ok(loginResDto); - } catch (CustomException e) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body("Unauthorized: " + e.getMessage()); - } - } - - private String getJwtFromRequest(HttpServletRequest request) { - String bearerToken = request.getHeader("Authorization"); - if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { - return bearerToken.substring(7); // "Bearer " 부분을 제거하고 토큰 반환 + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Forbidden: " + e.getMessage()); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("로그인 정보가 유효하지 않습니다."); } - return null; // 토큰이 없으면 null 반환 } /** diff --git a/src/main/java/com/zero/bwtableback/member/oauth2/controller/KakaoOAuth2Controller.java b/src/main/java/com/zero/bwtableback/member/oauth2/controller/KakaoOAuth2Controller.java index d73588ac..4f87496f 100644 --- a/src/main/java/com/zero/bwtableback/member/oauth2/controller/KakaoOAuth2Controller.java +++ b/src/main/java/com/zero/bwtableback/member/oauth2/controller/KakaoOAuth2Controller.java @@ -41,9 +41,6 @@ public class KakaoOAuth2Controller { public ResponseEntity kakaoLogin(@RequestParam(required = false) String code, HttpServletRequest request, HttpServletResponse response) throws JsonProcessingException { - // 요청 헤더에서 액세스 토큰 추출 - String accessToken = getJwtFromRequest(request); - // 첫 번째 로그인: 카카오에서 정보를 추출하여 서버에 회원가입 if (code != null) { String kakaoToken = kakaoService.getAccessToken(code); @@ -52,24 +49,23 @@ public ResponseEntity kakaoLogin(@RequestParam(required = false) String code, return ResponseEntity.ok(loginResDto); } else { - // 액세스 토큰 존재하고 유효한 경우 - if (StringUtils.hasText(accessToken) && tokenProvider.validateAccessToken(accessToken)) { - // 기존의 액세스 토큰과 사용자 정보를 반환 - LoginResDto loginResDto = authService.handleExistingToken(accessToken); - - return ResponseEntity.ok(loginResDto); + // 카카오 인가 코드가 없는 경우 + String accessToken = tokenProvider.extractToken(request); + if (StringUtils.hasText(accessToken)) { + if (tokenProvider.validateAccessToken(accessToken)) { + // 유효한 액세스 토큰이 있는 경우 + LoginResDto loginResDto = authService.handleExistingToken(accessToken); + return ResponseEntity.ok(loginResDto); + } else { + // 액세스 토큰이 만료된 경우 + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("토큰이 만료되었습니다."); + } + } else { + // 액세스 토큰이 없는 경우 + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("토큰이 존재하지 않습니다."); } - // 토큰이 없거나 유효하지 않은 경우 401 응답을 던짐 - return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body("Unauthorized. 토큰이 유효하지 않습니다."); - } - } - - private String getJwtFromRequest(HttpServletRequest request) { - String bearerToken = request.getHeader("Authorization"); - if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { - return bearerToken.substring(7); // "Bearer " 부분을 제거하고 토큰 반환 } - return null; // 토큰이 없으면 null 반환 } } \ No newline at end of file diff --git a/src/main/java/com/zero/bwtableback/member/oauth2/service/KakaoOAuth2Service.java b/src/main/java/com/zero/bwtableback/member/oauth2/service/KakaoOAuth2Service.java index 0d769f7c..bdeb286a 100644 --- a/src/main/java/com/zero/bwtableback/member/oauth2/service/KakaoOAuth2Service.java +++ b/src/main/java/com/zero/bwtableback/member/oauth2/service/KakaoOAuth2Service.java @@ -139,6 +139,7 @@ private MemberDto registerNewMember(KakaoUserInfoDto userInfo) { .nickname(userInfo.getNickName()) .phone(userInfo.getPhone()) .role(Role.GUEST) + .status(Status.ACTIVE) .provider(userInfo.getProvider()) .providerId(userInfo.getProviderId()) .profileImage(userInfo.getProfileImage()) diff --git a/src/main/java/com/zero/bwtableback/member/service/AuthService.java b/src/main/java/com/zero/bwtableback/member/service/AuthService.java index e103c8e8..df91d489 100644 --- a/src/main/java/com/zero/bwtableback/member/service/AuthService.java +++ b/src/main/java/com/zero/bwtableback/member/service/AuthService.java @@ -123,26 +123,27 @@ public LoginResDto signUpLogin(MemberDto memberDto, HttpServletRequest request, * 로그인 */ public LoginResDto login(MemberDto memberDto, HttpServletRequest request, HttpServletResponse response) { + try { + String accessToken = tokenProvider.createAccessToken(memberDto.getEmail(), memberDto.getRole()); + String refreshToken = tokenProvider.createRefreshToken(memberDto.getId().toString()); - String accessToken = tokenProvider.createAccessToken(memberDto.getEmail(), memberDto.getRole()); - String refreshToken = tokenProvider.createRefreshToken(memberDto.getId().toString()); - - // 회원 상태 조회 - - // HttpOnly 쿠키에 리프레시 토큰 저장 - saveRefreshTokenToCookie(refreshToken, response); - - // Redis에 리프레시 토큰 저장 - saveRefreshTokenToRedis(memberDto.getId(), refreshToken); + // HttpOnly 쿠키에 리프레시 토큰 저장 + saveRefreshTokenToCookie(refreshToken, response); - // 레스토랑 ID 조회 (사장님일 경우) - Long restaurantId = getRestaurantIdIfOwner(memberDto); + // Redis에 리프레시 토큰 저장 + saveRefreshTokenToRedis(memberDto.getId(), refreshToken); + // 레스토랑 ID 조회 (사장님일 경우) + Long restaurantId = getRestaurantIdIfOwner(memberDto); - return new LoginResDto(accessToken, memberDto, restaurantId); + return new LoginResDto(accessToken, memberDto, restaurantId); + } catch (Exception e) { + log.error("로그인 실패: {}", memberDto.getEmail(), e); + throw new IllegalArgumentException("로그인 실패", e); + } } - // 회원 인증 + // 이메일과 비밀번호 검증 public MemberDto authenticateMember(EmailLoginReqDto loginReqDto) { Member member = memberRepository.findByEmail(loginReqDto.getEmail()) .orElseThrow(() -> new CustomException(ErrorCode.INVALID_CREDENTIALS)); diff --git a/src/test/java/com/zero/bwtableback/member/servcie/AuthServiceTest.java b/src/test/java/com/zero/bwtableback/member/servcie/AuthServiceTest.java index 56f7efda..a53228f1 100644 --- a/src/test/java/com/zero/bwtableback/member/servcie/AuthServiceTest.java +++ b/src/test/java/com/zero/bwtableback/member/servcie/AuthServiceTest.java @@ -364,7 +364,7 @@ void logoutTest() { when(memberRepository.findByEmail(email)).thenReturn(Optional.of(member)); // when - authService.logout(email, request, response); + authService.logout(email, response); // then ArgumentCaptor cookieCaptor = ArgumentCaptor.forClass(Cookie.class); // HttpServletResponse에 추가된 쿠키 캡처 From 450fcf4f71466b76e69a84a1a5dd2e99eb6b4fb2 Mon Sep 17 00:00:00 2001 From: JYP Date: Sun, 1 Dec 2024 21:23:03 +0900 Subject: [PATCH 02/10] =?UTF-8?q?refactor:=20MemberController,MemberServic?= =?UTF-8?q?e=20=EC=A4=91=EB=B3=B5=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20(#103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/AuthController.java | 5 +- .../member/controller/MemberController.java | 18 ++---- .../member/dto/MemberPrivateDto.java | 15 +++++ .../member/service/AuthService.java | 13 ++-- .../member/service/MemberService.java | 61 ++++++------------- .../member/servcie/AuthServiceTest.java | 4 +- .../member/servcie/MemberServiceTest.java | 14 ++--- 7 files changed, 57 insertions(+), 73 deletions(-) diff --git a/src/main/java/com/zero/bwtableback/member/controller/AuthController.java b/src/main/java/com/zero/bwtableback/member/controller/AuthController.java index 7e607bda..aa1677ff 100644 --- a/src/main/java/com/zero/bwtableback/member/controller/AuthController.java +++ b/src/main/java/com/zero/bwtableback/member/controller/AuthController.java @@ -148,9 +148,8 @@ private String getRefreshTokenFromCookies(HttpServletRequest request) { @PostMapping("/logout") public ResponseEntity logout(@AuthenticationPrincipal MemberDetails memberDetails, HttpServletResponse response) { - String email = memberDetails.getUsername(); - authService.logout(email, response); + authService.logout(memberDetails.getMemberId(), response); return ResponseEntity.ok("로그아웃이 완료되었습니다."); } @@ -164,7 +163,7 @@ public ResponseEntity withdrawMember(@AuthenticationPrincipal MemberDetails m HttpServletResponse response) { authService.withdraw(memberDetails.getMemberId(), response); - return ResponseEntity.ok().body("회원탈퇴가 완료되었습니다."); + return ResponseEntity.ok("회원탈퇴가 완료되었습니다."); } } diff --git a/src/main/java/com/zero/bwtableback/member/controller/MemberController.java b/src/main/java/com/zero/bwtableback/member/controller/MemberController.java index 9f668c36..7f5b4c07 100644 --- a/src/main/java/com/zero/bwtableback/member/controller/MemberController.java +++ b/src/main/java/com/zero/bwtableback/member/controller/MemberController.java @@ -42,7 +42,7 @@ public ResponseEntity> getMembers(Pageable pageable) { */ @GetMapping("/{memberId}") public MemberDto getMemberById(@PathVariable Long memberId) { - return memberService.getMemberById(memberId); + return memberService.getMember(memberId); } /** @@ -55,8 +55,7 @@ public ResponseEntity getMyInfo(@AuthenticationPrincipal MemberDetails member if (memberDetails == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - Long memberId = memberDetails.getMemberId(); - return ResponseEntity.ok(memberService.getMyInfo(memberId)); + return ResponseEntity.ok(memberService.getMyInfo(memberDetails.getMemberId())); } /** @@ -68,9 +67,8 @@ public ResponseEntity> getMyReservations(Pageable pageab if (memberDetails == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - String email = memberDetails.getUsername(); - return ResponseEntity.ok(memberService.getMyReservations(pageable, email)); + return ResponseEntity.ok(memberService.getMyReservations(pageable, memberDetails.getMemberId())); } /** @@ -79,8 +77,7 @@ public ResponseEntity> getMyReservations(Pageable pageab @GetMapping("/me/reviews") public ResponseEntity> getMyReviews(Pageable pageable, @AuthenticationPrincipal MemberDetails memberDetails) { - String email = memberDetails.getUsername(); - return ResponseEntity.ok(memberService.getMyReviews(pageable, email)); + return ResponseEntity.ok(memberService.getMyReviews(pageable, memberDetails.getMemberId())); } /** @@ -92,9 +89,8 @@ public ResponseEntity> getMyChats(Pageable pageable, if (memberDetails == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - String email = memberDetails.getUsername(); - Page rooms = memberService.getMyChatRooms(pageable, email); + Page rooms = memberService.getMyChatRooms(pageable, memberDetails.getMemberId()); return ResponseEntity.ok(rooms); } @@ -108,7 +104,6 @@ public ResponseEntity> uploadFile(@AuthenticationPrincipal M if (memberDetails == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } - String email = memberDetails.getUsername(); try { String fileUrl = imageUploadService.uploadProfileImage(file, memberDetails.getMemberId()); @@ -131,8 +126,7 @@ public ResponseEntity> uploadFile(@AuthenticationPrincipal M * 새로운 이미지 업로드 (S3) */ @PutMapping("/me/profile-image") - public ResponseEntity updateProfileImage(@AuthenticationPrincipal MemberDetails memberDetails, - @RequestParam("file") MultipartFile file) throws IOException { + public ResponseEntity updateProfileImage(@AuthenticationPrincipal MemberDetails memberDetails, @RequestParam("file") MultipartFile file) throws IOException { return ResponseEntity.ok(imageUploadService.updateProfileImage(file, memberDetails.getMemberId())); } diff --git a/src/main/java/com/zero/bwtableback/member/dto/MemberPrivateDto.java b/src/main/java/com/zero/bwtableback/member/dto/MemberPrivateDto.java index 8b99f470..39a8c863 100644 --- a/src/main/java/com/zero/bwtableback/member/dto/MemberPrivateDto.java +++ b/src/main/java/com/zero/bwtableback/member/dto/MemberPrivateDto.java @@ -1,6 +1,7 @@ package com.zero.bwtableback.member.dto; import com.zero.bwtableback.member.entity.LoginType; +import com.zero.bwtableback.member.entity.Member; import com.zero.bwtableback.member.entity.Role; import lombok.AllArgsConstructor; import lombok.Getter; @@ -16,4 +17,18 @@ public MemberPrivateDto(Long id, String email, String name, String nickname, super(id, email, name, nickname, phone, role, profileImage, businessNubmer); this.loginType = loginType; } + + public static MemberPrivateDto from(Member member) { + return new MemberPrivateDto( + member.getId(), + member.getEmail(), + member.getName(), + member.getNickname(), + member.getPhone(), + member.getRole(), + member.getProfileImage(), + member.getBusinessNumber(), + member.getLoginType() + ); + } } diff --git a/src/main/java/com/zero/bwtableback/member/service/AuthService.java b/src/main/java/com/zero/bwtableback/member/service/AuthService.java index df91d489..86943661 100644 --- a/src/main/java/com/zero/bwtableback/member/service/AuthService.java +++ b/src/main/java/com/zero/bwtableback/member/service/AuthService.java @@ -235,9 +235,8 @@ private Long getRestaurantIdIfOwner(MemberDto member) { /** * 사용자 로그아웃 처리 */ - public void logout(String email, HttpServletResponse response) { - Member member = memberRepository.findByEmail(email) - .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + public void logout(Long memberId, HttpServletResponse response) { + Member member = getMemberById(memberId); String key = "refresh_token:" + member.getId(); redisTemplate.delete(key); @@ -256,8 +255,7 @@ public void logout(String email, HttpServletResponse response) { * 로그아웃 처리 후 */ public void withdraw(Long memberId, HttpServletResponse response) { - Member member = memberRepository.findById(memberId) - .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + Member member = getMemberById(memberId); String key = "refresh_token:" + member.getId(); redisTemplate.delete(key); @@ -275,4 +273,9 @@ public void withdraw(Long memberId, HttpServletResponse response) { member.setStatus(Status.INACTIVE); memberRepository.save(member); } + + public Member getMemberById(Long memberId) { + return memberRepository.findById(memberId) + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + } } \ No newline at end of file diff --git a/src/main/java/com/zero/bwtableback/member/service/MemberService.java b/src/main/java/com/zero/bwtableback/member/service/MemberService.java index 6be7cde9..b96948c7 100644 --- a/src/main/java/com/zero/bwtableback/member/service/MemberService.java +++ b/src/main/java/com/zero/bwtableback/member/service/MemberService.java @@ -32,73 +32,46 @@ public class MemberService { */ public Page getMembers(Pageable pageable) { return memberRepository.findAll(pageable) - .map(this::convertToDto); + .map(MemberDto::from); } /** - * 단일 회원 정보 조회 + * 회원 정보 조회 */ - public MemberDto getMemberById(Long memberId) { + public MemberDto getMember(Long memberId) { Member member = memberRepository.findById(memberId) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); - return convertToDto(member); + return MemberDto.from(member); } /** * 본인 정보 조회 */ public MemberPrivateDto getMyInfo(Long memberId) { - Member member = memberRepository.findById(memberId) - .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); - return convertToPrivateDto(member); - } - - private MemberDto convertToDto(Member member) { - return new MemberDto( - member.getId(), - member.getEmail(), - member.getName(), - member.getNickname(), - member.getPhone(), - member.getRole(), - member.getProfileImage(), - member.getBusinessNumber()); + Member member = getMemberById(memberId); + return MemberPrivateDto.from(member); } - private MemberPrivateDto convertToPrivateDto(Member member) { - return new MemberPrivateDto( - member.getId(), - member.getEmail(), - member.getName(), - member.getNickname(), - member.getPhone(), - member.getRole(), - member.getProfileImage(), - member.getBusinessNumber(), - member.getLoginType()); - } - - public Page getMyReservations(Pageable pageable, String email) { - Member member = memberRepository.findByEmail(email) - .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); - + public Page getMyReservations(Pageable pageable, Long memberId) { + Member member = getMemberById(memberId); return reservationRepository.findByMemberId(member.getId(), pageable) .map(ReservationResDto::fromEntity); } - public Page getMyReviews(Pageable pageable, String email) { - Member member = memberRepository.findByEmail(email) - .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); - + public Page getMyReviews(Pageable pageable, Long memberId) { + Member member = getMemberById(memberId); return reviewRepository.findByMemberIdOrderByRestaurantId(member.getId(), pageable) .map(ReviewDetailDto::fromEntity); } - public Page getMyChatRooms(Pageable pageable, String email) { - Member member = memberRepository.findByEmail(email) - .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); - + public Page getMyChatRooms(Pageable pageable, Long memberId) { + Member member = getMemberById(memberId); return chatRoomRepository.findChatRoomsByMemberIdOrderByLastMessageTime(member.getId(), pageable) .map(ChatRoomCreateResDto::fromEntity); } + + private Member getMemberById(Long memberId) { + return memberRepository.findById(memberId) + .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + } } \ No newline at end of file diff --git a/src/test/java/com/zero/bwtableback/member/servcie/AuthServiceTest.java b/src/test/java/com/zero/bwtableback/member/servcie/AuthServiceTest.java index a53228f1..1914b7fa 100644 --- a/src/test/java/com/zero/bwtableback/member/servcie/AuthServiceTest.java +++ b/src/test/java/com/zero/bwtableback/member/servcie/AuthServiceTest.java @@ -361,10 +361,10 @@ void logoutTest() { HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(HttpServletResponse.class); - when(memberRepository.findByEmail(email)).thenReturn(Optional.of(member)); + when(memberRepository.findById(memberId)).thenReturn(Optional.of(member)); // when - authService.logout(email, response); + authService.logout(memberId, response); // then ArgumentCaptor cookieCaptor = ArgumentCaptor.forClass(Cookie.class); // HttpServletResponse에 추가된 쿠키 캡처 diff --git a/src/test/java/com/zero/bwtableback/member/servcie/MemberServiceTest.java b/src/test/java/com/zero/bwtableback/member/servcie/MemberServiceTest.java index 0d460b9c..30376b85 100644 --- a/src/test/java/com/zero/bwtableback/member/servcie/MemberServiceTest.java +++ b/src/test/java/com/zero/bwtableback/member/servcie/MemberServiceTest.java @@ -15,7 +15,7 @@ import com.zero.bwtableback.reservation.entity.Reservation; import com.zero.bwtableback.reservation.entity.ReservationStatus; import com.zero.bwtableback.reservation.repository.ReservationRepository; -import com.zero.bwtableback.restaurant.dto.ReviewInfoDto; +import com.zero.bwtableback.restaurant.dto.ReviewDetailDto; import com.zero.bwtableback.restaurant.entity.Restaurant; import com.zero.bwtableback.restaurant.entity.Review; import com.zero.bwtableback.restaurant.repository.ReviewRepository; @@ -99,7 +99,7 @@ void testGetMemberById_Success() { when(memberRepository.findById(1L)).thenReturn(Optional.of(member)); // when - MemberDto result = memberService.getMemberById(1L); + MemberDto result = memberService.getMember(1L); System.out.println(result.getName()); // then @@ -115,7 +115,7 @@ public void testGetMemberById_UserNotFound() { // when & then CustomException exception = assertThrows(CustomException.class, () -> { - memberService.getMemberById(1L); + memberService.getMember(1L); }); assertEquals(ErrorCode.USER_NOT_FOUND, exception.getErrorCode()); } @@ -168,7 +168,7 @@ void testGetMyReservations_Success() { when(reservationRepository.findByMemberId(member.getId(), pageable)).thenReturn(pageReservations); // when - Page result = memberService.getMyReservations(pageable, member.getEmail()); + Page result = memberService.getMyReservations(pageable, member.getId()); // then assertNotNull(result); @@ -187,7 +187,7 @@ void testGetMyReviews_Success() { when(reviewRepository.findByMemberIdOrderByRestaurantId(member.getId(), pageable)).thenReturn(new PageImpl<>(reviews)); // when - Page result = memberService.getMyReviews(pageable, member.getEmail()); + Page result = memberService.getMyReviews(pageable, member.getId()); // then assertNotNull(result); @@ -201,11 +201,11 @@ void testGetMyChatRooms_Success() { Pageable pageable = PageRequest.of(0, 10); List chatRooms = new ArrayList<>(); // Mock ChatRoomCreateResDto 객체 추가 - when(memberRepository.findByEmail(member.getEmail())).thenReturn(Optional.of(member)); + when(memberRepository.findById(member.getId())).thenReturn(Optional.of(member)); when(chatRoomRepository.findChatRoomsByMemberIdOrderByLastMessageTime(member.getId(), pageable)).thenReturn(new PageImpl<>(chatRooms)); // when - Page result = memberService.getMyChatRooms(pageable, member.getEmail()); + Page result = memberService.getMyChatRooms(pageable, member.getId()); // then assertNotNull(result); From f41edb1e832c3fbce6c511b55c5f8bc70f2ea684 Mon Sep 17 00:00:00 2001 From: JYP Date: Sun, 1 Dec 2024 21:34:07 +0900 Subject: [PATCH 03/10] =?UTF-8?q?refactor:=20MemberController,MemberServic?= =?UTF-8?q?e=20=EC=A4=91=EB=B3=B5=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20(#103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zero/bwtableback/common/exception/ErrorCode.java | 2 ++ .../zero/bwtableback/member/service/AuthService.java | 7 ++----- .../bwtableback/member/service/MemberService.java | 11 ++++++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/zero/bwtableback/common/exception/ErrorCode.java b/src/main/java/com/zero/bwtableback/common/exception/ErrorCode.java index beab124d..a9ab11d6 100644 --- a/src/main/java/com/zero/bwtableback/common/exception/ErrorCode.java +++ b/src/main/java/com/zero/bwtableback/common/exception/ErrorCode.java @@ -79,6 +79,8 @@ public enum ErrorCode { FILE_UPLOAD_FAILED(HttpStatus.BAD_REQUEST, "파일 업로드에 실패했습니다."), FILE_DELETE_FAILED(HttpStatus.BAD_REQUEST, "파일 삭제에 실패하였습니다."), + // REDIS 오류 + REDIS_CONNECTION_FAILURE(HttpStatus.INTERNAL_SERVER_ERROR,"Redis에 연결할 수 없습니다."), // 기타 오류 UNAUTHORIZED_ACCESS(HttpStatus.FORBIDDEN, "접근 권한이 없습니다."), INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 내부 오류가 발생했습니다."); diff --git a/src/main/java/com/zero/bwtableback/member/service/AuthService.java b/src/main/java/com/zero/bwtableback/member/service/AuthService.java index 86943661..c9671754 100644 --- a/src/main/java/com/zero/bwtableback/member/service/AuthService.java +++ b/src/main/java/com/zero/bwtableback/member/service/AuthService.java @@ -163,7 +163,6 @@ public MemberDto authenticateMember(EmailLoginReqDto loginReqDto) { // 리프레시 토큰으로 액세스 토큰 갱신 public LoginResDto renewAccessTokenWithRefreshToken(String refreshToken) { String email = tokenProvider.getUsername(refreshToken); - Member member = memberRepository.findByEmail(email) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); @@ -179,7 +178,6 @@ public LoginResDto renewAccessTokenWithRefreshToken(String refreshToken) { // 리프레시 토큰 검증 public void validateRefreshToken(String refreshToken, Long memberId) { String key = "refresh_token:" + memberId; - String storedRefreshToken = redisTemplate.opsForValue().get(key); if (storedRefreshToken == null || !storedRefreshToken.equals(refreshToken)) { @@ -203,10 +201,9 @@ public void saveRefreshTokenToRedis(Long memberId, String refreshToken) { try { redisTemplate.opsForValue().set(key, refreshToken); } catch (RedisConnectionFailureException e) { - System.err.println("Redis에 연결할 수 없습니다: " + e.getMessage()); + throw new CustomException(ErrorCode.REDIS_CONNECTION_FAILURE); } catch (Exception e) { - // 다른 예외 처리 - System.err.println("예기치 않은 오류 발생: " + e.getMessage()); + throw new CustomException(ErrorCode.INTERNAL_SERVER_ERROR); } } diff --git a/src/main/java/com/zero/bwtableback/member/service/MemberService.java b/src/main/java/com/zero/bwtableback/member/service/MemberService.java index b96948c7..deaeff8e 100644 --- a/src/main/java/com/zero/bwtableback/member/service/MemberService.java +++ b/src/main/java/com/zero/bwtableback/member/service/MemberService.java @@ -52,24 +52,33 @@ public MemberPrivateDto getMyInfo(Long memberId) { return MemberPrivateDto.from(member); } + /** + * 나의 예약 목록 조회 + */ public Page getMyReservations(Pageable pageable, Long memberId) { Member member = getMemberById(memberId); return reservationRepository.findByMemberId(member.getId(), pageable) .map(ReservationResDto::fromEntity); } + /** + * 나의 리뷰 목록 조회 + */ public Page getMyReviews(Pageable pageable, Long memberId) { Member member = getMemberById(memberId); return reviewRepository.findByMemberIdOrderByRestaurantId(member.getId(), pageable) .map(ReviewDetailDto::fromEntity); } + /** + * 나의 채팅방 조회 + */ public Page getMyChatRooms(Pageable pageable, Long memberId) { Member member = getMemberById(memberId); return chatRoomRepository.findChatRoomsByMemberIdOrderByLastMessageTime(member.getId(), pageable) .map(ChatRoomCreateResDto::fromEntity); } - + private Member getMemberById(Long memberId) { return memberRepository.findById(memberId) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); From 3fa7eba4cd5f30b64598b3c8d1dc0258b4548f87 Mon Sep 17 00:00:00 2001 From: JYP Date: Tue, 3 Dec 2024 16:08:26 +0900 Subject: [PATCH 04/10] =?UTF-8?q?refactor:=20ChatController,ChatService=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?(#103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zero/bwtableback/chat/controller/ChatController.java | 6 +----- .../java/com/zero/bwtableback/chat/service/ChatService.java | 4 ---- .../com/zero/bwtableback/member/service/AuthService.java | 2 +- .../com/zero/bwtableback/member/service/MemberService.java | 2 +- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/zero/bwtableback/chat/controller/ChatController.java b/src/main/java/com/zero/bwtableback/chat/controller/ChatController.java index 7e63bd5c..18fbdf95 100644 --- a/src/main/java/com/zero/bwtableback/chat/controller/ChatController.java +++ b/src/main/java/com/zero/bwtableback/chat/controller/ChatController.java @@ -26,9 +26,7 @@ public class ChatController { private final ChatService chatService; - // 채팅방 생성 엔드포인트는 예약 확정 시 자동으로 생성 - - // FIXME 특정 채팅방 조회 (필요 여부 판단) + // 채팅방 조회 @GetMapping("/{chatRoomId}") public ResponseEntity getChatRoomById(@PathVariable Long chatRoomId) { ChatRoom chatRoom = chatService.getChatRoomById(chatRoomId); @@ -51,8 +49,6 @@ public ResponseEntity> getMessages(@PathVariable Long chatRo /** * 메시지 전송 * - * TODO Redis에 캐싱 및 배치 작업 고려 - * TODO 첫 연결 시 메시지 * 임시로 DB에 저장 */ @MessageMapping("/send/{chatRoomId}") diff --git a/src/main/java/com/zero/bwtableback/chat/service/ChatService.java b/src/main/java/com/zero/bwtableback/chat/service/ChatService.java index b18dedb8..2ece0736 100644 --- a/src/main/java/com/zero/bwtableback/chat/service/ChatService.java +++ b/src/main/java/com/zero/bwtableback/chat/service/ChatService.java @@ -44,12 +44,10 @@ public class ChatService { * @return 예약 정보, 가게 정보 */ public PaymentCompleteResDto createChatRoom(ReservationResDto reservationResDto) { - // 식당 및 예약 정보 조회 Restaurant restaurant = getRestaurant(reservationResDto.restaurantId()); Reservation reservation = getReservation(reservationResDto.reservationId()); Member member = getMember(reservationResDto.memberId()); - // 채팅방 이름 생성 String roomName = generateRoomName(restaurant.getName(), reservationResDto.reservationDate(), reservationResDto.reservationTime()); ChatRoom chatRoom = new ChatRoom(); @@ -65,8 +63,6 @@ public PaymentCompleteResDto createChatRoom(ReservationResDto reservationResDto) return PaymentCompleteResDto.fromEntities(restaurantDetailDto, reservation); } - - // 식당 조회 private Restaurant getRestaurant(Long restaurantId) { return restaurantRepository.findById(restaurantId) diff --git a/src/main/java/com/zero/bwtableback/member/service/AuthService.java b/src/main/java/com/zero/bwtableback/member/service/AuthService.java index c9671754..817163de 100644 --- a/src/main/java/com/zero/bwtableback/member/service/AuthService.java +++ b/src/main/java/com/zero/bwtableback/member/service/AuthService.java @@ -271,7 +271,7 @@ public void withdraw(Long memberId, HttpServletResponse response) { memberRepository.save(member); } - public Member getMemberById(Long memberId) { + private Member getMemberById(Long memberId) { return memberRepository.findById(memberId) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); } diff --git a/src/main/java/com/zero/bwtableback/member/service/MemberService.java b/src/main/java/com/zero/bwtableback/member/service/MemberService.java index deaeff8e..c603cb2f 100644 --- a/src/main/java/com/zero/bwtableback/member/service/MemberService.java +++ b/src/main/java/com/zero/bwtableback/member/service/MemberService.java @@ -78,7 +78,7 @@ public Page getMyChatRooms(Pageable pageable, Long memberI return chatRoomRepository.findChatRoomsByMemberIdOrderByLastMessageTime(member.getId(), pageable) .map(ChatRoomCreateResDto::fromEntity); } - + private Member getMemberById(Long memberId) { return memberRepository.findById(memberId) .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); From ee3d5c42ed6864217fd1158a491f10a428916693 Mon Sep 17 00:00:00 2001 From: JYP Date: Fri, 6 Dec 2024 16:17:05 +0900 Subject: [PATCH 05/10] =?UTF-8?q?refactor:=20ChatController,ChatService=20?= =?UTF-8?q?=EC=A4=91=EB=B3=B5=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?(#103)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bwtableback/chat/entity/ChatRoom.java | 6 ++- .../bwtableback/chat/service/ChatService.java | 52 +++++++++++-------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/zero/bwtableback/chat/entity/ChatRoom.java b/src/main/java/com/zero/bwtableback/chat/entity/ChatRoom.java index 6960dc47..94287f1b 100644 --- a/src/main/java/com/zero/bwtableback/chat/entity/ChatRoom.java +++ b/src/main/java/com/zero/bwtableback/chat/entity/ChatRoom.java @@ -4,14 +4,16 @@ import com.zero.bwtableback.reservation.entity.Reservation; import com.zero.bwtableback.restaurant.entity.Restaurant; import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; +import lombok.*; import java.util.List; @Entity @Getter @Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor @Table(name = "chat_room") public class ChatRoom { diff --git a/src/main/java/com/zero/bwtableback/chat/service/ChatService.java b/src/main/java/com/zero/bwtableback/chat/service/ChatService.java index 2ece0736..0e6b1be8 100644 --- a/src/main/java/com/zero/bwtableback/chat/service/ChatService.java +++ b/src/main/java/com/zero/bwtableback/chat/service/ChatService.java @@ -19,14 +19,15 @@ import com.zero.bwtableback.restaurant.entity.Restaurant; import com.zero.bwtableback.restaurant.repository.RestaurantRepository; import com.zero.bwtableback.restaurant.service.RestaurantService; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + @Service @RequiredArgsConstructor public class ChatService { @@ -50,19 +51,24 @@ public PaymentCompleteResDto createChatRoom(ReservationResDto reservationResDto) String roomName = generateRoomName(restaurant.getName(), reservationResDto.reservationDate(), reservationResDto.reservationTime()); - ChatRoom chatRoom = new ChatRoom(); - chatRoom.setRoomName(roomName); - chatRoom.setStatus(ChatRoomStatus.ACTIVE); - chatRoom.setRestaurant(restaurant); - chatRoom.setReservation(reservation); - chatRoom.setMember(member); - + ChatRoom chatRoom = createChatRoomEntity(roomName, restaurant, reservation, member); chatRoomRepository.save(chatRoom); RestaurantDetailDto restaurantDetailDto = restaurantService.getRestaurantById(restaurant.getId()); return PaymentCompleteResDto.fromEntities(restaurantDetailDto, reservation); } + // 채팅방 객체 생성 + private ChatRoom createChatRoomEntity(String roomName, Restaurant restaurant, Reservation reservation, Member member) { + return ChatRoom.builder() + .roomName(roomName) + .status(ChatRoomStatus.ACTIVE) + .restaurant(restaurant) + .reservation(reservation) + .member(member) + .build(); + } + // 식당 조회 private Restaurant getRestaurant(Long restaurantId) { return restaurantRepository.findById(restaurantId) @@ -92,7 +98,7 @@ private String generateRoomName(String restaurantName, LocalDate reservationDate */ public ChatRoom getChatRoomById(Long chatRoomId) { return chatRoomRepository.findById(chatRoomId) - .orElseThrow(() -> new RuntimeException("채팅방을 찾을 수 없습니다.")); + .orElseThrow(() -> new CustomException(ErrorCode.CHAT_ROOM_NOT_FOUND)); } /** @@ -103,7 +109,6 @@ public void inactivateChatRoom(Long reservationId) { .orElseThrow(() -> new CustomException(ErrorCode.CHAT_ROOM_NOT_FOUND)); chatRoom.setStatus(ChatRoomStatus.INACTIVE); - chatRoomRepository.save(chatRoom); } @@ -111,9 +116,6 @@ public void inactivateChatRoom(Long reservationId) { * 특정 채팅방 전체 메시지 조회 */ public Page getMessages(Long chatRoomId, Pageable pageable) { - chatRoomRepository.findById(chatRoomId) - .orElseThrow(() -> new CustomException(ErrorCode.CHAT_ROOM_NOT_FOUND)); - return messageRepository.findByChatRoomIdOrderByTimestampDesc(chatRoomId, pageable) .map(MessageResDto::fromEntity); } @@ -122,25 +124,31 @@ public Page getMessages(Long chatRoomId, Pageable pageable) { * 특정 채팅방 메시지 전송 */ public MessageResDto saveMessage(Long chatRoomId, String email, MessageReqDto messageReqDto) { - ChatRoom chatRoom = chatRoomRepository.findById(chatRoomId) - .orElseThrow(() -> new CustomException(ErrorCode.CHAT_ROOM_NOT_FOUND)); + ChatRoom chatRoom = getChatRoomById(chatRoomId); Member member = memberRepository.findByEmail(email) .orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND)); - Message message = Message.builder() + Message message = createMessageEntity(chatRoom, member, messageReqDto); + messageRepository.save(message); + + return new MessageResDto(member.getNickname(), messageReqDto.getContent(), messageReqDto.getTimestamp()); + } + + // 메시지 객체 생성 + private Message createMessageEntity(ChatRoom chatRoom, Member member, MessageReqDto messageReqDto) { + return Message.builder() .content(messageReqDto.getContent()) .sender(member) .chatRoom(chatRoom) .restaurant(chatRoom.getRestaurant()) .timestamp(messageReqDto.getTimestamp()) .build(); - - messageRepository.save(message); - - return new MessageResDto(member.getNickname(), messageReqDto.getContent(), messageReqDto.getTimestamp()); } + /** + * 채팅방 활성화 여부 확인 + */ public boolean isChatRoomActive(Long chatRoomId) { ChatRoom chatRoom = getChatRoomById(chatRoomId); return ChatRoomStatus.ACTIVE.equals(chatRoom.getStatus()); From a61824443de582c135b1c361efdd65ca7d4c8502 Mon Sep 17 00:00:00 2001 From: JYP Date: Thu, 12 Dec 2024 14:44:03 +0900 Subject: [PATCH 06/10] RESOLVE CONFLICT --- .../java/com/zero/bwtableback/restaurant/entity/Restaurant.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/zero/bwtableback/restaurant/entity/Restaurant.java b/src/main/java/com/zero/bwtableback/restaurant/entity/Restaurant.java index 8abb1c22..924ce5aa 100644 --- a/src/main/java/com/zero/bwtableback/restaurant/entity/Restaurant.java +++ b/src/main/java/com/zero/bwtableback/restaurant/entity/Restaurant.java @@ -85,7 +85,7 @@ public class Restaurant extends BaseEntity { ) private List hashtags; - @Column(nullable = false) // TODO: 평점 null 허용? + @Column(nullable = false) private double averageRating; // 평균 평점 @OneToOne From 24d877170cb57d831fe38e3e68f9157f95083f90 Mon Sep 17 00:00:00 2001 From: JYP Date: Sun, 15 Dec 2024 20:31:15 +0900 Subject: [PATCH 07/10] CONFLICT RESOLVE --- .../reservation/controller/ReservationController.java | 5 ++--- .../bwtableback/reservation/service/ReservationService.java | 4 +--- .../bwtableback/restaurant/controller/MainController.java | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/zero/bwtableback/reservation/controller/ReservationController.java b/src/main/java/com/zero/bwtableback/reservation/controller/ReservationController.java index a2eebfc0..c4c82a4d 100644 --- a/src/main/java/com/zero/bwtableback/reservation/controller/ReservationController.java +++ b/src/main/java/com/zero/bwtableback/reservation/controller/ReservationController.java @@ -61,8 +61,7 @@ public ReservationResDto getReservationById(@PathVariable Long reservationId) { * 4. 생성된 예약 토큰을 클라이언트에 반환합니다. */ @PostMapping() - public ResponseEntity requestReservation(@RequestBody ReservationCreateReqDto request, - @AuthenticationPrincipal MemberDetails memberDetails) { + public ResponseEntity requestReservation(@RequestBody ReservationCreateReqDto request) { ReservationAvailabilityDto availability = reservationService.checkReservationAvailability(request); if (availability.isAvailable()) { String reservationToken = UUID.randomUUID().toString(); @@ -79,7 +78,7 @@ public ResponseEntity requestReservation(@RequestBody ReservationCreateReqDto * 1. 결제 정보와 함께 요청이 들어오면, 해당 예약 정보를 조회 * 2. 결제가 성공적으로 완료되면, 분산 락을 사용하여 동시성 제어 * 3. 현재 예약된 인원 수를 확인하고, 최대 결제 인원을 초과하지 않는 경우에만 예약을 확정하고 DB에 저장 - * 4. 채팅방을 생성하고 Redis에서 임시 예약 정보를 삭제 + * 4. 채팅방을 생성하고 결제 정보를 저장 * * @return 결제 완료 페이지에 보여질 정보 반환 */ diff --git a/src/main/java/com/zero/bwtableback/reservation/service/ReservationService.java b/src/main/java/com/zero/bwtableback/reservation/service/ReservationService.java index 9dbbdbb2..140110d2 100644 --- a/src/main/java/com/zero/bwtableback/reservation/service/ReservationService.java +++ b/src/main/java/com/zero/bwtableback/reservation/service/ReservationService.java @@ -88,17 +88,15 @@ public ReservationAvailabilityDto checkReservationAvailability(ReservationCreate restaurantRepository.findById(request.restaurantId()) .orElseThrow(() -> new CustomException(ErrorCode.RESTAURANT_NOT_FOUND)); - // 예약 기간 설정 확인 ReservationSetting reservationSetting = findReservationSetting(request); - // 요일 설정 확인 WeekdaySetting weekdaySetting = findWeekdaySetting(reservationSetting, request.reservationDate()); - // 시간대 설정 확인 TimeslotSetting timeslotSetting = findTimeslotSetting(weekdaySetting, request.reservationTime()); String currentCountKey = String.format("reservation:currentCount:%d:%s:%s", request.restaurantId(), request.reservationDate(), request.reservationTime()); + if (integerRedisTemplate.opsForValue().get(currentCountKey) == null) { integerRedisTemplate.opsForValue().set(currentCountKey, timeslotSetting.getMaxCapacity()); } diff --git a/src/main/java/com/zero/bwtableback/restaurant/controller/MainController.java b/src/main/java/com/zero/bwtableback/restaurant/controller/MainController.java index 242f89cd..d9f803fb 100644 --- a/src/main/java/com/zero/bwtableback/restaurant/controller/MainController.java +++ b/src/main/java/com/zero/bwtableback/restaurant/controller/MainController.java @@ -119,7 +119,7 @@ public ResponseEntity> getRestaurantsByRegion(@RequestPa @GetMapping public ResponseEntity>> getMainPageData( Pageable pageable, Member member) { - + System.out.println("TEST"); Map> mainPageData = mainService.getMainPageData(pageable, member); From bcbb77bd22a57486aac96515b0e203c4311d70b7 Mon Sep 17 00:00:00 2001 From: JYP Date: Wed, 18 Dec 2024 12:57:07 +0900 Subject: [PATCH 08/10] fix: CONFLICT RESOLVE --- .../zero/bwtableback/member/servcie/MemberServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/zero/bwtableback/member/servcie/MemberServiceTest.java b/src/test/java/com/zero/bwtableback/member/servcie/MemberServiceTest.java index 30376b85..82c50a48 100644 --- a/src/test/java/com/zero/bwtableback/member/servcie/MemberServiceTest.java +++ b/src/test/java/com/zero/bwtableback/member/servcie/MemberServiceTest.java @@ -99,7 +99,7 @@ void testGetMemberById_Success() { when(memberRepository.findById(1L)).thenReturn(Optional.of(member)); // when - MemberDto result = memberService.getMember(1L); + MemberDto result = memberService.getMemberInfo(1L); System.out.println(result.getName()); // then @@ -115,7 +115,7 @@ public void testGetMemberById_UserNotFound() { // when & then CustomException exception = assertThrows(CustomException.class, () -> { - memberService.getMember(1L); + memberService.getMemberInfo(1L); }); assertEquals(ErrorCode.USER_NOT_FOUND, exception.getErrorCode()); } From 0ae3aea05e31db47d041bb2505ac35bfd5709523 Mon Sep 17 00:00:00 2001 From: JYP Date: Thu, 19 Dec 2024 21:44:56 +0900 Subject: [PATCH 09/10] =?UTF-8?q?hotfix:=20=ED=9A=8C=EC=9B=90=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A4=91=EB=B3=B5=20=EA=B2=80=EC=82=AC=20=EC=8B=9C?= =?UTF-8?q?=20=EC=97=AD=EC=A7=81=EB=A0=AC=ED=99=94=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/zero/bwtableback/member/dto/DuplicateCheckReqDto.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/zero/bwtableback/member/dto/DuplicateCheckReqDto.java b/src/main/java/com/zero/bwtableback/member/dto/DuplicateCheckReqDto.java index 0d8ef78f..ee8a0482 100644 --- a/src/main/java/com/zero/bwtableback/member/dto/DuplicateCheckReqDto.java +++ b/src/main/java/com/zero/bwtableback/member/dto/DuplicateCheckReqDto.java @@ -1,10 +1,14 @@ package com.zero.bwtableback.member.dto; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @Builder +@NoArgsConstructor +@AllArgsConstructor public class DuplicateCheckReqDto { private String email; private String nickname; From 43ba19a55c1cf0ad19386bf43508e4a779603944 Mon Sep 17 00:00:00 2001 From: JYP Date: Sun, 22 Dec 2024 23:02:27 +0900 Subject: [PATCH 10/10] fix: RESOLVE CONFLICT --- README.md | 151 ++++++++++++++++++++++++++--- src/main/resources/application.yml | 1 + 2 files changed, 140 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 4e73a72e..9e16f323 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,152 @@ # bw-table-back + ## 개요 -식당 테이블 예약 서비스 +- 프로젝트 명: 흑백테이블 +- 프로젝트 기간 : 2024.10.18 ~ 2024.11.28 (6주) +- 깃허브 주소 : https://github.com/bw-table +- 노션 + 팀링크 : [흑백테이블](https://www.notion.so/123e2b4a200680e5ac90daeffb97d8b8?pvs=21) + +## 팀원 + +| **오신웅** | **이솔** | **박준엽** | **차진아** | **지승연** | +|----------|----------|---------|---------|---------| +| 프론트엔드 팀장 | 팀원 | 백엔드 팀장 | 팀원 | 팀원 | +| Frontend | Frontend | Backend | Backend | Backend | + +### 백엔드 업무 담당 + +| **박준엽** | **차진아** | **지승연** | +|------------------------------------|----------|---------| +| - 회원
-예약
CI/CD 및 배포 환경 구성 | 알림
통계 | 식당 CRUD | + +## 📌 프로젝트 소개 + +### 기획 배경 + +--- + +현대의 외식 환경에서는 고객과 식당 간의 원활한 소통과 신뢰를 바탕으로 한 효율적인 예약 관리가 필수적입니다. +고객은 실시간으로 예약 현황을 확인하고, 맞춤형 서비스를 통해 자신에게 적합한 식당을 쉽게 탐색하기를 원합니다. +사장님들에게는 손쉬운 예약 상태 관리와 더불어 실시간으로 고객 요청을 처리하며 더 나은 서비스를 제공할 수 있는 시스템이 필요합니다. +이러한 요구를 충족하기 위해 흑백테이블 프로젝트를 기획했습니다. -## 회원 -### 공통 -- [ ] 소셜 로그인 및 인증 -### 손님 +### 해결 컨셉 + +--- + +- **실시간 예약 시스템** + - 실시간 예약 현황 확인 + - 방문 여부 및 노쇼 관리 +- **맞춤형 식당 탐색** + - 업종, 메뉴, 해시태그 기반 검색 + - 최근 예약 내역 기반 식당 추천 +- **신뢰할 수 있는 리뷰 시스템** + - 실제 방문 고객의 검증된 후기 +- **원활한 실시간 소통** + - 예약부터 방문까지 1:1 실시간 채팅 + - 특별 요청사항 전달 용이 +- **순차적인 예약 처리** + - 동시성을 제어하여 안전하고 순차적인 예약 처리 + +## 📌 주요 기능 요약 ### 사장님 -## 가게 +**스마트 예약 관리** + +- 실시간 예약 현황 확인 +- 방문 여부 및 노쇼 직접 관리 +- 세부적인 예약 슬롯 설정 및 관리 +- 최근 예약 내역 기반 통계 차트 확인 + +**효율적인 고객 소통** + +- 예약 고객과의 1:1 실시간 채팅 +- 특별 요청사항 확인 및 대응 + +**식당 정보 관리** + +- 프로모션 정보 업데이트 +- 식당을 잘 나타낼 수 있도록 직접 작성한 + 해시태그로 맞춤형 홍보 + +**간편한 예약 처리** + +- 예약과 동시에 이루어지는 예약금 결제 + +### 손님 + +**편리한 예약 시스템** + +- 실시간 예약 가능 시간 확인 +- 순차적인 예약 기회 + +**맞춤형 식당 탐색** + +- 가게이름, 해시태그, 업종, 메뉴로 검색해 맞춤 정보 탐색 +- 업데이트되는 프로모션 정보 확인 + +**신뢰할 수 있는 리뷰 시스템** + +- 실제 방문 고객의 검증된 후기 확인 +- 방문일 3일내에 작성, 작성일 3일 이내에만 수정할 수 있도록 하여 신뢰성 보장 + +**원활한 소통 채널** + +- 예약부터 방문까지 식당과 1:1 실시간 채팅 +- 알러지 정보나 특별 요청사항 쉽게 전달 + +**개인화된 서비스** + +- 과거 예약 및 방문 이력 관리 +- 최근 예약 내역을 기반으로 추천 식당 확인 +- 현재 위치 기반으로 추천 식당 확인 + +## 📌 기술 스택 + +### Frontend + +- Next.js 15 +- tailwindCSS +- zustand +- reat-query +- React-Hook-Form +- storybook +- sockJS +- stomp +- daisyUI +- react-icon +- github action + +### Backend + +- Language : Java 17 +- Framework : Spring Boot +- Build Tool : Gradle +- DB : MySQL , Redis +- Test : JUnit, Postman +- CI/CD: Docker, DockerHub, Github Action +- Auth : JWT, OAuth 2.0 +- JPA +- AWS EC2 +- AWS S3 +- WebSocket +- STOMP +- SSE +- Spring Security +- Spring Batch +- Spring Scheduler -## 예약 +## 프로젝트 구조 -## 해시태그 +--- -## 채팅 +![CleanShot 2024-11-27 at 23.09.22.png](https://prod-files-secure.s3.us-west-2.amazonaws.com/23988a35-eeeb-4174-b959-70dc0574a0cb/39be4891-affd-45d8-aba4-1062ca7f5abd/CleanShot_2024-11-27_at_23.09.22.png) -## 공지 +## ERD -## 알림 +## 개선할 점 -## 통계 +--- \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 205e8be5..88ec86b8 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,6 +2,7 @@ spring: activate: on-profile: prod multipart: + enabled: true max-file-size: 5MB max-request-size: 10MB iamport: