From 4288267fef7ca8010a96df84b88bc971b8f6e700 Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Mon, 30 Jun 2025 06:34:43 +0900 Subject: [PATCH 01/11] =?UTF-8?q?chore:=20=ED=8F=89=EB=AC=B8=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=A0=84=EC=86=A1=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai_model/schedular/ModelSchedular.java | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/schedular/ModelSchedular.java b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/schedular/ModelSchedular.java index 30c93d6..896be44 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/schedular/ModelSchedular.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/schedular/ModelSchedular.java @@ -40,51 +40,6 @@ public class ModelSchedular { @Value("${ai.server.url}") private String aiServerUrl; - /** - * 매일 새벽 5시에 모델 서버로 예측에 필요한 데이터를 평문 형태로 전송합니다. - */ -// @Transactional -// @Scheduled(cron = "0 0 5 * * *") -// public void pushPredictionDataToAiServer() { -// try { -// List members = memberRepository.findAllByIsDeletedFalse(); -// -// List allDtos = members.stream() -// .filter(member -> member.getCloset() != null) -// .map(member -> { -// try { -// return aiInternalService.makePredictRequest(member); -// } catch (Exception e) { -// log.error("멤버 {} 예측 데이터 생성 실패: {}", member.getId(), e.getMessage()); -// return null; -// } -// }) -// .filter(Objects::nonNull) -// .collect(Collectors.toList()); -// -// if (allDtos.isEmpty()) { -// log.info("AI 서버로 전송할 데이터가 없습니다."); -// return; -// } -// -// HttpHeaders headers = new HttpHeaders(); -// headers.setContentType(MediaType.APPLICATION_JSON); -// -// HttpEntity> requestEntity = new HttpEntity<>(allDtos, headers); -// ResponseEntity response = restTemplate.postForEntity(aiServerUrl, requestEntity, String.class); -// -// if (response.getStatusCode().is2xxSuccessful()) { -// log.info("AI 서버에 예측 데이터 전송 완료. 응답: {}", response.getStatusCode()); -// } else { -// log.warn("AI 서버 응답 실패. 상태코드: {}, 응답본문: {}", response.getStatusCode(), response.getBody()); -// } -// -// } catch (Exception e) { -// log.error("AI 서버 전송 실패", e); -// } -// } - - /** * 매일 새벽 5시에 모델 서버로 예측에 필요한 데이터를 암호화된 형태로 전송합니다. */ From d42276665bc889eb4fa927bffcc77e26b5147a89 Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Mon, 30 Jun 2025 06:35:04 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20=EB=A0=88=EC=9D=B4=EC=96=B4?= =?UTF-8?q?=EB=93=9C=20=EA=B0=80=EB=8A=A5=ED=95=9C=20=EC=9D=98=EC=83=81=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=EB=A1=9C=EC=A7=81=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/closet/service/ClosetService.java | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClosetService.java b/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClosetService.java index 880fa9f..341836c 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClosetService.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClosetService.java @@ -219,34 +219,6 @@ public ClothListDto getOuters(Member member) { } } - @Transactional(readOnly = true) - public ClothListDto findLayerFlexibleOuters(Member member) { // 상의가 될 수 있는 아우터 - Closet closet = getCloset(member); - - return findLayerFlexibleClothes( - OUTER, - closet.getOuterList(), - layerFlexibleOuter, - Outer::isActive, - Outer::getOuterType, - this::mapOuterToDto - ); - } - - @Transactional(readOnly = true) - public ClothListDto findLayerFlexibleUppers(Member member) { // 아우터가 될 수 있는 상의 - Closet closet = getCloset(member); - - return findLayerFlexibleClothes( - UPPER, - closet.getUpperList(), - layerFlexibleUpper, - Upper::isActive, - Upper::getUpperType, - this::mapUpperToDto - ); - } - @Transactional public void updateUpper(Long clothId, UpdateClothDto updateDto, Member member) { try { From 8419d55834ab753fd0814614ee2ca29b14dc0f15 Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 18:20:08 +0900 Subject: [PATCH 03/11] =?UTF-8?q?refactor:=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - auth 관련 메소드를 두는 서비스 클래스에 account 관련 메소도가 포함되어있었는데, 분리함. --- .../member/api/MyAccountController.java | 15 ++- .../domain/member/service/AuthService.java | 94 --------------- .../member/service/MyAccountService.java | 114 ++++++++++++++++++ 3 files changed, 121 insertions(+), 102 deletions(-) create mode 100644 src/main/java/com/howWeather/howWeather_backend/domain/member/service/MyAccountService.java diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/member/api/MyAccountController.java b/src/main/java/com/howWeather/howWeather_backend/domain/member/api/MyAccountController.java index 12ae721..ad1bc55 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/member/api/MyAccountController.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/member/api/MyAccountController.java @@ -4,8 +4,7 @@ import com.howWeather.howWeather_backend.domain.member.dto.ProfileChangeIntDto; import com.howWeather.howWeather_backend.domain.member.dto.ProfileDto; import com.howWeather.howWeather_backend.domain.member.entity.Member; -import com.howWeather.howWeather_backend.domain.member.repository.MemberRepository; -import com.howWeather.howWeather_backend.domain.member.service.AuthService; +import com.howWeather.howWeather_backend.domain.member.service.MyAccountService; import com.howWeather.howWeather_backend.global.Response.ApiResponse; import com.howWeather.howWeather_backend.global.jwt.CheckAuthenticatedUser; import lombok.RequiredArgsConstructor; @@ -22,13 +21,13 @@ @RequiredArgsConstructor @RequestMapping("/api/mypage") public class MyAccountController { - private final AuthService authService; + private final MyAccountService myAccountService; @GetMapping("/profile") @CheckAuthenticatedUser public ResponseEntity getProfile(@RequestHeader("Authorization") String accessTokenHeader, @AuthenticationPrincipal Member member) { - ProfileDto profile = authService.getProfile(member); + ProfileDto profile = myAccountService.getProfile(member); return ResponseEntity.ok(profile); } @@ -37,7 +36,7 @@ public ResponseEntity getProfile(@RequestHeader("Authorization") Str public ResponseEntity> updateGender(@RequestHeader("Authorization") String accessTokenHeader, @RequestBody ProfileChangeIntDto profileChangeDto, @AuthenticationPrincipal Member member) { - authService.updateGender(member, profileChangeDto); + myAccountService.updateGender(member, profileChangeDto); return ApiResponse.success(HttpStatus.OK, "성별을 성공적으로 수정하였습니다."); } @@ -46,7 +45,7 @@ public ResponseEntity> updateGender(@RequestHeader("Authoriz public ResponseEntity> updateAgeGroup(@RequestHeader("Authorization") String accessTokenHeader, @RequestBody ProfileChangeIntDto profileChangeDto, @AuthenticationPrincipal Member member) { - authService.updateAgeGroup(member, profileChangeDto); + myAccountService.updateAgeGroup(member, profileChangeDto); return ApiResponse.success(HttpStatus.OK, "연령대를 성공적으로 수정하였습니다."); } @@ -55,7 +54,7 @@ public ResponseEntity> updateAgeGroup(@RequestHeader("Author public ResponseEntity> updateNickname(@RequestHeader("Authorization") String accessTokenHeader, @Valid @RequestBody NicknameDto nicknameDto, @AuthenticationPrincipal Member member) { - authService.updateNickname(member,nicknameDto); + myAccountService.updateNickname(member,nicknameDto); return ApiResponse.success(HttpStatus.OK, "닉네임을 성공적으로 수정하였습니다."); } @@ -64,7 +63,7 @@ public ResponseEntity> updateNickname(@RequestHeader("Author public ResponseEntity> updateConstitution(@RequestHeader("Authorization") String accessTokenHeader, @Valid @RequestBody ProfileChangeIntDto profileChangeDto, @AuthenticationPrincipal Member member) { - authService.updateConstitution(member, profileChangeDto); + myAccountService.updateConstitution(member, profileChangeDto); return ApiResponse.success(HttpStatus.OK, "체질을 성공적으로 수정하였습니다."); } } diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/member/service/AuthService.java b/src/main/java/com/howWeather/howWeather_backend/domain/member/service/AuthService.java index 3291b08..cf09836 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/member/service/AuthService.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/member/service/AuthService.java @@ -165,27 +165,6 @@ private void blacklistToken(String token, String tokenType) { } } - @Transactional(readOnly = true) - public ProfileDto getProfile(Member member) { - try { - return ProfileDto.builder() - .loginId(member.getLoginId()) - .email(member.getEmail()) - .ageGroup(member.getAgeGroup()) - .nickname(member.getNickname()) - .bodyType(member.getBodyType()) - .constitution(member.getConstitution()) - .gender(member.getGender()) - .build(); - - } catch (CustomException e) { - throw e; - } catch (Exception e) { - log.error("프로필 조회 중 에러 발생: {}", e.getMessage(), e); - throw new CustomException(ErrorCode.UNKNOWN_ERROR, "프로필 조회 중 오류가 발생했습니다."); - } - } - @Transactional public void changePasswordAndLogout(Member member, PasswordChangeDto dto, String accessToken, String refreshToken) { changePassword(member, dto); @@ -232,79 +211,6 @@ private void validateOldPassword(Member member, String oldPassword) { } } - @Transactional - public void updateGender(Member member, ProfileChangeIntDto profileChangeDto) { - try { - validateIntData(profileChangeDto.getData(), 1, 2); - if (profileChangeDto.getData() != null) { - Member persistedMember = memberRepository.findById(member.getId()) - .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); - persistedMember.changeGender(profileChangeDto.getData()); - } - } catch (CustomException e) { - throw e; - } catch (Exception e) { - log.error("성별 수정 중 에러 발생: {}", e.getMessage(), e); - throw new CustomException(ErrorCode.UNKNOWN_ERROR, "성별 수정 중 오류가 발생했습니다."); - } - } - - @Transactional - public void updateAgeGroup(Member member, ProfileChangeIntDto profileChangeDto) { - try { - validateIntData(profileChangeDto.getData(), 1, 3); - if (profileChangeDto.getData() != null) { - Member persistedMember = memberRepository.findById(member.getId()) - .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); - persistedMember.changeAgeGroup(profileChangeDto.getData()); - } - } catch (CustomException e) { - throw e; - } catch (Exception e) { - log.error("연령대 수정 중 에러 발생: {}", e.getMessage(), e); - throw new CustomException(ErrorCode.UNKNOWN_ERROR, "연령대 수정 중 오류가 발생했습니다."); - } - } - - @Transactional - public void updateNickname(Member member, NicknameDto nicknameDto) { - try { - if (nicknameDto.getData() != null) { - Member persistedMember = memberRepository.findById(member.getId()) - .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); - persistedMember.changeNickname(nicknameDto.getData()); - } - } catch (CustomException e) { - throw e; - } catch (Exception e) { - log.error("닉네임 수정 중 에러 발생: {}", e.getMessage(), e); - throw new CustomException(ErrorCode.UNKNOWN_ERROR, "닉네임 수정 중 오류가 발생했습니다."); - } - } - - @Transactional - public void updateConstitution(Member member, ProfileChangeIntDto profileChangeDto) { - try { - validateIntData(profileChangeDto.getData(), 1, 3); - if (profileChangeDto.getData() != null) { - Member persistedMember = memberRepository.findById(member.getId()) - .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); - persistedMember.changeConstitution(profileChangeDto.getData()); - } - } catch (CustomException e) { - throw e; - } catch (Exception e) { - log.error("체질 수정 중 에러 발생: {}", e.getMessage(), e); - throw new CustomException(ErrorCode.UNKNOWN_ERROR, "체질 수정 중 오류가 발생했습니다."); - } - } - - private void validateIntData(Integer data, int s, int e) { - if (data < s || data > e) { - throw new CustomException(ErrorCode.INVALID_INPUT, "유효하지 않은 입력값입니다."); - } - } - @Transactional public void withdraw(Member member, String jwtAccessToken, String refreshToken, String socialAccessToken) { try { diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/member/service/MyAccountService.java b/src/main/java/com/howWeather/howWeather_backend/domain/member/service/MyAccountService.java new file mode 100644 index 0000000..f427047 --- /dev/null +++ b/src/main/java/com/howWeather/howWeather_backend/domain/member/service/MyAccountService.java @@ -0,0 +1,114 @@ +package com.howWeather.howWeather_backend.domain.member.service; + +import com.howWeather.howWeather_backend.domain.member.dto.NicknameDto; +import com.howWeather.howWeather_backend.domain.member.dto.ProfileChangeIntDto; +import com.howWeather.howWeather_backend.domain.member.dto.ProfileDto; +import com.howWeather.howWeather_backend.domain.member.entity.Member; +import com.howWeather.howWeather_backend.domain.member.repository.MemberRepository; +import com.howWeather.howWeather_backend.global.exception.CustomException; +import com.howWeather.howWeather_backend.global.exception.ErrorCode; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MyAccountService { + private final MemberRepository memberRepository; + + @Transactional(readOnly = true) + public ProfileDto getProfile(Member member) { + try { + return ProfileDto.builder() + .loginId(member.getLoginId()) + .email(member.getEmail()) + .ageGroup(member.getAgeGroup()) + .nickname(member.getNickname()) + .bodyType(member.getBodyType()) + .constitution(member.getConstitution()) + .gender(member.getGender()) + .build(); + + } catch (CustomException e) { + throw e; + } catch (Exception e) { + log.error("프로필 조회 중 에러 발생: {}", e.getMessage(), e); + throw new CustomException(ErrorCode.UNKNOWN_ERROR, "프로필 조회 중 오류가 발생했습니다."); + } + } + + @Transactional + public void updateGender(Member member, ProfileChangeIntDto profileChangeDto) { + try { + validateIntData(profileChangeDto.getData(), 1, 2); + if (profileChangeDto.getData() != null) { + Member persistedMember = memberRepository.findById(member.getId()) + .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); + persistedMember.changeGender(profileChangeDto.getData()); + } + } catch (CustomException e) { + throw e; + } catch (Exception e) { + log.error("성별 수정 중 에러 발생: {}", e.getMessage(), e); + throw new CustomException(ErrorCode.UNKNOWN_ERROR, "성별 수정 중 오류가 발생했습니다."); + } + } + + @Transactional + public void updateAgeGroup(Member member, ProfileChangeIntDto profileChangeDto) { + try { + validateIntData(profileChangeDto.getData(), 1, 3); + if (profileChangeDto.getData() != null) { + Member persistedMember = memberRepository.findById(member.getId()) + .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); + persistedMember.changeAgeGroup(profileChangeDto.getData()); + } + } catch (CustomException e) { + throw e; + } catch (Exception e) { + log.error("연령대 수정 중 에러 발생: {}", e.getMessage(), e); + throw new CustomException(ErrorCode.UNKNOWN_ERROR, "연령대 수정 중 오류가 발생했습니다."); + } + } + + @Transactional + public void updateNickname(Member member, NicknameDto nicknameDto) { + try { + if (nicknameDto.getData() != null) { + Member persistedMember = memberRepository.findById(member.getId()) + .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); + persistedMember.changeNickname(nicknameDto.getData()); + } + } catch (CustomException e) { + throw e; + } catch (Exception e) { + log.error("닉네임 수정 중 에러 발생: {}", e.getMessage(), e); + throw new CustomException(ErrorCode.UNKNOWN_ERROR, "닉네임 수정 중 오류가 발생했습니다."); + } + } + + @Transactional + public void updateConstitution(Member member, ProfileChangeIntDto profileChangeDto) { + try { + validateIntData(profileChangeDto.getData(), 1, 3); + if (profileChangeDto.getData() != null) { + Member persistedMember = memberRepository.findById(member.getId()) + .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); + persistedMember.changeConstitution(profileChangeDto.getData()); + } + } catch (CustomException e) { + throw e; + } catch (Exception e) { + log.error("체질 수정 중 에러 발생: {}", e.getMessage(), e); + throw new CustomException(ErrorCode.UNKNOWN_ERROR, "체질 수정 중 오류가 발생했습니다."); + } + } + + private void validateIntData(Integer data, int start, int end) { + if (data < start || data > end) { + throw new CustomException(ErrorCode.INVALID_INPUT, "유효하지 않은 입력값입니다."); + } + } +} From e9d490235970efbcabde69a4c0dec7f987fb37fe Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 18:23:58 +0900 Subject: [PATCH 04/11] =?UTF-8?q?chore:=20=EC=82=AC=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20API=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai_model/api/AiInternalController.java | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/api/AiInternalController.java b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/api/AiInternalController.java index ca9a03e..45579ee 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/api/AiInternalController.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/api/AiInternalController.java @@ -62,7 +62,6 @@ public ResponseEntity> sendAllUsersPredictionDataSecure() { public ResponseEntity> saveRecommendations(@RequestBody Map encryptedBody) { try { String decryptedJson = aesCipher.decrypt(encryptedBody); - log.info("🔓 복호화된 데이터:\n{}", decryptedJson); if (decryptedJson.startsWith("\"") && decryptedJson.endsWith("\"")) { decryptedJson = objectMapper.readValue(decryptedJson, String.class); @@ -76,7 +75,6 @@ public ResponseEntity> saveRecommendations(@RequestBody Map< recommendationService.save(dto); return ApiResponse.success(HttpStatus.OK, "예측 결과를 성공적으로 저장했습니다."); } catch (CustomException e) { - log.error("커스텀 예외 발생: {}", e.getMessage(), e); return ResponseEntity .status(e.getHttpStatus()) .body(ApiResponse.fail(e)); @@ -116,36 +114,4 @@ private Map encryptPredictionData(List d return null; } } - - // TODO : 암/복호화 API 연결 이후 아래 코드 삭제 - - @PostMapping("/prediction") - public ResponseEntity> sendAllUsersPredictionData() { - try { - List members = memberRepository.findAllByIsDeletedFalse(); - - List allDtos = members.stream() - .filter(member -> member.getCloset() != null) - .map(aiInternalService::makePredictRequest) - .collect(Collectors.toList()); - - return ResponseEntity.ok(allDtos); - } catch (Exception e) { - log.error(e.getMessage()); - } - return null; - } - - @PostMapping("/recommendation") - public ResponseEntity> saveRecommendations(@RequestBody ModelClothingRecommendationDto dto) { - recommendationService.save(dto); - return ApiResponse.success(HttpStatus.OK, "예측 결과를 성공적으로 저장했습니다."); - } - - @PostMapping("/history") - public ResponseEntity>> getSimilarHistory(@RequestBody HistoryRequestDto dto) { - dto.validate(); - List result = recordCalendarService.getMemberHistory(dto); - return ApiResponse.success(HttpStatus.OK, result); - } } From 1e9dd685f0df58273c226f3467e1f600d228efcc Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 18:28:40 +0900 Subject: [PATCH 05/11] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A3=BC=EC=84=9D=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=20=EC=B6=9C=EB=A0=A5=EB=AC=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/ai_model/schedular/ModelSchedular.java | 10 +--------- .../ai_model/service/RecommendationService.java | 11 ++--------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/schedular/ModelSchedular.java b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/schedular/ModelSchedular.java index 896be44..49db6f8 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/schedular/ModelSchedular.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/schedular/ModelSchedular.java @@ -67,15 +67,7 @@ public void pushPredictionAESDataToAiServer() { return; } - ObjectMapper objectMapper = new ObjectMapper(); - String plainJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(allDtos); - log.info("✅ 예측 데이터 (평문 JSON):\n{}", plainJson); - Map encrypted = encryptPredictionData(allDtos); - - String encryptedJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(encrypted); - log.info("🔒 예측 데이터 (암호화된 JSON):\n{}", encryptedJson); - HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity> requestEntity = new HttpEntity<>(encrypted, headers); @@ -94,7 +86,7 @@ public void pushPredictionAESDataToAiServer() { private Map encryptPredictionData(List dtos) { try { String jsonData = objectMapper.writeValueAsString(dtos); - return aesCipher.encrypt(jsonData); // { "iv": "...", "payload": "..." } + return aesCipher.encrypt(jsonData); } catch (Exception e) { log.error("예측 데이터 암호화 실패: {}", e.getMessage()); return null; diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/service/RecommendationService.java b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/service/RecommendationService.java index 574c5e4..85d838d 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/service/RecommendationService.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/service/RecommendationService.java @@ -66,8 +66,6 @@ private RecommendPredictDto makeResultForPredict(Closet closet, ClothingRecommen } } - // TODO : AI 학습 이후 사용자가 대량으로 의상을 삭제해서 추천할 의상이 없어져버리는 경우에 대한 고민이 필요해보임. - private List makeOuterList(Closet closet, List outers) { if (outers.isEmpty()) return new ArrayList<>(); @@ -84,8 +82,6 @@ private List makeOuterList(Closet closet, List outers) { } } } - - // if (result.isEmpty()) throw new CustomException(ErrorCode.NO_RECOMMEND_OUTER); return new ArrayList<>(resultSet); } @@ -103,7 +99,6 @@ private List makeUpperList(Closet closet, List tops) { } } } - // if (result.isEmpty()) throw new CustomException(ErrorCode.NO_RECOMMEND_UPPER); return new ArrayList<>(resultSet); } @@ -123,12 +118,11 @@ private List makeWeatherFeeling(Map predicti List forecasts = weatherForecastRepository .findByRegionNameAndForecastDateAndHourIn(regionName, forecastDate, hours); - // hour 기준으로 forecast 객체를 통째로 저장 (중복 방지 및 날짜 포함용) Map hourToForecastMap = forecasts.stream() .collect(Collectors.toMap( WeatherForecast::getHour, forecast -> forecast, - (oldVal, newVal) -> newVal // 중복 시간대가 있다면 최신 데이터로 덮기 + (oldVal, newVal) -> newVal )); for (Map.Entry entry : predictionMap.entrySet()) { @@ -138,7 +132,7 @@ private List makeWeatherFeeling(Map predicti if (forecast != null) { WeatherFeelingDto dto = WeatherFeelingDto.builder() - .date(forecast.getForecastDate()) // 추가 + .date(forecast.getForecastDate()) .time(hour) .feeling(feeling) .temperature(forecast.getTemperature()) @@ -160,7 +154,6 @@ private List getModelPrediction(Long id, LocalDate now) throw new CustomException(ErrorCode.NO_PREDICT_DATA); } return list; - // return clothingRecommendationRepository.findByMemberIdAndDate(id, now); } @Transactional From bcd4fb4d9ca6ae7af8aa85bcd03b7679ce04706d Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 18:34:42 +0900 Subject: [PATCH 06/11] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/closet/service/ClosetService.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClosetService.java b/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClosetService.java index 341836c..f814feb 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClosetService.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClosetService.java @@ -35,8 +35,6 @@ public class ClosetService { private static final Long MAX_UPPER_ID = 9L; private static final String UPPER = "uppers"; private static final String OUTER = "outers"; - private final List layerFlexibleUpper = new ArrayList<>(List.of(9L)); // 아우터로 할 수 있는 상의 - private final List layerFlexibleOuter = new ArrayList<>(List.of(3L)); // 상의로 할 수 있는 아우터 @Transactional @@ -71,14 +69,11 @@ private void addUpperClothes(Closet closet, List uppers) { for (ClothRegisterDto c : uppers) { validateClothDto(c, UPPER); - boolean isLayerFlexible = layerFlexibleUpper.contains(c.getClothType()); - Upper newUpper = Upper.builder() .upperType(c.getClothType()) .color(c.getColor()) .thickness(c.getThickness()) .isActive(true) - .isLayerFlexible(isLayerFlexible) .build(); boolean isDuplicate = closet.getUpperList().stream() @@ -94,14 +89,11 @@ private void addOuterClothes(Closet closet, List outers) { for (ClothRegisterDto c : outers) { validateClothDto(c, OUTER); - boolean isLayerFlexible = layerFlexibleOuter.contains(c.getClothType()); - Outer newOuter = Outer.builder() .outerType(c.getClothType()) .color(c.getColor()) .thickness(c.getThickness()) .isActive(true) - .isLayerFlexible(isLayerFlexible) .build(); boolean isDuplicate = closet.getOuterList().stream() @@ -205,7 +197,6 @@ public ClothListDto getUppers(Member member) { } catch (Exception e) { throw new CustomException(ErrorCode.UNKNOWN_ERROR, "아우터 조회 중 서버 오류가 발생했습니다."); } - } @Transactional(readOnly = true) From 7e7a3dd841bd4c3e0729f06e17737eeeba47d32b Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 18:35:12 +0900 Subject: [PATCH 07/11] =?UTF-8?q?refactor:=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/closet/api/ClothController.java | 8 ++++---- .../service/{ClothService.java => ClothImageService.java} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/com/howWeather/howWeather_backend/domain/closet/service/{ClothService.java => ClothImageService.java} (96%) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/closet/api/ClothController.java b/src/main/java/com/howWeather/howWeather_backend/domain/closet/api/ClothController.java index 0a39203..36c439e 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/closet/api/ClothController.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/closet/api/ClothController.java @@ -1,6 +1,6 @@ package com.howWeather.howWeather_backend.domain.closet.api; -import com.howWeather.howWeather_backend.domain.closet.service.ClothService; +import com.howWeather.howWeather_backend.domain.closet.service.ClothImageService; import com.howWeather.howWeather_backend.domain.member.entity.Member; import com.howWeather.howWeather_backend.global.Response.ApiResponse; import com.howWeather.howWeather_backend.global.jwt.CheckAuthenticatedUser; @@ -16,14 +16,14 @@ @RequiredArgsConstructor @RequestMapping("/api/cloth") public class ClothController { - private final ClothService clothService; + private final ClothImageService clothImageService; @GetMapping("/upper-image/{clothType}") @CheckAuthenticatedUser public ResponseEntity> upperImage(@RequestHeader("Authorization") String accessTokenHeader, @AuthenticationPrincipal Member member, @PathVariable("clothType") int clothType) { - String url = clothService.getUpperImage(clothType); + String url = clothImageService.getUpperImage(clothType); return ApiResponse.success(HttpStatus.OK, url); } @@ -32,7 +32,7 @@ public ResponseEntity> upperImage(@RequestHeader("Authorizat public ResponseEntity> outerImage(@RequestHeader("Authorization") String accessTokenHeader, @AuthenticationPrincipal Member member, @PathVariable("clothType") int clothType) { - String url = clothService.getOuterImage(clothType); + String url = clothImageService.getOuterImage(clothType); return ApiResponse.success(HttpStatus.OK, url); } } diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClothService.java b/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClothImageService.java similarity index 96% rename from src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClothService.java rename to src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClothImageService.java index fff756c..29851d0 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClothService.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/closet/service/ClothImageService.java @@ -11,7 +11,7 @@ @Service @Slf4j @AllArgsConstructor -public class ClothService { +public class ClothImageService { private final ClothRepository clothRepository; @Transactional(readOnly = true) From 76fb9cfdf3d927e108e8683978ee0fd6ac8575f4 Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 18:51:55 +0900 Subject: [PATCH 08/11] =?UTF-8?q?refactor:=20API=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20YML=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B2=BD=EB=A1=9C=20=EB=A1=9C=EB=93=9C?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/ai_model/api/AiInternalController.java | 2 +- .../howWeather_backend/global/cipher/AesTestController.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/api/AiInternalController.java b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/api/AiInternalController.java index 45579ee..eb8ca2b 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/api/AiInternalController.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/ai_model/api/AiInternalController.java @@ -30,7 +30,7 @@ @Slf4j @RestController @RequiredArgsConstructor -@RequestMapping("/internal-api/model") +@RequestMapping("${service-api.ai}") public class AiInternalController { private final AiInternalService aiInternalService; private final MemberRepository memberRepository; diff --git a/src/main/java/com/howWeather/howWeather_backend/global/cipher/AesTestController.java b/src/main/java/com/howWeather/howWeather_backend/global/cipher/AesTestController.java index d462d15..03f96e7 100644 --- a/src/main/java/com/howWeather/howWeather_backend/global/cipher/AesTestController.java +++ b/src/main/java/com/howWeather/howWeather_backend/global/cipher/AesTestController.java @@ -13,10 +13,9 @@ import java.util.Map; @RestController -@RequestMapping("/api/aes-test") +@RequestMapping("${service-api.aes}") @RequiredArgsConstructor public class AesTestController { - private final AESCipher aesCipher; private final ObjectMapper objectMapper; From 6a801d991d3300df576f575125e921cb3af00bf7 Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 18:57:28 +0900 Subject: [PATCH 09/11] =?UTF-8?q?chore:=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/jwt/RefreshToken.java | 16 ---------------- .../global/jwt/RefreshTokenRepository.java | 6 ------ .../global/jwt/RefreshTokenService.java | 19 ------------------- 3 files changed, 41 deletions(-) delete mode 100644 src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshToken.java delete mode 100644 src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshTokenRepository.java delete mode 100644 src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshTokenService.java diff --git a/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshToken.java b/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshToken.java deleted file mode 100644 index 266fc9e..0000000 --- a/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshToken.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.howWeather.howWeather_backend.global.jwt; - -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import lombok.*; - -@Builder(access = AccessLevel.PROTECTED) -@AllArgsConstructor -@Data -@Entity -@NoArgsConstructor -public class RefreshToken { - @Id - private String username; - private String refreshToken; -} diff --git a/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshTokenRepository.java b/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshTokenRepository.java deleted file mode 100644 index fb237ba..0000000 --- a/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshTokenRepository.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.howWeather.howWeather_backend.global.jwt; - -import org.springframework.data.jpa.repository.JpaRepository; - -public interface RefreshTokenRepository extends JpaRepository { -} \ No newline at end of file diff --git a/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshTokenService.java b/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshTokenService.java deleted file mode 100644 index 1931404..0000000 --- a/src/main/java/com/howWeather/howWeather_backend/global/jwt/RefreshTokenService.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.howWeather.howWeather_backend.global.jwt; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@Component -@RequiredArgsConstructor -public class RefreshTokenService { - private final RefreshTokenRepository refreshTokenRepository; - - public void saveRefreshToken(String username, String refreshToken) { - RefreshToken savedRefreshToken = new RefreshToken(username, refreshToken); - refreshTokenRepository.save(savedRefreshToken); - } -} \ No newline at end of file From 152a1a77f03e46e4b8116cf5891c1e3ddaea2f49 Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 18:57:50 +0900 Subject: [PATCH 10/11] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A3=BC=EC=84=9D=20=EB=B0=8F=20import=EB=AC=B8=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/weather/scheduler/WeatherScheduler.java | 5 ++--- .../global/custom/InvalidPrefix.java | 2 +- .../global/exception/LoginException.java | 2 -- .../global/jwt/JwtTokenProvider.java | 11 ----------- 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/weather/scheduler/WeatherScheduler.java b/src/main/java/com/howWeather/howWeather_backend/domain/weather/scheduler/WeatherScheduler.java index dc1f99d..a217f98 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/weather/scheduler/WeatherScheduler.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/weather/scheduler/WeatherScheduler.java @@ -1,6 +1,5 @@ package com.howWeather.howWeather_backend.domain.weather.scheduler; -import com.howWeather.howWeather_backend.domain.ai_model.repository.ClothingRecommendationRepository; import com.howWeather.howWeather_backend.domain.weather.repository.WeatherForecastRepository; import com.howWeather.howWeather_backend.domain.weather.service.WeatherService; import lombok.AllArgsConstructor; @@ -57,7 +56,7 @@ public void deleteOldWeatherData() { /** * 매일 오전 4시 30분에 ai 학습에 이용될 오늘의 예보 데이터를 가져옵니다. */ - @Scheduled(cron = "0 30 4 * * *", zone = "Asia/Seoul") // 매일 오전 4시 30분에 예보 데이터 + @Scheduled(cron = "0 30 4 * * *", zone = "Asia/Seoul") public void fetchDailyOneCallWeather() { log.info("Forecast API로 용산구의 날씨 예보를 가져옵니다. 시간: {}", LocalDateTime.now()); weatherService.fetchHourlyForecast(); @@ -66,7 +65,7 @@ public void fetchDailyOneCallWeather() { /** * 매일 오전 7시에 오늘 이전의 예보 데이터를 삭제합니다. */ - @Scheduled(cron = "0 0 7 * * *", zone = "Asia/Seoul") // 매일 오전 7시 + @Scheduled(cron = "0 0 7 * * *", zone = "Asia/Seoul") public void deleteOldForecastData() { LocalDate today = LocalDate.now(); weatherForecastRepository.deleteByForecastDateBefore(today); diff --git a/src/main/java/com/howWeather/howWeather_backend/global/custom/InvalidPrefix.java b/src/main/java/com/howWeather/howWeather_backend/global/custom/InvalidPrefix.java index 85eda24..f238e1b 100644 --- a/src/main/java/com/howWeather/howWeather_backend/global/custom/InvalidPrefix.java +++ b/src/main/java/com/howWeather/howWeather_backend/global/custom/InvalidPrefix.java @@ -13,5 +13,5 @@ String message() default "아이디는 'Google_', 'Kakao_' 등의 접두사로 시작할 수 없습니다."; Class[] groups() default {}; Class[] payload() default {}; - String[] prefixes(); // 금지할 접두사 목록 + String[] prefixes(); } diff --git a/src/main/java/com/howWeather/howWeather_backend/global/exception/LoginException.java b/src/main/java/com/howWeather/howWeather_backend/global/exception/LoginException.java index 0b44aee..af433ae 100644 --- a/src/main/java/com/howWeather/howWeather_backend/global/exception/LoginException.java +++ b/src/main/java/com/howWeather/howWeather_backend/global/exception/LoginException.java @@ -1,7 +1,5 @@ package com.howWeather.howWeather_backend.global.exception; -import lombok.Getter; - public class LoginException extends CustomException { public LoginException(ErrorCode errorCode, String message) { super(errorCode, message); diff --git a/src/main/java/com/howWeather/howWeather_backend/global/jwt/JwtTokenProvider.java b/src/main/java/com/howWeather/howWeather_backend/global/jwt/JwtTokenProvider.java index ee5dbc1..17b6475 100644 --- a/src/main/java/com/howWeather/howWeather_backend/global/jwt/JwtTokenProvider.java +++ b/src/main/java/com/howWeather/howWeather_backend/global/jwt/JwtTokenProvider.java @@ -109,17 +109,6 @@ public JwtToken reissueAccessToken(String refreshToken) { .build(); } -// public Authentication getAuthentication(String token) { -// Claims claims = parseClaims(token); -// String loginId = claims.getSubject(); -// -// UserDetails userDetails = customUserDetailsService.loadUserByUsername(loginId); -// -// System.out.println("userDetails = " + userDetails); -// return new UsernamePasswordAuthenticationToken(userDetails, token, userDetails.getAuthorities()); -// } - - public Authentication getAuthentication(String token) { Claims claims = parseClaims(token); if (claims == null || claims.getSubject() == null) { From 0e04b13443ab554bc91bc10c1555531535b8269c Mon Sep 17 00:00:00 2001 From: yeonjae02 <0yeonjae2@naver.com> Date: Thu, 31 Jul 2025 19:15:19 +0900 Subject: [PATCH 11/11] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?= =?UTF-8?q?=EC=A7=80=EC=97=AD=20=EA=B4=80=EB=A0=A8=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/api/MyAccountController.java | 4 +- .../member/service/MyAccountService.java | 63 +++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/member/api/MyAccountController.java b/src/main/java/com/howWeather/howWeather_backend/domain/member/api/MyAccountController.java index 2da3825..b1ea425 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/member/api/MyAccountController.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/member/api/MyAccountController.java @@ -72,7 +72,7 @@ public ResponseEntity> updateConstitution(@RequestHeader("Au @CheckAuthenticatedUser public ResponseEntity> getLocation(@RequestHeader("Authorization") String accessTokenHeader, @AuthenticationPrincipal Member member) { - String location = authService.getLoccation(member); + String location = myAccountService.getLoccation(member); return ApiResponse.success(HttpStatus.OK, location); } @@ -81,7 +81,7 @@ public ResponseEntity> getLocation(@RequestHeader("Authoriza public ResponseEntity> updateLocation(@RequestHeader("Authorization") String accessTokenHeader, @Valid @RequestBody RegionDto regionDto, @AuthenticationPrincipal Member member) { - authService.updateLocation(member, regionDto); + myAccountService.updateLocation(member, regionDto); return ApiResponse.success(HttpStatus.OK, "지역을 성공적으로 수정하였습니다."); } } diff --git a/src/main/java/com/howWeather/howWeather_backend/domain/member/service/MyAccountService.java b/src/main/java/com/howWeather/howWeather_backend/domain/member/service/MyAccountService.java index f427047..6783ac3 100644 --- a/src/main/java/com/howWeather/howWeather_backend/domain/member/service/MyAccountService.java +++ b/src/main/java/com/howWeather/howWeather_backend/domain/member/service/MyAccountService.java @@ -3,8 +3,11 @@ import com.howWeather.howWeather_backend.domain.member.dto.NicknameDto; import com.howWeather.howWeather_backend.domain.member.dto.ProfileChangeIntDto; import com.howWeather.howWeather_backend.domain.member.dto.ProfileDto; +import com.howWeather.howWeather_backend.domain.member.dto.RegionDto; import com.howWeather.howWeather_backend.domain.member.entity.Member; import com.howWeather.howWeather_backend.domain.member.repository.MemberRepository; +import com.howWeather.howWeather_backend.domain.weather.entity.Region; +import com.howWeather.howWeather_backend.domain.weather.repository.RegionRepository; import com.howWeather.howWeather_backend.global.exception.CustomException; import com.howWeather.howWeather_backend.global.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -12,11 +15,14 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalTime; + @Slf4j @Service @RequiredArgsConstructor public class MyAccountService { private final MemberRepository memberRepository; + private final RegionRepository regionRepository; @Transactional(readOnly = true) public ProfileDto getProfile(Member member) { @@ -111,4 +117,61 @@ private void validateIntData(Integer data, int start, int end) { throw new CustomException(ErrorCode.INVALID_INPUT, "유효하지 않은 입력값입니다."); } } + + @Transactional(readOnly = true) + public String getLoccation(Member member) { + try { + String region = member.getRegionName(); + + if (region == null || region.trim().isEmpty()) + return "서울특별시 용산구"; + + return region; + + } catch (CustomException e) { + throw e; + }catch (Exception e) { + log.error("지역 조회 중 에러 발생: {}", e.getMessage(), e); + throw new CustomException(ErrorCode.UNKNOWN_ERROR, "지역 조회 중 오류가 발생했습니다."); + } + } + + @Transactional + public void updateLocation(Member member, RegionDto regionDto) { + try { + LocalTime now = LocalTime.now(); + if (!now.isBefore(LocalTime.of(4, 00)) && now.isBefore(LocalTime.of(7, 0))) { + throw new CustomException(ErrorCode.TIME_RESTRICTED_FOR_REGION_CHANGE); + } + validateRegion(regionDto.getRegionName()); + + Member persistedMember = memberRepository.findById(member.getId()) + .orElseThrow(() -> new CustomException(ErrorCode.ID_NOT_FOUND, "회원 정보를 찾을 수 없습니다.")); + + String oldRegionName = persistedMember.getRegionName(); + String newRegionName = regionDto.getRegionName(); + + if (oldRegionName == null || !newRegionName.equals(oldRegionName)) { + if (oldRegionName != null) { + regionRepository.findByName(oldRegionName).ifPresent(Region::decrementCurrentUserCount); + } + + Region newRegion = regionRepository.findByName(newRegionName) + .orElseThrow(() -> new CustomException(ErrorCode.REGION_NOT_FOUND)); + newRegion.incrementCurrentUserCount(); + persistedMember.changeRegion(newRegionName); + } + } catch (CustomException e) { + throw e; + } catch (Exception e) { + log.error("지역 수정 중 에러 발생: {}", e.getMessage(), e); + throw new CustomException(ErrorCode.UNKNOWN_ERROR, "지역 수정 중 오류가 발생했습니다."); + } + } + + private void validateRegion(String regionName) { + if (regionName == null || regionName.isEmpty() || !regionRepository.existsByName(regionName)) { + throw new CustomException(ErrorCode.REGION_NOT_FOUND); + } + } }