diff --git a/common/src/main/java/entity/User.java b/common/src/main/java/entity/User.java index 4dbdfd3..4197cbd 100644 --- a/common/src/main/java/entity/User.java +++ b/common/src/main/java/entity/User.java @@ -32,7 +32,7 @@ public class User { private String nickname; @Column(nullable = true) - private String location = "창천동"; + private String location = "서울특별시 서대문구 창천동"; @Column(nullable = true) private double latitude = 37.55348; diff --git a/producer/src/main/java/server/producer/common/dto/enums/ErrorCode.java b/producer/src/main/java/server/producer/common/dto/enums/ErrorCode.java index 6ec8a86..4fce8b0 100644 --- a/producer/src/main/java/server/producer/common/dto/enums/ErrorCode.java +++ b/producer/src/main/java/server/producer/common/dto/enums/ErrorCode.java @@ -27,6 +27,7 @@ public enum ErrorCode { NOT_FOUND_HOUSE(40401, "존재하지 않는 매물 ID 입니다."), HOUSE_NOT_FOUND(40402, "존재하지 않는 매물입니다."), ROOM_NOT_FOUND(40403, "존재하지 않는 방입니다."), + USER_NOT_FOUND(40404, "존재하지 않는 유저입니다."), //405 Method Not Allowed METHOD_NOT_ALLOWED(40500, "해당 요청은 지원되지 않습니다."), diff --git a/producer/src/main/java/server/producer/domain/controller/UserController.java b/producer/src/main/java/server/producer/domain/controller/UserController.java index 16ad848..486cf97 100644 --- a/producer/src/main/java/server/producer/domain/controller/UserController.java +++ b/producer/src/main/java/server/producer/domain/controller/UserController.java @@ -12,6 +12,7 @@ import server.producer.domain.dto.response.*; import server.producer.domain.service.UserService; import server.producer.security.jwt.JwtTokenProvider; +import server.producer.security.jwt.RefreshTokenRepository; import java.security.InvalidParameterException; @@ -20,6 +21,8 @@ @RequiredArgsConstructor public class UserController { private final UserService userService; + private final JwtTokenProvider jwtTokenProvider; + private final RefreshTokenRepository refreshTokenRepository; @GetMapping("/home") public ApiResponseDto getUserHomeInfo(HttpServletRequest request) { @@ -27,6 +30,8 @@ public ApiResponseDto getUserHomeInfo(HttpServletRequest re Long userId = SecurityUtil.getCurrentUserId(); HomeInfoResponseDto userHomeInfo = userService.getUserInfoAndRecentlyViewedHouse(userId); return ApiResponseDto.success(SuccessCode.MAIN_PAGE_GET_SUCCESS, userHomeInfo); + } catch (EntityNotFoundException e) { + return ApiResponseDto.fail(ErrorCode.USER_NOT_FOUND); } catch (InvalidParameterException e) { return ApiResponseDto.fail(ErrorCode.INVALID_PARAMETER); // userId가 유효하지 않은 경우 } catch (Exception e) { @@ -131,10 +136,30 @@ public ApiResponseDto updateGender(@RequestBody GenderU } @DeleteMapping("/delete") - public ApiResponseDto deleteUser() { + public ApiResponseDto deleteUser(@RequestHeader("Authorization") String refreshTokenHeader) { try { - Long userId = SecurityUtil.getCurrentUserId(); + if (refreshTokenHeader == null || !refreshTokenHeader.startsWith("Bearer ")) { + return ApiResponseDto.fail(ErrorCode.MISSING_REQUIRED_HEADER); + } + String refreshToken = refreshTokenHeader.substring(7); + + // 1. 토큰 유효성 검사 + if (!jwtTokenProvider.validateToken(refreshToken)) { + return ApiResponseDto.fail(ErrorCode.INVALID_REFRESH_TOKEN); + } + + // 2. 토큰 저장소에서 userId 조회 + Long userId = refreshTokenRepository.findUserIdByToken(refreshToken).orElse(null); + if (userId == null) { + return ApiResponseDto.fail(ErrorCode.INVALID_REFRESH_TOKEN); + } + + // 3. 토큰 삭제 + refreshTokenRepository.deleteByToken(refreshToken); + + // 4. 유저 삭제 userService.deleteUser(userId); + return ApiResponseDto.success(SuccessCode.USER_DELETE_SUCCESS, null); } catch (EntityNotFoundException e) { return ApiResponseDto.fail(ErrorCode.INVALID_PARAMETER); diff --git a/producer/src/main/java/server/producer/domain/service/SocialLoginService.java b/producer/src/main/java/server/producer/domain/service/SocialLoginService.java index e5e3940..c3b4e61 100644 --- a/producer/src/main/java/server/producer/domain/service/SocialLoginService.java +++ b/producer/src/main/java/server/producer/domain/service/SocialLoginService.java @@ -32,6 +32,7 @@ public SocialLoginResponseDto loginOrSignup(String provider, String accessToken) .socialType(userInfo.getProvider()) .email(userInfo.getEmail()) .nickname(userInfo.getNickname()) + .location("서울특별시 서대문구 창천동") .build(); return userRepository.save(created); }); diff --git a/producer/src/main/java/server/producer/domain/service/UserService.java b/producer/src/main/java/server/producer/domain/service/UserService.java index 9bb4af1..21e4bea 100644 --- a/producer/src/main/java/server/producer/domain/service/UserService.java +++ b/producer/src/main/java/server/producer/domain/service/UserService.java @@ -3,6 +3,8 @@ import entity.*; import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,6 +24,7 @@ import java.util.stream.Collectors; @Service +@Slf4j @RequiredArgsConstructor public class UserService { @@ -44,22 +47,31 @@ public HomeInfoResponseDto getUserInfoAndRecentlyViewedHouse(Long userId) { for (RecentlyViewedHouse rvh : houses) { House house = rvh.getHouse(); - final boolean isPinned = house.getPins().stream() - .anyMatch(pin -> pin.getUser().getId().equals(userId)); - HomeInfoResponseDto.RecentlyViewedHouseDto dto = new HomeInfoResponseDto.RecentlyViewedHouseDto( - house.getId(), - house.calculateMonthlyRent(), - house.calculateDeposit(), - house.calculateOccupancyType(), - house.getLocation(), - house.getGenderPolicy().toString(), - house.getLocationDescription(), - isPinned, - house.getMoodTag(), - house.getContractTerm(), - house.getMainImgUrl() - ); - recentlyViewedHouseDtos.add(dto); + if (house == null) { + log.warn("RecentlyViewedHouse 변환 중 예외 발생: {}", "house is null"); + continue; + } + try { + final boolean isPinned = house.getPins() != null && house.getPins().stream() + .anyMatch(pin -> pin.getUser() != null && pin.getUser().getId().equals(userId)); + HomeInfoResponseDto.RecentlyViewedHouseDto dto = new HomeInfoResponseDto.RecentlyViewedHouseDto( + house.getId(), + house.calculateMonthlyRent(), + house.calculateDeposit(), + house.calculateOccupancyType(), + house.getLocation(), + house.getGenderPolicy() != null ? house.getGenderPolicy().toString() : null, + house.getLocationDescription(), + isPinned, + house.getMoodTag(), + house.getContractTerm(), + house.getMainImgUrl() + ); + recentlyViewedHouseDtos.add(dto); + } catch (Exception e) { + log.warn("RecentlyViewedHouse 변환 중 예외 발생: {}", e.getMessage()); + continue; + } } return new HomeInfoResponseDto(nickname, location, recentlyViewedHouseDtos); } diff --git a/producer/src/main/java/server/producer/security/jwt/JwtTokenProvider.java b/producer/src/main/java/server/producer/security/jwt/JwtTokenProvider.java index ec5b55b..e9eb1d9 100644 --- a/producer/src/main/java/server/producer/security/jwt/JwtTokenProvider.java +++ b/producer/src/main/java/server/producer/security/jwt/JwtTokenProvider.java @@ -41,7 +41,17 @@ public Long getUserId(String token) { .parseClaimsJws(token) .getBody(); - return claims.get("userId", Long.class); + Object userId = claims.get("userId"); + if (userId instanceof Integer) { + return ((Integer) userId).longValue(); + } + if (userId instanceof Long) { + return (Long) userId; + } + if (userId instanceof String) { + return Long.parseLong((String) userId); + } + throw new RuntimeException("userId 타입이 올바르지 않습니다: " + userId.getClass()); } private String createToken(User user, long validity) {