From dc042bd20c76ba05c283168b5b0b0fcbe2f51cbb Mon Sep 17 00:00:00 2001 From: sshnote Date: Wed, 12 Feb 2025 19:01:38 +0900 Subject: [PATCH 01/34] =?UTF-8?q?=F0=9F=93=9D=20=20docs:=20SwaggerConfig?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prod 배포 주소까지 추가하였습니다. --- .../java/com/example/mody/global/config/SwaggerConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/mody/global/config/SwaggerConfig.java b/src/main/java/com/example/mody/global/config/SwaggerConfig.java index 8f839d4d..4c5fae5d 100644 --- a/src/main/java/com/example/mody/global/config/SwaggerConfig.java +++ b/src/main/java/com/example/mody/global/config/SwaggerConfig.java @@ -14,8 +14,10 @@ @Configuration @OpenAPIDefinition( servers = { - @Server(url = "https://kkoalla.app:8443", description = "모디 https 개발 서버입니다."), + @Server(url = "https://kkoalla.app:8443/dev", description = "모디 https 개발 서버입니다."), + @Server(url = "https://kkoalla.app:8443/prod", description = "모디 https 배포 서버입니다."), @Server(url = "http://3.37.4.11:8000", description = "모디 http 개발 서버입니다."), + @Server(url = "http://3.37.4.11:8080", description = "모디 http 배포 서버입니다."), @Server(url = "http://localhost:8080", description = "모디 local 서버입니다.") } ) From 2bbb6b13397ad9ace00f82009e46d37386dd5bf7 Mon Sep 17 00:00:00 2001 From: sshnote Date: Thu, 13 Feb 2025 00:09:28 +0900 Subject: [PATCH 02/34] =?UTF-8?q?=F0=9F=94=A8=20=20fix:=20=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=EB=A7=81=20=EC=A0=95=ED=99=95=EB=8F=84=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 스타일에 따라 크롤링 사진이 정확하지 않은 오류를 해결하였습니다. --- .../mody/domain/recommendation/service/CrawlerService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/mody/domain/recommendation/service/CrawlerService.java b/src/main/java/com/example/mody/domain/recommendation/service/CrawlerService.java index fb4c1b6f..f07883b2 100644 --- a/src/main/java/com/example/mody/domain/recommendation/service/CrawlerService.java +++ b/src/main/java/com/example/mody/domain/recommendation/service/CrawlerService.java @@ -27,7 +27,7 @@ public String getRandomImageUrl(String keyword) { WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); try { - String searchUrl = "https://kr.pinterest.com/search/pins/?q=" + URLEncoder.encode(keyword, StandardCharsets.UTF_8); + String searchUrl = "https://kr.pinterest.com/search/pins/?q=" + URLEncoder.encode(keyword + " 스타일", StandardCharsets.UTF_8); driver.navigate().to(searchUrl); log.info("Pinterest 검색 URL 접속 완료: {}", searchUrl); @@ -74,7 +74,7 @@ private WebDriver getWebDriver() { options.addArguments("--disable-dev-shm-usage"); // /dev/shm 사용 비활성화(Docker 환경에서 크롬 크래시 문제 해결) options.addArguments("--ignore-ssl-errors=yes"); options.addArguments("--ignore-certificate-errors"); // SSL 차단 대비 - + options.addArguments("--window-size=1920,1080"); // 해상도 설정(가로 1920px, 세로 1080px) return new ChromeDriver(options); } } From dd472dedae1ed0be7bd7879a41eecaf854fd16d2 Mon Sep 17 00:00:00 2001 From: jher235 Date: Sat, 15 Feb 2025 23:54:06 +0900 Subject: [PATCH 03/34] =?UTF-8?q?:recycle:=20[#129]=20refactor:=20?= =?UTF-8?q?=EC=A0=95=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mody/domain/post/dto/response/PostImageResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/mody/domain/post/dto/response/PostImageResponse.java b/src/main/java/com/example/mody/domain/post/dto/response/PostImageResponse.java index 4821d2b9..34ef07b5 100644 --- a/src/main/java/com/example/mody/domain/post/dto/response/PostImageResponse.java +++ b/src/main/java/com/example/mody/domain/post/dto/response/PostImageResponse.java @@ -9,7 +9,7 @@ @AllArgsConstructor(access = AccessLevel.PRIVATE) public class PostImageResponse { private String s3Url; - public static PostImageResponse of(PostImage postImage){ + public static PostImageResponse from(PostImage postImage){ return new PostImageResponse(postImage.getUrl()); } } From 4ff9e246a3f3da9256aebdd3ab61b6f0c762d0a0 Mon Sep 17 00:00:00 2001 From: jher235 Date: Sat, 15 Feb 2025 23:54:45 +0900 Subject: [PATCH 04/34] =?UTF-8?q?:sparkles:=20[#129]=20feature:=20PostResp?= =?UTF-8?q?onse=20dto=20=ED=95=84=EB=93=9C=EC=97=90=20isMine=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/mody/domain/post/dto/response/PostResponse.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/mody/domain/post/dto/response/PostResponse.java b/src/main/java/com/example/mody/domain/post/dto/response/PostResponse.java index e3b3baba..8fd72f94 100644 --- a/src/main/java/com/example/mody/domain/post/dto/response/PostResponse.java +++ b/src/main/java/com/example/mody/domain/post/dto/response/PostResponse.java @@ -13,6 +13,7 @@ public class PostResponse { private Long postId; private Long writerId; private String writerNickName; + private Boolean isMine; private String content; private Boolean isPublic; private Integer likeCount; @@ -23,6 +24,7 @@ public class PostResponse { public PostResponse(Long postId, Long writerId, String nickName, + Boolean isMine, String content, Boolean isPublic, Integer likeCount, @@ -32,13 +34,14 @@ public PostResponse(Long postId, this.postId = postId; this.writerId = writerId; this.writerNickName = nickName; + this.isMine = isMine; this.content = content; this.isPublic = isPublic; this.likeCount = likeCount; this.isLiked = isLiked; this.bodyType = bodyType; this.files = files.stream() - .map(PostImageResponse::of) + .map(PostImageResponse::from) .toList(); } } From 8fcbf6ece4d8d5e9f943f3dec40a3b370663e286 Mon Sep 17 00:00:00 2001 From: jher235 Date: Sat, 15 Feb 2025 23:55:12 +0900 Subject: [PATCH 05/34] =?UTF-8?q?:sparkles:=20[#129]=20feature:=20PostResp?= =?UTF-8?q?onse=20dto=20=ED=95=84=EB=93=9C=EC=97=90=20isMine=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EB=90=98=EC=96=B4=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mody/domain/post/repository/PostCustomRepositoryImpl.java | 3 +++ .../example/mody/domain/post/service/PostQueryServiceImpl.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java index 12db84a3..4393b394 100644 --- a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java +++ b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java @@ -93,6 +93,7 @@ public PostListResponse getPostList(Optional cursorPost, Integer size, Mem qPost.id, qMember.id, qMember.nickname, + qMember.eq(member), qPost.content, qPost.isPublic, qPost.likeCount, @@ -142,6 +143,7 @@ public LikedPostsResponse getLikedPosts(Long cursor, Integer size, Member member qPost.id, qMember.id, qMember.nickname, + qMember.eq(member), qPost.content, qPost.isPublic, qPost.likeCount, @@ -192,6 +194,7 @@ public PostListResponse getMyPosts(Long cursor, Integer size, Member member) { qPost.id, qMember.id, qMember.nickname, + qMember.eq(member), qPost.content, qPost.isPublic, qPost.likeCount, diff --git a/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java b/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java index ecc2e9dc..eb61fe50 100644 --- a/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java +++ b/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java @@ -96,7 +96,7 @@ public PostResponse getPost(Member member, Long postId){ Optional existingLike = postLikeRepository.findByPostAndMember(post, member); - PostResponse postResponse = new PostResponse(post.getId(), post.getMember().getId(),post.getMember().getNickname(), post.getContent(), post.getIsPublic(), post.getLikeCount(), existingLike.isPresent() ,post.getBodyType().getName(), post.getImages()); + PostResponse postResponse = new PostResponse(post.getId(), post.getMember().getId(),post.getMember().getNickname(),post.getMember().equals(member), post.getContent(), post.getIsPublic(), post.getLikeCount(), existingLike.isPresent() ,post.getBodyType().getName(), post.getImages()); return postResponse; } From 91c84deb69448c63105d1b2d1d43241b5e5589cb Mon Sep 17 00:00:00 2001 From: jher235 Date: Sun, 16 Feb 2025 00:26:04 +0900 Subject: [PATCH 06/34] =?UTF-8?q?:recycle:=20[#129]=20refactor:=20post=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1=EC=9E=90?= =?UTF-8?q?=EB=A5=BC=20=EB=B9=8C=EB=8D=94=EB=A1=9C=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/mody/domain/post/entity/Post.java | 10 +++++----- .../domain/post/service/PostCommandServiceImpl.java | 11 +++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/mody/domain/post/entity/Post.java b/src/main/java/com/example/mody/domain/post/entity/Post.java index c66ee581..e9152b31 100644 --- a/src/main/java/com/example/mody/domain/post/entity/Post.java +++ b/src/main/java/com/example/mody/domain/post/entity/Post.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import lombok.*; import org.hibernate.annotations.DynamicUpdate; import com.example.mody.domain.bodytype.entity.BodyType; @@ -23,9 +24,6 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; @Entity(name = "post") @Getter @@ -62,14 +60,15 @@ public class Post extends BaseEntity { private String content; @Column(nullable = false) - private Integer likeCount; + private Integer likeCount = 0; @Column(nullable = false) private Boolean isPublic; @Column(nullable = false) - private Integer reportCount; + private Integer reportCount = 0; + @Builder public Post(Member member, BodyType bodyType, String content, Boolean isPublic) { this.member = member; this.bodyType = bodyType; @@ -78,6 +77,7 @@ public Post(Member member, BodyType bodyType, String content, Boolean isPublic) this.likeCount = 0; this.reportCount = 0; this.images = new ArrayList<>(); + this.likes = new ArrayList<>(); } public void decreaseLikeCount() { diff --git a/src/main/java/com/example/mody/domain/post/service/PostCommandServiceImpl.java b/src/main/java/com/example/mody/domain/post/service/PostCommandServiceImpl.java index 27e3b2dc..a4e3ddba 100644 --- a/src/main/java/com/example/mody/domain/post/service/PostCommandServiceImpl.java +++ b/src/main/java/com/example/mody/domain/post/service/PostCommandServiceImpl.java @@ -16,6 +16,7 @@ import com.example.mody.global.common.exception.RestApiException; import com.example.mody.global.common.exception.code.status.S3ErrorStatus; import org.springframework.http.HttpMethod; +import org.springframework.security.core.parameters.P; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -66,10 +67,12 @@ public void createPost(PostCreateRequest postCreateRequest, Member member) { BodyType bodyType = optionalBodyType.orElseThrow(() -> new BodyTypeException(MEMBER_BODY_TYPE_NOT_FOUND)); - Post post = new Post(member, - bodyType, - postCreateRequest.getContent(), - postCreateRequest.getIsPublic()); + Post post = Post.builder() + .member(member) + .bodyType(bodyType) + .content(postCreateRequest.getContent()) + .isPublic(postCreateRequest.getIsPublic()) + .build(); postCreateRequest.getS3Urls().forEach(s3Url -> { validateS3Url(s3Url); // 유효한 S3 url인지 검증 From c930ab922ade924e74e374d43ee856c67d1cf9ea Mon Sep 17 00:00:00 2001 From: jher235 Date: Sun, 16 Feb 2025 00:28:54 +0900 Subject: [PATCH 07/34] =?UTF-8?q?:memo:=20[#129]=20comment:=20PostImage=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90=EC=84=9C=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EC=9E=90=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=9D=B4=EC=9C=A0=EC=97=90=20=EB=8C=80=ED=95=B4=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/mody/domain/post/entity/PostImage.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/example/mody/domain/post/entity/PostImage.java b/src/main/java/com/example/mody/domain/post/entity/PostImage.java index 1b71ffaf..b44da966 100644 --- a/src/main/java/com/example/mody/domain/post/entity/PostImage.java +++ b/src/main/java/com/example/mody/domain/post/entity/PostImage.java @@ -23,6 +23,11 @@ public class PostImage extends BaseEntity { @Column(nullable = false) private String url; + /** + * 필드 개수가 적고, 필드들이 필수값이므로 빌더 패턴을 사용하지 않고 생성자를 사용함 + * @param post + * @param s3Url + */ public PostImage(Post post, String s3Url){ this.post = post; this.url = s3Url; From 3631c842393dde8eb8c5be3aad3fec2c9b818ff1 Mon Sep 17 00:00:00 2001 From: yunseo02 <154687627+yunseo02@users.noreply.github.com> Date: Mon, 17 Feb 2025 22:49:42 +0900 Subject: [PATCH 08/34] =?UTF-8?q?=E2=9C=A8=20[#132]feature:=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=EC=99=84=EB=A3=8C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EA=B5=AC=EC=A1=B0,=20=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 회원가입 완료 api에서 인증되지 않은 사용자 오류 처리를 위해 secutiryConfig 수정 --- .../auth/controller/AuthController.java | 28 +++++++++++-------- .../auth/jwt/JwtAuthenticationFilter.java | 1 - .../member/service/MemberCommandService.java | 4 ++- .../service/MemberCommandServiceImpl.java | 4 +-- .../mody/global/config/SecurityConfig.java | 3 +- .../RecommendationCommendServiceTest.java | 22 +++++++++++++++ 6 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 src/test/java/com/example/mody/domain/recommendation/service/RecommendationCommendServiceTest.java diff --git a/src/main/java/com/example/mody/domain/auth/controller/AuthController.java b/src/main/java/com/example/mody/domain/auth/controller/AuthController.java index 25e39852..81780981 100644 --- a/src/main/java/com/example/mody/domain/auth/controller/AuthController.java +++ b/src/main/java/com/example/mody/domain/auth/controller/AuthController.java @@ -1,9 +1,16 @@ package com.example.mody.domain.auth.controller; +import com.example.mody.domain.exception.MemberException; +import com.example.mody.domain.member.entity.Member; +import com.example.mody.global.common.exception.code.status.GlobalErrorStatus; +import com.example.mody.global.common.exception.code.status.MemberErrorStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseCookie; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -96,26 +103,25 @@ public class AuthController { ) ), @ApiResponse( - responseCode = "404", - description = "사용자를 찾을 수 없음", + responseCode = "COMMON401", + description = "로그인하지 않은 경우에 발생합니다.(엑세스 토큰을 넣지 않았을 때)", content = @Content( mediaType = "application/json", examples = @ExampleObject( value = """ - { - "timestamp": "2024-01-13T10:00:00", - "code": "MEMBER404", - "message": "해당 회원을 찾을 수 없습니다.", - "result": null - } - """ + { + "timestamp": "2025-02-17T22:23:22.7640118", + "code": "COMMON401", + "message": "인증이 필요합니다." + } + """ ) ) ) }) @PostMapping("/signup/complete") public BaseResponse completeRegistration( - @AuthenticationPrincipal CustomUserDetails userDetails, + @AuthenticationPrincipal CustomUserDetails customUserDetails, @Valid @RequestBody @Parameter( description = "회원가입 완료 요청 정보", @@ -137,7 +143,7 @@ public BaseResponse completeRegistration( ) ) MemberRegistrationRequest request ) { - memberCommandService.completeRegistration(userDetails.getMember().getId(), request); + memberCommandService.completeRegistration(customUserDetails.getMember(), request); return BaseResponse.onSuccess(null); } diff --git a/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java b/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java index 11599ba8..8fee4243 100644 --- a/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java @@ -37,7 +37,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtProvider jwtProvider; private final MemberRepository memberRepository; private final ObjectMapper objectMapper; - private final MemberQueryService memberQueryService; @Override protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { diff --git a/src/main/java/com/example/mody/domain/member/service/MemberCommandService.java b/src/main/java/com/example/mody/domain/member/service/MemberCommandService.java index a417aea4..818cd2a2 100644 --- a/src/main/java/com/example/mody/domain/member/service/MemberCommandService.java +++ b/src/main/java/com/example/mody/domain/member/service/MemberCommandService.java @@ -4,10 +4,12 @@ import com.example.mody.domain.auth.dto.request.MemberRegistrationRequest; import com.example.mody.domain.auth.dto.response.LoginResponse; +import com.example.mody.domain.auth.security.CustomUserDetails; +import com.example.mody.domain.member.entity.Member; import jakarta.servlet.http.HttpServletResponse; public interface MemberCommandService { - void completeRegistration(Long memberId, MemberRegistrationRequest request); + void completeRegistration(Member member, MemberRegistrationRequest request); LoginResponse joinMember(MemberJoinRequest request, HttpServletResponse response); diff --git a/src/main/java/com/example/mody/domain/member/service/MemberCommandServiceImpl.java b/src/main/java/com/example/mody/domain/member/service/MemberCommandServiceImpl.java index b68fce8c..e646218e 100644 --- a/src/main/java/com/example/mody/domain/member/service/MemberCommandServiceImpl.java +++ b/src/main/java/com/example/mody/domain/member/service/MemberCommandServiceImpl.java @@ -29,9 +29,7 @@ public class MemberCommandServiceImpl implements MemberCommandService { private final AuthCommandService authCommandService; @Override - public void completeRegistration(Long memberId, MemberRegistrationRequest request) { - Member member = memberRepository.findById(memberId) - .orElseThrow(() -> new MemberException(MemberErrorStatus.MEMBER_NOT_FOUND)); + public void completeRegistration(Member member, MemberRegistrationRequest request) { member.completeRegistration( request.getNickname(), diff --git a/src/main/java/com/example/mody/global/config/SecurityConfig.java b/src/main/java/com/example/mody/global/config/SecurityConfig.java index 37a1e9bc..5f1c1f6a 100644 --- a/src/main/java/com/example/mody/global/config/SecurityConfig.java +++ b/src/main/java/com/example/mody/global/config/SecurityConfig.java @@ -56,6 +56,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .httpBasic(httpBasic -> httpBasic.disable()) .authorizeHttpRequests(authz -> authz + .requestMatchers("/auth/signup/complete").authenticated() .requestMatchers("/auth/**", "/oauth2/**").permitAll() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-ui.html").permitAll() .requestMatchers("/email/**").permitAll() @@ -130,7 +131,7 @@ public CorsConfigurationSource corsConfigurationSource() { @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { - return new JwtAuthenticationFilter(jwtProvider, memberRepository, objectMapper, memberQueryService); + return new JwtAuthenticationFilter(jwtProvider, memberRepository, objectMapper); } @Bean diff --git a/src/test/java/com/example/mody/domain/recommendation/service/RecommendationCommendServiceTest.java b/src/test/java/com/example/mody/domain/recommendation/service/RecommendationCommendServiceTest.java new file mode 100644 index 00000000..6ecad9ee --- /dev/null +++ b/src/test/java/com/example/mody/domain/recommendation/service/RecommendationCommendServiceTest.java @@ -0,0 +1,22 @@ +package com.example.mody.domain.recommendation.service; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + + + +class RecommendationCommendServiceTest { + + @Test + void recommendStyle() { + } + + @Test + void recommendFashionItem() { + } + + @Test + void toggleLike() { + } +} \ No newline at end of file From 7d4745683e3fd8f77d0cd5f99dc4fad34362bcf1 Mon Sep 17 00:00:00 2001 From: yunseo02 <154687627+yunseo02@users.noreply.github.com> Date: Mon, 17 Feb 2025 22:53:36 +0900 Subject: [PATCH 09/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#132]=20refactor:?= =?UTF-8?q?=20=EC=B6=94=EC=B2=9C=20=EC=A2=8B=EC=95=84=EC=9A=94=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 추천 좋아요 필드명을 수정하였습니다. --- src/main/java/com/example/mody/domain/member/entity/Member.java | 2 +- .../mody/domain/recommendation/entity/Recommendation.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/mody/domain/member/entity/Member.java b/src/main/java/com/example/mody/domain/member/entity/Member.java index 841d779e..175a88c0 100644 --- a/src/main/java/com/example/mody/domain/member/entity/Member.java +++ b/src/main/java/com/example/mody/domain/member/entity/Member.java @@ -66,7 +66,7 @@ public class Member extends BaseEntity { cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) - private List RecommendLikes = new ArrayList<>(); + private List recommendationLikes = new ArrayList<>(); /** * 회원이 작성한 게시글 목록 diff --git a/src/main/java/com/example/mody/domain/recommendation/entity/Recommendation.java b/src/main/java/com/example/mody/domain/recommendation/entity/Recommendation.java index 40a53ca6..651dd341 100644 --- a/src/main/java/com/example/mody/domain/recommendation/entity/Recommendation.java +++ b/src/main/java/com/example/mody/domain/recommendation/entity/Recommendation.java @@ -52,7 +52,7 @@ public class Recommendation extends BaseEntity { cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) - private List RecommendLikes = new ArrayList<>(); + private List recommendationLikes = new ArrayList<>(); public void increaseLikeCount() { this.likeCount++; From c301b64f31b55bda266ed704f0d08addca5cb539 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 00:22:44 +0900 Subject: [PATCH 10/34] =?UTF-8?q?=E2=9C=A8=20=20feat=20:=20OpenAI=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/mody/global/templates/PromptManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/mody/global/templates/PromptManager.java b/src/main/java/com/example/mody/global/templates/PromptManager.java index c8052a3b..ce8bb3f5 100644 --- a/src/main/java/com/example/mody/global/templates/PromptManager.java +++ b/src/main/java/com/example/mody/global/templates/PromptManager.java @@ -18,6 +18,7 @@ public String createBodyTypeAnalysisPrompt(String nickName, Gender gender, Strin """ ## 명령 닉네임과 성별, 그리고 사용자의 답변을 기반으로 체형 타입(네추럴, 스트레이트, 웨이브 중 하나)을 분석하고, 설명과 스타일링 팁을 제공해줘. + 이 때 강조할 부분과 보완할 부분을 기계적이지 않고 자세하게 답변해줘. 결과는 JSON 형식으로 반환해줘. ## 사용자 정보 From d9d992dd63249f2861c20e9c408624435af5f9ce Mon Sep 17 00:00:00 2001 From: jher235 Date: Tue, 18 Feb 2025 01:25:20 +0900 Subject: [PATCH 11/34] =?UTF-8?q?:recycle:=20[#131]=20refactor:=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EC=B5=9C=EC=A0=81=ED=99=94=20=EB=B0=8F=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=B6=84=EB=A6=AC=20-=20=EA=B8=B0?= =?UTF-8?q?=EC=A1=B4=20=EC=9D=B8=EB=8D=B1=EC=8A=A4=EB=A5=BC=20=ED=83=80?= =?UTF-8?q?=EC=A7=80=20=EB=AA=BB=ED=95=98=EB=8D=98=20=EC=A0=95=EB=A0=AC=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=20=EC=88=98=EC=A0=95=20-=20=EC=9D=B8?= =?UTF-8?q?=EB=8D=B1=EC=8A=A4=20=EC=82=AC=EC=9A=A9=EC=9D=B4=20=EB=B6=88?= =?UTF-8?q?=EA=B0=80=ED=96=88=EB=8D=98=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EC=BB=A4=EC=84=9C=EB=A5=BC=20=EC=A7=80=EC=9A=B0=EA=B3=A0=20?= =?UTF-8?q?=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=83=81=ED=99=A9=EB=B3=84=20=EC=B5=9C?= =?UTF-8?q?=EC=A0=81=ED=99=94=20-=20=EC=A4=91=EB=B3=B5=EB=90=98=EB=8A=94?= =?UTF-8?q?=20jpaQueryFactory=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/repository/PostCustomRepository.java | 6 +- .../repository/PostCustomRepositoryImpl.java | 270 ++++++++---------- 2 files changed, 119 insertions(+), 157 deletions(-) diff --git a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepository.java b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepository.java index dafacb5a..a2ef262d 100644 --- a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepository.java +++ b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepository.java @@ -5,13 +5,15 @@ import com.example.mody.domain.post.dto.response.PostListResponse; import com.example.mody.domain.post.dto.response.recode.LikedPostsResponse; import com.example.mody.domain.post.entity.Post; -import jakarta.persistence.EntityManager; import java.util.Optional; public interface PostCustomRepository { - public PostListResponse getPostList(Optional cursorPost, Integer size, Member member, Optional bodyType); + public PostListResponse getBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType); + public PostListResponse getOtherBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType); public LikedPostsResponse getLikedPosts(Long cursor, Integer size, Member member); public PostListResponse getMyPosts(Long cursor, Integer size, Member member); + public PostListResponse getRecentPosts(Long cursor, Integer size, Member member); + } diff --git a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java index 4393b394..4d4350bb 100644 --- a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java +++ b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java @@ -1,6 +1,7 @@ package com.example.mody.domain.post.repository; import com.example.mody.domain.bodytype.entity.BodyType; +import com.example.mody.domain.bodytype.entity.QBodyType; import com.example.mody.domain.member.entity.Member; import com.example.mody.domain.member.entity.QMember; import com.example.mody.domain.post.dto.response.PostListResponse; @@ -20,8 +21,10 @@ import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.QueryHint; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.hibernate.annotations.QueryHints; import org.springframework.stereotype.Repository; import java.time.format.DateTimeFormatter; @@ -39,6 +42,7 @@ public class PostCustomRepositoryImpl implements PostCustomRepository{ private final QMember qMember = QMember.member; private final QMemberPostLike qMemberPostLike = QMemberPostLike.memberPostLike; private final QPostImage qPostImage = QPostImage.postImage; + private final QBodyType qBodyType = QBodyType.bodyType; /** @@ -50,59 +54,45 @@ public class PostCustomRepositoryImpl implements PostCustomRepository{ * @return */ @Override - public PostListResponse getPostList(Optional cursorPost, Integer size, Member member, Optional bodyType) { + public PostListResponse getBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType) { BooleanBuilder predicate = new BooleanBuilder(); predicate.and(qPost.isPublic.eq(true)); // 공개여부 == true + predicate.and(qPost.bodyType.eq(bodyType)); if(cursorPost.isPresent()){ - String customCursor = createCustomCursor(cursorPost.get(), bodyType); - log.info(customCursor); - predicate.and(applyCustomCursor(customCursor, bodyType)); - } - - BooleanExpression isLiked = Expressions.asBoolean(false); - if (member != null){ - isLiked = isLikedResult(member); + predicate.and(qPost.id.lt(cursorPost.get().getId())); } //동적 정렬 List> orderSpecifiers = new ArrayList<>(); - if (bodyType.isPresent()) { - orderSpecifiers.add(matchedBodyTypeAsInteger(bodyType).desc()); // bodyType이 존재할 때만 정렬 조건 추가 - } - orderSpecifiers.add(qPost.createdAt.desc()); // 항상 createdAt으로 정렬 + orderSpecifiers.add(qPost.id.desc()); // id를 auto_increment 를 사용하므로 created_at을 대신하여 id로 최신순 정렬을 함 - List postIds = jpaQueryFactory - .select(qPost.id) - .from(qPost) - .where(predicate) - .orderBy(orderSpecifiers.toArray(new OrderSpecifier[0])) - .limit(size+1) //하나 더 가져와서 다음 요소가 존재하는지 확인 - .fetch(); + List postIds = getPostIds(predicate, size, orderSpecifiers); + List postResponses = getPostResponsesByIds(postIds, member, orderSpecifiers); - Map postResponseMap = jpaQueryFactory - .from(qPost) - .leftJoin(qPost.member, qMember) - .leftJoin(qPost.images, qPostImage) - .leftJoin(qMemberPostLike).on(qMemberPostLike.post.eq(qPost).and(qMemberPostLike.member.eq(member))) - .where(qPost.id.in(postIds)) - .orderBy(orderSpecifiers.toArray(new OrderSpecifier[0])) - .transform(GroupBy.groupBy(qPost.id).as( - Projections.constructor(PostResponse.class, - qPost.id, - qMember.id, - qMember.nickname, - qMember.eq(member), - qPost.content, - qPost.isPublic, - qPost.likeCount, - qMemberPostLike.isNotNull(), - qPost.bodyType.name, - GroupBy.list(qPostImage) - ))); + // 여기서는 목록 개수가 size 개수와 동일한 경우도 hasNext가 true임. + return PostListResponse.of(hasNext.apply(postResponses, size-1), + postResponses.subList(0, Math.min(size, postResponses.size()))); + } - List postResponses = new ArrayList<>(postResponseMap.values()); + @Override + public PostListResponse getOtherBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType) { + BooleanBuilder predicate = new BooleanBuilder(); + + predicate.and(qPost.isPublic.eq(true)); // 공개여부 == true + predicate.and(qPost.bodyType.ne(bodyType)); + + if(cursorPost.isPresent()){ + predicate.and(qPost.id.lt(cursorPost.get().getId())); + } + + //동적 정렬 + List> orderSpecifiers = new ArrayList<>(); + orderSpecifiers.add(qPost.id.desc()); + + List postIds = getPostIds(predicate, size+1, orderSpecifiers); //하나 더 가져와서 다음 요소가 존재하는지 확인 + List postResponses = getPostResponsesByIds(postIds, member, orderSpecifiers); return PostListResponse.of(hasNext.apply(postResponses, size), postResponses.subList(0, Math.min(size, postResponses.size()))); @@ -122,40 +112,12 @@ public LikedPostsResponse getLikedPosts(Long cursor, Integer size, Member member predicate.and(qMemberPostLike.id.lt(cursor)); } - predicate.and(qMemberPostLike.member.eq(member)); - - List postIds = jpaQueryFactory - .select(qPost.id) - .from(qPost) - .leftJoin(qMemberPostLike).on(qMemberPostLike.post.eq(qPost).and(qMemberPostLike.member.eq(member))) - .where(predicate) - .orderBy(qMemberPostLike.createdAt.desc()) - .limit(size+1) //하나 더 가져와서 다음 요소가 존재하는지 확인 - .fetch(); - - Map postResponseMap = jpaQueryFactory - .from(qPost) - .leftJoin(qPost.member, qMember) - .leftJoin(qPost.images, qPostImage) - .where(qPost.id.in(postIds)) - .transform(GroupBy.groupBy(qPost.id).as( - Projections.constructor(PostResponse.class, - qPost.id, - qMember.id, - qMember.nickname, - qMember.eq(member), - qPost.content, - qPost.isPublic, - qPost.likeCount, - Expressions.asBoolean(Expressions.TRUE), - qPost.bodyType.name, - GroupBy.list(qPostImage) - ))); + List> orderSpecifiers = new ArrayList<>(); + orderSpecifiers.add(qMemberPostLike.id.desc()); // 최근에 누른 좋아요 순으로 정렬 - List postResponses = postIds.stream() - .map(postResponseMap::get) - .filter(Objects::nonNull) - .toList(); + List postIds = getMemberLikedPostIds( + predicate, size+1, member, orderSpecifiers); + List postResponses = getLikedPostResponsesByIds(postIds, member); return new LikedPostsResponse( hasNext.apply(postResponses, size), @@ -172,23 +134,68 @@ public PostListResponse getMyPosts(Long cursor, Integer size, Member member) { predicate.and(qPost.id.lt(cursor)); } - log.info(predicate.toString()); + List> orderSpecifiers = new ArrayList<>(); + orderSpecifiers.add(qPost.id.desc()); + + List postIds = getPostIds(predicate, size+1, orderSpecifiers); + List postResponses = getPostResponsesByIds(postIds, member, orderSpecifiers); + + return PostListResponse.of(hasNext.apply(postResponses, size), + postResponses.subList(0, Math.min(size, postResponses.size()))); + } - List postIds = jpaQueryFactory + @Override + public PostListResponse getRecentPosts(Long cursor, Integer size, Member member) { + BooleanBuilder predicate = new BooleanBuilder(); + + predicate.and(qPost.isPublic.eq(true)); + + if(cursor != null){ + predicate.and(qPost.id.lt(cursor)); + } + + List> orderSpecifiers = new ArrayList<>(); + orderSpecifiers.add(qPost.id.desc()); + + List postIds = getPostIds(predicate, size+1, orderSpecifiers); + List postResponses = getPostResponsesByIds(postIds, member, orderSpecifiers); + + return PostListResponse.of(hasNext.apply(postResponses, size), + postResponses.subList(0, Math.min(size, postResponses.size()))); + } + + private List getPostIds(BooleanBuilder predicate, Integer size, + List> orderSpecifiers){ + return jpaQueryFactory .select(qPost.id) .from(qPost) .where(predicate) - .orderBy(qPost.createdAt.desc()) - .limit(size+1) //하나 더 가져와서 다음 요소가 존재하는지 확인 + .orderBy(orderSpecifiers.toArray(new OrderSpecifier[0])) + .limit(size) .fetch(); + } + private List getMemberLikedPostIds(BooleanBuilder predicate, Integer size, Member member, + List> orderSpecifiers){ + return jpaQueryFactory + .select(qPost.id) + .from(qPost) + .innerJoin(qMemberPostLike).on(qMemberPostLike.post.eq(qPost).and(qMemberPostLike.member.eq(member))) + .where(predicate) + .orderBy(orderSpecifiers.toArray(new OrderSpecifier[0])) + .limit(size) + .fetch(); + } + private List getPostResponsesByIds (List postIds, Member member, + List> orderSpecifiers){ Map postResponseMap = jpaQueryFactory .from(qPost) - .leftJoin(qPost.member, qMember) + .innerJoin(qPost.member, qMember) .leftJoin(qPost.images, qPostImage) .leftJoin(qMemberPostLike).on(qMemberPostLike.post.eq(qPost).and(qMemberPostLike.member.eq(member))) + .innerJoin(qPost.bodyType, qBodyType) .where(qPost.id.in(postIds)) - .orderBy( qPost.createdAt.desc()) + .orderBy(orderSpecifiers.toArray(new OrderSpecifier[0])) .transform(GroupBy.groupBy(qPost.id).as( Projections.constructor(PostResponse.class, qPost.id, @@ -204,87 +211,40 @@ public PostListResponse getMyPosts(Long cursor, Integer size, Member member) { ))); List postResponses = new ArrayList<>(postResponseMap.values()); - - return PostListResponse.of(hasNext.apply(postResponses, size), - postResponses.subList(0, Math.min(size, postResponses.size()))); - } - - private BiFunction , Integer, Boolean> hasNext = (list, size) -> list.size() > size; - - /** - * // 정렬 기준. 특정 바디 타입이 요구되지 않으면 전부 1 - * @param bodyType - * @return - */ - private NumberExpression matchedBodyTypeAsInteger(Optional bodyType){ - if(bodyType.isPresent()){ - return new CaseBuilder() - .when(qPost.bodyType.eq(bodyType.get())).then(1) - .otherwise(0); - } - return Expressions.asNumber(0); - } - - private StringExpression matchedBodyTypeAsString(Optional bodyType){ - if(bodyType.isPresent()){ - return new CaseBuilder() - .when(qPost.bodyType.eq(bodyType.get())).then("1") - .otherwise("0"); - } - return Expressions.asString("0"); + return postResponses; } - private BooleanExpression isLikedResult(Member member){ - return JPAExpressions - .selectFrom(qMemberPostLike) - .where(qMemberPostLike.member.eq(member).and(qMemberPostLike.post.eq(qPost))) - .exists(); - } - - private String createCustomCursor(Post cursor, Optional bodyType){ - if (cursor == null || bodyType == null) { - return null; - } - - String isMatchedBodyType = "0"; - if(bodyType.isPresent()){ - if(cursor.getBodyType().getId().equals(bodyType.get().getId())){ - isMatchedBodyType = "1"; - } - } - - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); - return isMatchedBodyType + String.format("%19s", formatter.format(cursor.getCreatedAt())).replaceAll(" ","0"); - } + private List getLikedPostResponsesByIds (List postIds, Member member){ + Map postResponseMap = jpaQueryFactory + .from(qPost) + .innerJoin(qPost.member, qMember) + .leftJoin(qPost.images, qPostImage) + .innerJoin(qPost.bodyType, qBodyType) + .where(qPost.id.in(postIds)) + .transform(GroupBy.groupBy(qPost.id).as( + Projections.constructor(PostResponse.class, + qPost.id, + qMember.id, + qMember.nickname, + qMember.eq(member), + qPost.content, + qPost.isPublic, + qPost.likeCount, + Expressions.asBoolean(Expressions.TRUE), + qPost.bodyType.name, + GroupBy.list(qPostImage) + ))); - /** - * createdAt을 'YYYYMMDDHHmmss' 로 변환 - * @return - */ - private StringTemplate mySqlDateFormat(){ - return Expressions.stringTemplate( - "CAST(DATE_FORMAT({0}, {1}) AS STRING)", - qPost.createdAt, - ConstantImpl.create("%Y%m%d%H%i%s") - ); + return orderByPostIds(postIds, postResponseMap); } - private StringExpression formatCreatedAt(StringTemplate stringTemplate){ - return StringExpressions.lpad(stringTemplate, 19, '0'); + private List orderByPostIds(List postIds, Map postResponseMap){ + return postIds.stream() + .map(postResponseMap::get) + .filter(Objects::nonNull) + .toList(); } - private BooleanExpression applyCustomCursor(String customCursor, Optional bodyType) { - if (customCursor == null) { // 커서가 없으면 조건 없음 - return null; - } - - // bodyType 순서 계산 - StringExpression isMatchedBodyType = matchedBodyTypeAsString(bodyType); // bodyType 일치 여부 - StringTemplate postCreatedAtTemplate = mySqlDateFormat(); //DATE_FORMAT으로 날짜 형태 변경 - StringExpression formattedCreatedAt = formatCreatedAt(postCreatedAtTemplate); // 날짜 형태 변경을 포맷 - - return isMatchedBodyType.concat(formattedCreatedAt) - .lt(customCursor); - } + private BiFunction , Integer, Boolean> hasNext = (list, size) -> list.size() > size; } From ee7676be24e0563f4baf7e7db9bba52d9c68ef8b Mon Sep 17 00:00:00 2001 From: yunseo02 <154687627+yunseo02@users.noreply.github.com> Date: Tue, 18 Feb 2025 01:27:06 +0900 Subject: [PATCH 12/34] =?UTF-8?q?=E2=9C=A8=20[#132]=20feature:=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=95=84=EC=9B=83=20=EC=9D=B8=EC=A6=9D=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit securityConfig의 인증 url에 로그아웃을 추가하였습니다. --- .../example/mody/domain/member/entity/QMember.java | 4 ++-- .../domain/recommendation/entity/QRecommendation.java | 2 +- .../mody/domain/auth/controller/AuthController.java | 11 +++++------ .../mody/domain/auth/jwt/JwtAuthenticationFilter.java | 4 +++- .../controller/RecommendationController.java | 2 +- .../controller/RecommendationControllerInterface.java | 6 +++--- .../example/mody/global/config/SecurityConfig.java | 2 +- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/generated/com/example/mody/domain/member/entity/QMember.java b/src/main/generated/com/example/mody/domain/member/entity/QMember.java index 51045878..20ef3d23 100644 --- a/src/main/generated/com/example/mody/domain/member/entity/QMember.java +++ b/src/main/generated/com/example/mody/domain/member/entity/QMember.java @@ -60,9 +60,9 @@ public class QMember extends EntityPathBase { public final StringPath providerId = createString("providerId"); - public final ListPath recommendations = this.createList("recommendations", com.example.mody.domain.recommendation.entity.Recommendation.class, com.example.mody.domain.recommendation.entity.QRecommendation.class, PathInits.DIRECT2); + public final ListPath recommendationLikes = this.createList("recommendationLikes", com.example.mody.domain.recommendation.entity.mapping.MemberRecommendationLike.class, com.example.mody.domain.recommendation.entity.mapping.QMemberRecommendationLike.class, PathInits.DIRECT2); - public final ListPath RecommendLikes = this.createList("RecommendLikes", com.example.mody.domain.recommendation.entity.mapping.MemberRecommendationLike.class, com.example.mody.domain.recommendation.entity.mapping.QMemberRecommendationLike.class, PathInits.DIRECT2); + public final ListPath recommendations = this.createList("recommendations", com.example.mody.domain.recommendation.entity.Recommendation.class, com.example.mody.domain.recommendation.entity.QRecommendation.class, PathInits.DIRECT2); public final NumberPath reportCount = createNumber("reportCount", Integer.class); diff --git a/src/main/generated/com/example/mody/domain/recommendation/entity/QRecommendation.java b/src/main/generated/com/example/mody/domain/recommendation/entity/QRecommendation.java index e5e23219..92d17470 100644 --- a/src/main/generated/com/example/mody/domain/recommendation/entity/QRecommendation.java +++ b/src/main/generated/com/example/mody/domain/recommendation/entity/QRecommendation.java @@ -40,7 +40,7 @@ public class QRecommendation extends EntityPathBase { public final com.example.mody.domain.member.entity.QMember member; - public final ListPath RecommendLikes = this.createList("RecommendLikes", com.example.mody.domain.recommendation.entity.mapping.MemberRecommendationLike.class, com.example.mody.domain.recommendation.entity.mapping.QMemberRecommendationLike.class, PathInits.DIRECT2); + public final ListPath recommendationLikes = this.createList("recommendationLikes", com.example.mody.domain.recommendation.entity.mapping.MemberRecommendationLike.class, com.example.mody.domain.recommendation.entity.mapping.QMemberRecommendationLike.class, PathInits.DIRECT2); public final EnumPath recommendType = createEnum("recommendType", com.example.mody.domain.recommendation.enums.RecommendType.class); diff --git a/src/main/java/com/example/mody/domain/auth/controller/AuthController.java b/src/main/java/com/example/mody/domain/auth/controller/AuthController.java index 81780981..5cabc2ce 100644 --- a/src/main/java/com/example/mody/domain/auth/controller/AuthController.java +++ b/src/main/java/com/example/mody/domain/auth/controller/AuthController.java @@ -249,18 +249,17 @@ public BaseResponse reissueToken( ) ), @ApiResponse( - responseCode = "AUTH401", + responseCode = "COMMON401", description = "인증되지 않은 사용자", content = @Content( mediaType = "application/json", examples = @ExampleObject( value = """ { - "timestamp": "2024-01-13T10:00:00", - "code": "AUTH001", - "message": "JWT가 없습니다.", - "result": null - } + "timestamp": "2025-02-17T22:23:22.7640118", + "code": "COMMON401", + "message": "인증이 필요합니다." + } """ ) ) diff --git a/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java b/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java index 8fee4243..19b5ad13 100644 --- a/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java @@ -46,7 +46,9 @@ protected boolean shouldNotFilter(HttpServletRequest request) throws ServletExce uri = uri.substring(contextPath.length()); } log.info("JwtAuthenticationFilter - Request URI after context removal: {}", uri); - boolean skip = uri.startsWith("/auth/") && !uri.startsWith("/auth/signup/complete") || + boolean skip = uri.startsWith("/auth/") + && !uri.startsWith("/auth/signup/complete") + && !uri.startsWith("/auth/logout")|| uri.startsWith("/oauth2/") || uri.startsWith("/email/") || uri.startsWith("/swagger-ui/") || diff --git a/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationController.java b/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationController.java index 0da5e2a8..7ba9cf9b 100644 --- a/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationController.java +++ b/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationController.java @@ -40,7 +40,7 @@ public BaseResponse getStyleCategories() { return BaseResponse.onSuccess(categoryResponse); } - // 스타일 추천 좋아요 + // 추천 좋아요 @PostMapping("/{recommendationId}/like") public BaseResponse toggleStyleLike( @PathVariable(name = "recommendationId") Long recommendationId, diff --git a/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationControllerInterface.java b/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationControllerInterface.java index 8a68a82b..e0f6b48e 100644 --- a/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationControllerInterface.java +++ b/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationControllerInterface.java @@ -30,11 +30,11 @@ public interface RecommendationControllerInterface { BaseResponse getStyleCategories(); - @Operation(summary = "스타일 추천 좋아요 API", description = "스타일 추천에 대한 좋아요 기능") + @Operation(summary = "추천 좋아요 API", description = "추천에 대한 좋아요 기능") @PostMapping("/{recommendationId}/like") @ApiResponses({ - @ApiResponse(responseCode = "COMMON200", description = "스타일 추천에 좋아요 성공"), - @ApiResponse(responseCode = "RECOMMENDATION404", description = "요청한 스타일 추천 결과물이 존재하지 않는 경우") + @ApiResponse(responseCode = "COMMON200", description = "추천에 좋아요 성공"), + @ApiResponse(responseCode = "RECOMMENDATION404", description = "요청한 추천 결과물이 존재하지 않는 경우") }) BaseResponse toggleStyleLike(Long recommendationId,CustomUserDetails customUserDetails); diff --git a/src/main/java/com/example/mody/global/config/SecurityConfig.java b/src/main/java/com/example/mody/global/config/SecurityConfig.java index 5f1c1f6a..b4918dba 100644 --- a/src/main/java/com/example/mody/global/config/SecurityConfig.java +++ b/src/main/java/com/example/mody/global/config/SecurityConfig.java @@ -56,7 +56,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .httpBasic(httpBasic -> httpBasic.disable()) .authorizeHttpRequests(authz -> authz - .requestMatchers("/auth/signup/complete").authenticated() + .requestMatchers("/auth/signup/complete", "/auth/logout").authenticated() .requestMatchers("/auth/**", "/oauth2/**").permitAll() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-ui.html").permitAll() .requestMatchers("/email/**").permitAll() From af58331cc5d144d6004f761a1bb44b53e8b7740e Mon Sep 17 00:00:00 2001 From: yunseo02 <154687627+yunseo02@users.noreply.github.com> Date: Tue, 18 Feb 2025 01:43:01 +0900 Subject: [PATCH 13/34] =?UTF-8?q?=F0=9F=94=A5=20[#132]=20remove:=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C,=20=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 필요없는 부분 정리하였습니다. --- .../auth/controller/AuthController.java | 7 ------ .../controller/RecommendationController.java | 6 ----- .../RecommendationControllerInterface.java | 2 -- .../RecommendationCommendServiceTest.java | 22 ------------------- 4 files changed, 37 deletions(-) delete mode 100644 src/test/java/com/example/mody/domain/recommendation/service/RecommendationCommendServiceTest.java diff --git a/src/main/java/com/example/mody/domain/auth/controller/AuthController.java b/src/main/java/com/example/mody/domain/auth/controller/AuthController.java index 5cabc2ce..1a080f47 100644 --- a/src/main/java/com/example/mody/domain/auth/controller/AuthController.java +++ b/src/main/java/com/example/mody/domain/auth/controller/AuthController.java @@ -1,16 +1,9 @@ package com.example.mody.domain.auth.controller; -import com.example.mody.domain.exception.MemberException; -import com.example.mody.domain.member.entity.Member; -import com.example.mody.global.common.exception.code.status.GlobalErrorStatus; -import com.example.mody.global.common.exception.code.status.MemberErrorStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseCookie; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; diff --git a/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationController.java b/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationController.java index 7ba9cf9b..906e8fed 100644 --- a/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationController.java +++ b/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationController.java @@ -9,12 +9,6 @@ import com.example.mody.domain.recommendation.service.RecommendationCommendService; import com.example.mody.domain.recommendation.service.RecommendationQueryService; import com.example.mody.global.common.base.BaseResponse; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.ExampleObject; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationControllerInterface.java b/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationControllerInterface.java index e0f6b48e..855c1ce2 100644 --- a/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationControllerInterface.java +++ b/src/main/java/com/example/mody/domain/recommendation/controller/RecommendationControllerInterface.java @@ -13,8 +13,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; -import jakarta.validation.Valid; -import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; public interface RecommendationControllerInterface { diff --git a/src/test/java/com/example/mody/domain/recommendation/service/RecommendationCommendServiceTest.java b/src/test/java/com/example/mody/domain/recommendation/service/RecommendationCommendServiceTest.java deleted file mode 100644 index 6ecad9ee..00000000 --- a/src/test/java/com/example/mody/domain/recommendation/service/RecommendationCommendServiceTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.example.mody.domain.recommendation.service; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - - - -class RecommendationCommendServiceTest { - - @Test - void recommendStyle() { - } - - @Test - void recommendFashionItem() { - } - - @Test - void toggleLike() { - } -} \ No newline at end of file From e69986ba8abf925d6db9e953450ffcaf8260e462 Mon Sep 17 00:00:00 2001 From: jher235 Date: Tue, 18 Feb 2025 01:53:17 +0900 Subject: [PATCH 14/34] =?UTF-8?q?:recycle:=20[#131]=20refactor:=20?= =?UTF-8?q?=EB=B9=84=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20-=20=EA=B8=B0=EC=A1=B4=20=EA=B2=8C?= =?UTF-8?q?=EC=8B=9C=EA=B8=80=20=EC=A0=84=EC=B2=B4=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EC=83=81=ED=99=A9=EB=B3=84?= =?UTF-8?q?=EB=A1=9C=20=EB=8B=A4=EB=A5=B8=20=EC=BF=BC=EB=A6=AC=EA=B0=80=20?= =?UTF-8?q?=EB=8F=99=EC=9E=91=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B9=84?= =?UTF-8?q?=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=EC=9D=84=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/service/PostQueryServiceImpl.java | 46 ++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java b/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java index eb61fe50..89f033ee 100644 --- a/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java +++ b/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java @@ -34,19 +34,19 @@ public class PostQueryServiceImpl implements PostQueryService { @Override @Transactional(readOnly = true) public PostListResponse getPosts(Member member, Integer size, Long cursor) { - if(size<=0){ throw new RestApiException(GlobalErrorStatus.NEGATIVE_PAGE_SIZE_REQUEST); } - Optional cursorPost = getCursorPost(cursor); - - if(member != null){ - Optional bodyTypeOptional = bodyTypeService.findLastBodyType(member); - return postRepository.getPostList(cursorPost, size, member, bodyTypeOptional); + Optional bodyTypeOptional = bodyTypeService.findLastBodyType(member); + if(bodyTypeOptional.isEmpty()){ + return getRecentPostResponses(member, size, cursor); } + BodyType userBodyType = bodyTypeOptional.get(); + + Optional cursorPost = getCursorPost(cursor); - return postRepository.getPostList(cursorPost, size, member, Optional.empty()); + return getPostsByBodyType(member, size, cursorPost, userBodyType); } @Override @@ -101,5 +101,37 @@ public PostResponse getPost(Member member, Long postId){ return postResponse; } + private PostListResponse getRecentPostResponses(Member member, Integer size, Long cursor){ + return postRepository.getRecentPosts(cursor, size, member); + } + + private PostListResponse getPostsByBodyType( + Member member, Integer size, Optional cursorPost, BodyType userBodyType){ + // 커서가 존재하지 않거나(== 최초 조회) 커서 post의 바디타입이 유저의 바디타입과 일치하는 경우 + if(cursorPost.isEmpty() || + cursorPost.get().getBodyType().equals(userBodyType)){ + return getBodyTypePosts(member, size, cursorPost, userBodyType); + } + return getOtherBodyTypePosts(member, size,Optional.empty(), userBodyType); + } + + private PostListResponse getBodyTypePosts( + Member member, Integer size, Optional cursorPost, BodyType userBodyType){ + PostListResponse bodyTypePosts = postRepository.getBodyTypePosts(cursorPost, size, member, userBodyType); + + int insufficientCount = size - bodyTypePosts.getPostResponses().size(); + if (insufficientCount > 0){ + PostListResponse otherBodyTypePosts = getOtherBodyTypePosts( + member, insufficientCount,Optional.empty(), userBodyType); + return PostListResponse.of(bodyTypePosts, otherBodyTypePosts); + } + return bodyTypePosts; + } + + private PostListResponse getOtherBodyTypePosts( + Member member, Integer size, Optional cursorPost, BodyType userBodyType){ + return postRepository.getOtherBodyTypePosts(cursorPost, size, member, userBodyType); + } + } From ab9c2b7ef8f541d8be33241a2c48df47888e3329 Mon Sep 17 00:00:00 2001 From: jher235 Date: Tue, 18 Feb 2025 01:57:21 +0900 Subject: [PATCH 15/34] =?UTF-8?q?:recycle:=20[#131]=20refactor:=202?= =?UTF-8?q?=EA=B0=80=EC=A7=80=20PostResponses=EB=A5=BC=20=EB=B3=91?= =?UTF-8?q?=ED=95=A9=ED=95=98=EB=8A=94=20of=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{PostListResponse.java => PostResponses.java} | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) rename src/main/java/com/example/mody/domain/post/dto/response/{PostListResponse.java => PostResponses.java} (68%) diff --git a/src/main/java/com/example/mody/domain/post/dto/response/PostListResponse.java b/src/main/java/com/example/mody/domain/post/dto/response/PostResponses.java similarity index 68% rename from src/main/java/com/example/mody/domain/post/dto/response/PostListResponse.java rename to src/main/java/com/example/mody/domain/post/dto/response/PostResponses.java index 7186a315..ae95fde1 100644 --- a/src/main/java/com/example/mody/domain/post/dto/response/PostListResponse.java +++ b/src/main/java/com/example/mody/domain/post/dto/response/PostResponses.java @@ -27,6 +27,14 @@ public static PostListResponse of(Boolean hasNext, List postRespon */ public static PostListResponse of(Boolean hasNext, List postResponses, Long cursor){ Long newCursor = hasNext ? cursor : null; - return new PostListResponse(postResponses, new CursorPagination(hasNext, newCursor)); + return new PostResponses(postResponses, new CursorPagination(hasNext, newCursor)); + } + + public static PostResponses of(PostResponses firstPosts, PostResponses secondPosts){ + List newPostResponses = new ArrayList<>( + firstPosts.getPostResponses().size() + secondPosts.getPostResponses().size()); + newPostResponses.addAll(firstPosts.getPostResponses()); + newPostResponses.addAll(secondPosts.getPostResponses()); + return new PostResponses(newPostResponses, secondPosts.cursorPagination); } } From 40aa4155df1b097ab18108f7d05a397ca7e925ae Mon Sep 17 00:00:00 2001 From: jher235 Date: Tue, 18 Feb 2025 01:58:49 +0900 Subject: [PATCH 16/34] =?UTF-8?q?:recycle:=20[#131]=20refactor:=20PostResp?= =?UTF-8?q?onses=20=EB=A1=9C=20response=20dto=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20-=20=EA=B8=B0=EC=A1=B4=20PostListResponse?= =?UTF-8?q?=20=EB=B3=B4=EB=8B=A4=20PostResponses=20=EA=B0=80=20=ED=86=B5?= =?UTF-8?q?=EC=9D=BC=EC=84=B1=EC=9E=88=EB=8B=A4=EA=B3=A0=20=ED=8C=90?= =?UTF-8?q?=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/controller/PostController.java | 24 ++++++++----------- .../post/dto/response/PostResponses.java | 9 +++---- .../post/repository/PostCustomRepository.java | 10 ++++---- .../repository/PostCustomRepositoryImpl.java | 24 +++++++------------ .../domain/post/service/PostQueryService.java | 8 +++---- .../post/service/PostQueryServiceImpl.java | 24 +++++++++---------- 6 files changed, 45 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/example/mody/domain/post/controller/PostController.java b/src/main/java/com/example/mody/domain/post/controller/PostController.java index 3daf39fd..10234c69 100644 --- a/src/main/java/com/example/mody/domain/post/controller/PostController.java +++ b/src/main/java/com/example/mody/domain/post/controller/PostController.java @@ -1,11 +1,9 @@ package com.example.mody.domain.post.controller; -import com.example.mody.domain.member.entity.Member; import com.example.mody.domain.member.repository.MemberRepository; import com.example.mody.domain.post.dto.request.PostUpdateRequest; import com.example.mody.domain.post.dto.response.PostResponse; -import com.example.mody.domain.post.entity.Post; import io.swagger.v3.oas.annotations.Parameters; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -20,9 +18,8 @@ import org.springframework.web.bind.annotation.RestController; import com.example.mody.domain.auth.security.CustomUserDetails; -import com.example.mody.domain.member.repository.MemberRepository; import com.example.mody.domain.post.dto.request.PostCreateRequest; -import com.example.mody.domain.post.dto.response.PostListResponse; +import com.example.mody.domain.post.dto.response.PostResponses; import com.example.mody.domain.post.exception.annotation.ExistsPost; import com.example.mody.domain.post.service.PostCommandService; import com.example.mody.domain.post.service.PostQueryService; @@ -30,7 +27,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.annotations.media.Schema; @@ -61,12 +57,12 @@ public class PostController { description = "게시글 목록 조회 성공" ) }) - public BaseResponse getAllPosts( + public BaseResponse getAllPosts( @AuthenticationPrincipal CustomUserDetails customUserDetails, @RequestParam(name = "cursor", required = false) Long cursor, @RequestParam(name = "size", defaultValue = "15") Integer size) { - PostListResponse postListResponse = postQueryService.getPosts(customUserDetails.getMember(), size, cursor); - return BaseResponse.onSuccess(postListResponse); + PostResponses postResponses = postQueryService.getPosts(customUserDetails.getMember(), size, cursor); + return BaseResponse.onSuccess(postResponses); } /** @@ -272,12 +268,12 @@ public BaseResponse togglePostLike( description = "게시글 목록 조회 성공" ) }) - public BaseResponse getLikedPosts( + public BaseResponse getLikedPosts( @AuthenticationPrincipal CustomUserDetails customUserDetails, @RequestParam(name = "cursor", required = false) Long cursor, @RequestParam(name = "size", defaultValue = "15") Integer size) { - PostListResponse postListResponse = postQueryService.getLikedPosts(customUserDetails.getMember(), size, cursor); - return BaseResponse.onSuccess(postListResponse); + PostResponses postResponses = postQueryService.getLikedPosts(customUserDetails.getMember(), size, cursor); + return BaseResponse.onSuccess(postResponses); } @GetMapping("/me") @@ -288,12 +284,12 @@ public BaseResponse getLikedPosts( description = "게시글 목록 조회 성공" ) }) - public BaseResponse getMyPosts( + public BaseResponse getMyPosts( @AuthenticationPrincipal CustomUserDetails customUserDetails, @RequestParam(name = "cursor", required = false) Long cursor, @RequestParam(name = "size", defaultValue = "15") Integer size) { - PostListResponse postListResponse = postQueryService.getMyPosts(customUserDetails.getMember(), size, cursor); - return BaseResponse.onSuccess(postListResponse); + PostResponses postResponses = postQueryService.getMyPosts(customUserDetails.getMember(), size, cursor); + return BaseResponse.onSuccess(postResponses); } @PostMapping("/{postId}/reports") diff --git a/src/main/java/com/example/mody/domain/post/dto/response/PostResponses.java b/src/main/java/com/example/mody/domain/post/dto/response/PostResponses.java index ae95fde1..75a531e3 100644 --- a/src/main/java/com/example/mody/domain/post/dto/response/PostResponses.java +++ b/src/main/java/com/example/mody/domain/post/dto/response/PostResponses.java @@ -5,17 +5,18 @@ import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.ArrayList; import java.util.List; @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) -public class PostListResponse { +public class PostResponses { private List postResponses; private CursorPagination cursorPagination; - public static PostListResponse of(Boolean hasNext, List postResponses){ + public static PostResponses of(Boolean hasNext, List postResponses){ Long cursor = hasNext ? postResponses.getLast().getPostId() : null; - return new PostListResponse(postResponses, new CursorPagination(hasNext, cursor)); + return new PostResponses(postResponses, new CursorPagination(hasNext, cursor)); } /** @@ -25,7 +26,7 @@ public static PostListResponse of(Boolean hasNext, List postRespon * @param cursor 반환하는 게시물 중 마지막 게시물과 클라이언트에 대한 likeId * @return */ - public static PostListResponse of(Boolean hasNext, List postResponses, Long cursor){ + public static PostResponses of(Boolean hasNext, List postResponses, Long cursor){ Long newCursor = hasNext ? cursor : null; return new PostResponses(postResponses, new CursorPagination(hasNext, newCursor)); } diff --git a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepository.java b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepository.java index a2ef262d..863a3f1c 100644 --- a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepository.java +++ b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepository.java @@ -2,7 +2,7 @@ import com.example.mody.domain.bodytype.entity.BodyType; import com.example.mody.domain.member.entity.Member; -import com.example.mody.domain.post.dto.response.PostListResponse; +import com.example.mody.domain.post.dto.response.PostResponses; import com.example.mody.domain.post.dto.response.recode.LikedPostsResponse; import com.example.mody.domain.post.entity.Post; @@ -10,10 +10,10 @@ public interface PostCustomRepository { - public PostListResponse getBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType); - public PostListResponse getOtherBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType); + public PostResponses getBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType); + public PostResponses getOtherBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType); public LikedPostsResponse getLikedPosts(Long cursor, Integer size, Member member); - public PostListResponse getMyPosts(Long cursor, Integer size, Member member); - public PostListResponse getRecentPosts(Long cursor, Integer size, Member member); + public PostResponses getMyPosts(Long cursor, Integer size, Member member); + public PostResponses getRecentPosts(Long cursor, Integer size, Member member); } diff --git a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java index 4d4350bb..ef648179 100644 --- a/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java +++ b/src/main/java/com/example/mody/domain/post/repository/PostCustomRepositoryImpl.java @@ -4,7 +4,7 @@ import com.example.mody.domain.bodytype.entity.QBodyType; import com.example.mody.domain.member.entity.Member; import com.example.mody.domain.member.entity.QMember; -import com.example.mody.domain.post.dto.response.PostListResponse; +import com.example.mody.domain.post.dto.response.PostResponses; import com.example.mody.domain.post.dto.response.PostResponse; import com.example.mody.domain.post.dto.response.recode.LikedPostsResponse; import com.example.mody.domain.post.entity.Post; @@ -13,21 +13,15 @@ import com.example.mody.domain.post.entity.mapping.QMemberPostLike; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.group.GroupBy; -import com.querydsl.core.types.ConstantImpl; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.*; -import com.querydsl.core.types.dsl.StringTemplate; -import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.impl.JPAQueryFactory; -import jakarta.persistence.QueryHint; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.hibernate.annotations.QueryHints; import org.springframework.stereotype.Repository; -import java.time.format.DateTimeFormatter; import java.util.*; import java.util.function.BiFunction; @@ -54,7 +48,7 @@ public class PostCustomRepositoryImpl implements PostCustomRepository{ * @return */ @Override - public PostListResponse getBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType) { + public PostResponses getBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType) { BooleanBuilder predicate = new BooleanBuilder(); predicate.and(qPost.isPublic.eq(true)); // 공개여부 == true @@ -72,12 +66,12 @@ public PostListResponse getBodyTypePosts(Optional cursorPost, Integer size List postResponses = getPostResponsesByIds(postIds, member, orderSpecifiers); // 여기서는 목록 개수가 size 개수와 동일한 경우도 hasNext가 true임. - return PostListResponse.of(hasNext.apply(postResponses, size-1), + return PostResponses.of(hasNext.apply(postResponses, size-1), postResponses.subList(0, Math.min(size, postResponses.size()))); } @Override - public PostListResponse getOtherBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType) { + public PostResponses getOtherBodyTypePosts(Optional cursorPost, Integer size, Member member, BodyType bodyType) { BooleanBuilder predicate = new BooleanBuilder(); predicate.and(qPost.isPublic.eq(true)); // 공개여부 == true @@ -94,7 +88,7 @@ public PostListResponse getOtherBodyTypePosts(Optional cursorPost, Integer List postIds = getPostIds(predicate, size+1, orderSpecifiers); //하나 더 가져와서 다음 요소가 존재하는지 확인 List postResponses = getPostResponsesByIds(postIds, member, orderSpecifiers); - return PostListResponse.of(hasNext.apply(postResponses, size), + return PostResponses.of(hasNext.apply(postResponses, size), postResponses.subList(0, Math.min(size, postResponses.size()))); } @@ -125,7 +119,7 @@ public LikedPostsResponse getLikedPosts(Long cursor, Integer size, Member member } @Override - public PostListResponse getMyPosts(Long cursor, Integer size, Member member) { + public PostResponses getMyPosts(Long cursor, Integer size, Member member) { BooleanBuilder predicate = new BooleanBuilder(); predicate.and(qPost.member.eq(member)); @@ -140,12 +134,12 @@ public PostListResponse getMyPosts(Long cursor, Integer size, Member member) { List postIds = getPostIds(predicate, size+1, orderSpecifiers); List postResponses = getPostResponsesByIds(postIds, member, orderSpecifiers); - return PostListResponse.of(hasNext.apply(postResponses, size), + return PostResponses.of(hasNext.apply(postResponses, size), postResponses.subList(0, Math.min(size, postResponses.size()))); } @Override - public PostListResponse getRecentPosts(Long cursor, Integer size, Member member) { + public PostResponses getRecentPosts(Long cursor, Integer size, Member member) { BooleanBuilder predicate = new BooleanBuilder(); predicate.and(qPost.isPublic.eq(true)); @@ -160,7 +154,7 @@ public PostListResponse getRecentPosts(Long cursor, Integer size, Member member) List postIds = getPostIds(predicate, size+1, orderSpecifiers); List postResponses = getPostResponsesByIds(postIds, member, orderSpecifiers); - return PostListResponse.of(hasNext.apply(postResponses, size), + return PostResponses.of(hasNext.apply(postResponses, size), postResponses.subList(0, Math.min(size, postResponses.size()))); } diff --git a/src/main/java/com/example/mody/domain/post/service/PostQueryService.java b/src/main/java/com/example/mody/domain/post/service/PostQueryService.java index 430729be..34cd1581 100644 --- a/src/main/java/com/example/mody/domain/post/service/PostQueryService.java +++ b/src/main/java/com/example/mody/domain/post/service/PostQueryService.java @@ -1,12 +1,12 @@ package com.example.mody.domain.post.service; import com.example.mody.domain.member.entity.Member; -import com.example.mody.domain.post.dto.response.PostListResponse; +import com.example.mody.domain.post.dto.response.PostResponses; import com.example.mody.domain.post.dto.response.PostResponse; public interface PostQueryService { - public PostListResponse getPosts(Member member, Integer size, Long cursor); - public PostListResponse getLikedPosts(Member member, Integer size, Long cursor); - public PostListResponse getMyPosts(Member member, Integer size, Long cursor); + public PostResponses getPosts(Member member, Integer size, Long cursor); + public PostResponses getLikedPosts(Member member, Integer size, Long cursor); + public PostResponses getMyPosts(Member member, Integer size, Long cursor); public PostResponse getPost(Member member, Long postId); } diff --git a/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java b/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java index 89f033ee..8531fa7c 100644 --- a/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java +++ b/src/main/java/com/example/mody/domain/post/service/PostQueryServiceImpl.java @@ -4,7 +4,7 @@ import com.example.mody.domain.bodytype.service.BodyTypeService; import com.example.mody.domain.exception.PostException; import com.example.mody.domain.member.entity.Member; -import com.example.mody.domain.post.dto.response.PostListResponse; +import com.example.mody.domain.post.dto.response.PostResponses; import com.example.mody.domain.post.dto.response.PostResponse; import com.example.mody.domain.post.dto.response.recode.LikedPostsResponse; import com.example.mody.domain.post.entity.Post; @@ -33,7 +33,7 @@ public class PostQueryServiceImpl implements PostQueryService { @Override @Transactional(readOnly = true) - public PostListResponse getPosts(Member member, Integer size, Long cursor) { + public PostResponses getPosts(Member member, Integer size, Long cursor) { if(size<=0){ throw new RestApiException(GlobalErrorStatus.NEGATIVE_PAGE_SIZE_REQUEST); } @@ -51,7 +51,7 @@ public PostListResponse getPosts(Member member, Integer size, Long cursor) { @Override @Transactional(readOnly = true) - public PostListResponse getLikedPosts(Member member, Integer size, Long cursor) { + public PostResponses getLikedPosts(Member member, Integer size, Long cursor) { if(size<=0){ throw new RestApiException(GlobalErrorStatus.NEGATIVE_PAGE_SIZE_REQUEST); } @@ -63,12 +63,12 @@ public PostListResponse getLikedPosts(Member member, Integer size, Long cursor) nextLike = Optional.ofNullable(findByMemberAndPostId(member, postResponse.getPostId()).getId()); } - return PostListResponse.of(likedPostsResponse.hasNext(), likedPostsResponse.postResponses(), nextLike.orElse(null)); + return PostResponses.of(likedPostsResponse.hasNext(), likedPostsResponse.postResponses(), nextLike.orElse(null)); } @Override @Transactional(readOnly = true) - public PostListResponse getMyPosts(Member member, Integer size, Long cursor) { + public PostResponses getMyPosts(Member member, Integer size, Long cursor) { if(size<=0){ throw new RestApiException(GlobalErrorStatus.NEGATIVE_PAGE_SIZE_REQUEST); } @@ -101,11 +101,11 @@ public PostResponse getPost(Member member, Long postId){ return postResponse; } - private PostListResponse getRecentPostResponses(Member member, Integer size, Long cursor){ + private PostResponses getRecentPostResponses(Member member, Integer size, Long cursor){ return postRepository.getRecentPosts(cursor, size, member); } - private PostListResponse getPostsByBodyType( + private PostResponses getPostsByBodyType( Member member, Integer size, Optional cursorPost, BodyType userBodyType){ // 커서가 존재하지 않거나(== 최초 조회) 커서 post의 바디타입이 유저의 바디타입과 일치하는 경우 if(cursorPost.isEmpty() || @@ -115,20 +115,20 @@ private PostListResponse getPostsByBodyType( return getOtherBodyTypePosts(member, size,Optional.empty(), userBodyType); } - private PostListResponse getBodyTypePosts( + private PostResponses getBodyTypePosts( Member member, Integer size, Optional cursorPost, BodyType userBodyType){ - PostListResponse bodyTypePosts = postRepository.getBodyTypePosts(cursorPost, size, member, userBodyType); + PostResponses bodyTypePosts = postRepository.getBodyTypePosts(cursorPost, size, member, userBodyType); int insufficientCount = size - bodyTypePosts.getPostResponses().size(); if (insufficientCount > 0){ - PostListResponse otherBodyTypePosts = getOtherBodyTypePosts( + PostResponses otherBodyTypePosts = getOtherBodyTypePosts( member, insufficientCount,Optional.empty(), userBodyType); - return PostListResponse.of(bodyTypePosts, otherBodyTypePosts); + return PostResponses.of(bodyTypePosts, otherBodyTypePosts); } return bodyTypePosts; } - private PostListResponse getOtherBodyTypePosts( + private PostResponses getOtherBodyTypePosts( Member member, Integer size, Optional cursorPost, BodyType userBodyType){ return postRepository.getOtherBodyTypePosts(cursorPost, size, member, userBodyType); } From e5a10c1fc29b68d535ce3922c81fd86c660b11c1 Mon Sep 17 00:00:00 2001 From: jher235 Date: Tue, 18 Feb 2025 02:00:03 +0900 Subject: [PATCH 17/34] =?UTF-8?q?:sparkles:=20[#131]=20feature:=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=20=EB=B9=84=EA=B5=90=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20equals=20=EB=B0=8F=20hashcode=20=EC=98=A4=EB=B2=84?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mody/domain/bodytype/entity/BodyType.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/com/example/mody/domain/bodytype/entity/BodyType.java b/src/main/java/com/example/mody/domain/bodytype/entity/BodyType.java index 217032a5..09659fcb 100644 --- a/src/main/java/com/example/mody/domain/bodytype/entity/BodyType.java +++ b/src/main/java/com/example/mody/domain/bodytype/entity/BodyType.java @@ -1,6 +1,7 @@ package com.example.mody.domain.bodytype.entity; import com.example.mody.domain.bodytype.entity.mapping.MemberBodyType; +import com.example.mody.domain.member.entity.Member; import com.example.mody.global.common.base.BaseEntity; import jakarta.persistence.*; import lombok.*; @@ -9,6 +10,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; @Entity @Getter @@ -30,4 +32,20 @@ public class BodyType extends BaseEntity { @OneToMany(mappedBy = "bodyType", cascade = CascadeType.ALL) private List memberBodyTypeList = new ArrayList<>(); + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (!(o instanceof BodyType that)) { + return false; + } + return Objects.equals(that.getId(), this.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } } \ No newline at end of file From 86fc09121a8181f13c3efa9096a2ab2a1fbc8d0d Mon Sep 17 00:00:00 2001 From: jher235 Date: Tue, 18 Feb 2025 02:00:24 +0900 Subject: [PATCH 18/34] =?UTF-8?q?:sparkles:=20[#131]=20feature:=20idx=5Fme?= =?UTF-8?q?mber=5Fpost=20=EC=9D=B8=EB=8D=B1=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/entity/mapping/MemberPostLike.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/example/mody/domain/post/entity/mapping/MemberPostLike.java b/src/main/java/com/example/mody/domain/post/entity/mapping/MemberPostLike.java index 0595a9b0..8ea98ce7 100644 --- a/src/main/java/com/example/mody/domain/post/entity/mapping/MemberPostLike.java +++ b/src/main/java/com/example/mody/domain/post/entity/mapping/MemberPostLike.java @@ -1,5 +1,6 @@ package com.example.mody.domain.post.entity.mapping; +import jakarta.persistence.*; import org.hibernate.annotations.DynamicInsert; import org.hibernate.annotations.DynamicUpdate; @@ -7,15 +8,6 @@ import com.example.mody.domain.post.entity.Post; import com.example.mody.global.common.base.BaseEntity; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -29,7 +21,10 @@ @AllArgsConstructor @DynamicInsert @DynamicUpdate -@Table(name = "member_post_like") +@Table(name = "member_post_like", indexes = { + @Index(name = "idx_member_post", + columnList = "member_id, post_id") +}) public class MemberPostLike extends BaseEntity { @Id From e56e690b73c4c166d38f7d16926637924544d6b1 Mon Sep 17 00:00:00 2001 From: jher235 Date: Tue, 18 Feb 2025 02:00:40 +0900 Subject: [PATCH 19/34] =?UTF-8?q?:sparkles:=20[#131]=20feature:=20idx=5Fbo?= =?UTF-8?q?dytype=5Fpost,=20idx=5Fmember=5Fpost=20=EC=9D=B8=EB=8D=B1?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/mody/domain/post/entity/Post.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/example/mody/domain/post/entity/Post.java b/src/main/java/com/example/mody/domain/post/entity/Post.java index e9152b31..c6335cec 100644 --- a/src/main/java/com/example/mody/domain/post/entity/Post.java +++ b/src/main/java/com/example/mody/domain/post/entity/Post.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.DynamicUpdate; @@ -13,22 +14,15 @@ import com.example.mody.domain.post.entity.mapping.MemberPostLike; import com.example.mody.global.common.base.BaseEntity; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; - @Entity(name = "post") @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table(name = "post") +@Table(name = "post", indexes = { + @Index(name = "idx_bodytype_post", + columnList = "body_type_id, post_id"), + @Index(name = "idx_member_post", + columnList = "member_id, post_id") +}) @DynamicUpdate public class Post extends BaseEntity { From 48aa44626f943128105dc326d20ee8833b329583 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 16:20:51 +0900 Subject: [PATCH 20/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=20refactor:=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bodytype/controller/BodyTypeController.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeController.java b/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeController.java index 5e3ca045..df23c4a8 100644 --- a/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeController.java +++ b/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeController.java @@ -9,7 +9,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.ExampleObject; -import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; @@ -87,16 +86,6 @@ public BaseResponse analyzeBodyType( return BaseResponse.onSuccess(memberBodyTypeCommandService.analyzeBodyType(customUserDetails.getMember(), request.getAnswer())); } -// @GetMapping() -// @Operation(summary = "체형 질문 문항 조회 API - 프론트와 협의 필요(API 연동 안 해도 됨)", -// description = "체형 분석을 하기 위해 질문 문항을 받아 오는 API입니다. 이 부분은 서버에서 바로 프롬프트로 넣는 방법도 있기 때문에 프론트와 협의 후 진행하겠습니다.") -// @ApiResponses({ -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200",description = "OK, 성공") -// }) -// public BaseResponse getQuestion() { -// return BaseResponse.onSuccess(null); -// } - @GetMapping("/result") @Operation(summary = "체형 분석 결과 조회 API", description = "사용자의 체형 분석 결과를 받아 오는 API입니다.") @ApiResponses({ From 6daec9b8990271f815a2d7202f1da11bdff4a1e1 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 16:37:31 +0900 Subject: [PATCH 21/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20refactor:?= =?UTF-8?q?=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=B1=85=EC=9E=84=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 스웨거 명세와 실제 로직을 분리하기 위해 인터페이스를 도입하였습니다. --- .../controller/BodyTypeController.java | 112 +--------------- .../BodyTypeControllerInterface.java | 124 ++++++++++++++++++ 2 files changed, 127 insertions(+), 109 deletions(-) create mode 100644 src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeControllerInterface.java diff --git a/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeController.java b/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeController.java index df23c4a8..1d32797c 100644 --- a/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeController.java +++ b/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeController.java @@ -7,78 +7,23 @@ import com.example.mody.domain.bodytype.service.memberbodytype.MemberBodyTypeQueryService; import com.example.mody.global.common.base.BaseResponse; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.ExampleObject; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; -@Tag(name = "체형 분석", description = "체형 분석 API") +@Tag(name = "체형 분석", description = "체형 분석 관련 API") @RestController @RequestMapping("/body-analysis") @RequiredArgsConstructor -public class BodyTypeController { +public class BodyTypeController implements BodyTypeControllerInterface { private final MemberBodyTypeCommandService memberBodyTypeCommandService; private final MemberBodyTypeQueryService memberBodyTypeQueryService; @PostMapping("/result") - @Operation(summary = "체형 분석 API", description = "OpenAi를 사용해서 사용자의 체형을 분석하는 API입니다. Request Body에는 질문에 맞는 답변 목록을 보내주세요.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",description = "체형 분석 성공"), - @ApiResponse( - responseCode = "401", - description = "Access Token이 필요합니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "COMMON401", - "message": "인증이 필요합니다." - } - """ - ) - ) - ), - @ApiResponse( - responseCode = "404", - description = "체형을 찾을 수 없습니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "BODY_TYPE404", - "message": "체형을 찾을 수 없습니다." - } - """ - ) - ) - ), - @ApiResponse( - responseCode = "500", - description = "GPT가 적절한 응답을 하지 못 했습니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "ANALYSIS108", - "message": "GPT가 올바르지 않은 답변을 했습니다. 관리자에게 문의하세요." - } - """ - ) - ) - ), - }) + @Operation(summary = "체형 분석 API", description = "OpenAI를 사용해서 사용자의 체형을 분석하는 API입니다. Request Body에는 질문에 맞는 답변 목록을 보내주세요.") public BaseResponse analyzeBodyType( @AuthenticationPrincipal CustomUserDetails customUserDetails, @Valid @RequestBody BodyTypeAnalysisRequest request @@ -88,57 +33,6 @@ public BaseResponse analyzeBodyType( @GetMapping("/result") @Operation(summary = "체형 분석 결과 조회 API", description = "사용자의 체형 분석 결과를 받아 오는 API입니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",description = "체형 분석 결과 조회 성공"), - @ApiResponse( - responseCode = "400", - description = "체형 분석 결과를 처리하는 중 JSON 파싱에 실패했습니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "JSON_PARSING400", - "message": "체형 분석 결과를 처리하는 중 JSON 파싱에 실패했습니다." - } - """ - ) - ) - ), - @ApiResponse( - responseCode = "401", - description = "Access Token이 필요합니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "COMMON401", - "message": "인증이 필요합니다." - } - """ - ) - ) - ), - @ApiResponse( - responseCode = "404", - description = "체형 분석 결과를 찾을 수 없습니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "MEMBER_BODY_TYPE404", - "message": "체형 분석 결과를 찾을 수 없습니다." - } - """ - ) - ) - ), - }) public BaseResponse getBodyType(@AuthenticationPrincipal CustomUserDetails customUserDetails) { return BaseResponse.onSuccess(memberBodyTypeQueryService.getBodyTypeAnalysis(customUserDetails.getMember())); } diff --git a/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeControllerInterface.java b/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeControllerInterface.java new file mode 100644 index 00000000..7928eb6a --- /dev/null +++ b/src/main/java/com/example/mody/domain/bodytype/controller/BodyTypeControllerInterface.java @@ -0,0 +1,124 @@ +package com.example.mody.domain.bodytype.controller; + +import com.example.mody.domain.auth.security.CustomUserDetails; +import com.example.mody.domain.bodytype.dto.request.BodyTypeAnalysisRequest; +import com.example.mody.domain.bodytype.dto.response.BodyTypeAnalysisResponse; +import com.example.mody.global.common.base.BaseResponse; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.validation.Valid; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.RequestBody; + +public interface BodyTypeControllerInterface { + + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "체형 분석 성공"), + @ApiResponse( + responseCode = "401", + description = "Access Token이 필요합니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "COMMON401", + "message": "인증이 필요합니다." + } + """ + ) + ) + ), + @ApiResponse( + responseCode = "404", + description = "체형을 찾을 수 없습니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "BODY_TYPE404", + "message": "체형을 찾을 수 없습니다." + } + """ + ) + ) + ), + @ApiResponse( + responseCode = "500", + description = "GPT가 적절한 응답을 하지 못 했습니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "ANALYSIS108", + "message": "GPT가 올바르지 않은 답변을 했습니다. 관리자에게 문의하세요." + } + """ + ) + ) + ), + }) + BaseResponse analyzeBodyType( + @AuthenticationPrincipal CustomUserDetails customUserDetails, + @Valid @RequestBody BodyTypeAnalysisRequest request); + + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",description = "체형 분석 결과 조회 성공"), + @ApiResponse( + responseCode = "400", + description = "체형 분석 결과를 처리하는 중 JSON 파싱에 실패했습니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "JSON_PARSING400", + "message": "체형 분석 결과를 처리하는 중 JSON 파싱에 실패했습니다." + } + """ + ) + ) + ), + @ApiResponse( + responseCode = "401", + description = "Access Token이 필요합니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "COMMON401", + "message": "인증이 필요합니다." + } + """ + ) + ) + ), + @ApiResponse( + responseCode = "404", + description = "체형 분석 결과를 찾을 수 없습니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "MEMBER_BODY_TYPE404", + "message": "체형 분석 결과를 찾을 수 없습니다." + } + """ + ) + ) + ), + }) + BaseResponse getBodyType(@AuthenticationPrincipal CustomUserDetails customUserDetails); +} From 8cb21c08ae16945a00bc48d6f0c6bd2ab0893080 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 16:41:15 +0900 Subject: [PATCH 22/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20=ED=95=84?= =?UTF-8?q?=EC=9A=94=20=EC=97=86=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/bodytype/dto/request/BodyTypeAnalysisRequest.java | 2 -- .../domain/bodytype/repository/MemberBodyTypeRepository.java | 1 - .../service/memberbodytype/MemberBodyTypeCommandService.java | 2 +- .../service/memberbodytype/MemberBodyTypeQueryService.java | 4 ++-- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/mody/domain/bodytype/dto/request/BodyTypeAnalysisRequest.java b/src/main/java/com/example/mody/domain/bodytype/dto/request/BodyTypeAnalysisRequest.java index 7845d86d..dfd66d1f 100644 --- a/src/main/java/com/example/mody/domain/bodytype/dto/request/BodyTypeAnalysisRequest.java +++ b/src/main/java/com/example/mody/domain/bodytype/dto/request/BodyTypeAnalysisRequest.java @@ -5,8 +5,6 @@ import lombok.NoArgsConstructor; import lombok.Setter; -import java.util.List; - /** * 체형 분석 요청 DTO */ diff --git a/src/main/java/com/example/mody/domain/bodytype/repository/MemberBodyTypeRepository.java b/src/main/java/com/example/mody/domain/bodytype/repository/MemberBodyTypeRepository.java index fc6af18b..fc398cab 100644 --- a/src/main/java/com/example/mody/domain/bodytype/repository/MemberBodyTypeRepository.java +++ b/src/main/java/com/example/mody/domain/bodytype/repository/MemberBodyTypeRepository.java @@ -10,7 +10,6 @@ @Repository public interface MemberBodyTypeRepository extends JpaRepository { Optional findTopByMemberOrderByCreatedAt(Member member); - Optional findMemberBodyTypeByMember(Member member); Long countAllByMember(Member member); Optional findTopByMemberOrderByCreatedAtDesc(Member member); } diff --git a/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeCommandService.java b/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeCommandService.java index f89dc89a..7fe2ec12 100644 --- a/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeCommandService.java +++ b/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeCommandService.java @@ -4,5 +4,5 @@ import com.example.mody.domain.member.entity.Member; public interface MemberBodyTypeCommandService { - public BodyTypeAnalysisResponse analyzeBodyType(Member member, String answers); + BodyTypeAnalysisResponse analyzeBodyType(Member member, String answers); } diff --git a/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeQueryService.java b/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeQueryService.java index 9d394ff0..d7d9ec36 100644 --- a/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeQueryService.java +++ b/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeQueryService.java @@ -5,7 +5,7 @@ import com.example.mody.domain.member.entity.Member; public interface MemberBodyTypeQueryService { - public BodyTypeAnalysisResponse getBodyTypeAnalysis(Member member); + BodyTypeAnalysisResponse getBodyTypeAnalysis(Member member); - public MemberBodyType getMemberBodyType(Member member); + MemberBodyType getMemberBodyType(Member member); } From 0ae8c944ca7e636d3d38d49a61fdf586dab2aae1 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 16:55:34 +0900 Subject: [PATCH 23/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20=EC=B2=B4?= =?UTF-8?q?=ED=98=95=20=EB=B6=84=EC=84=9D=20API=20=EC=B5=9C=EC=A0=81?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bodytype/service/bodytype/BodyTypeQueryServiceImpl.java | 5 ++--- .../memberbodytype/MemberBodyTypeCommandServiceImpl.java | 5 +---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/mody/domain/bodytype/service/bodytype/BodyTypeQueryServiceImpl.java b/src/main/java/com/example/mody/domain/bodytype/service/bodytype/BodyTypeQueryServiceImpl.java index b5d66e5d..6264f19b 100644 --- a/src/main/java/com/example/mody/domain/bodytype/service/bodytype/BodyTypeQueryServiceImpl.java +++ b/src/main/java/com/example/mody/domain/bodytype/service/bodytype/BodyTypeQueryServiceImpl.java @@ -18,8 +18,7 @@ public class BodyTypeQueryServiceImpl implements BodyTypeQueryService { // 체형 이름으로 BodyType 클래스 조회 @Override public BodyType findByBodyTypeName(String bodyTypeName) { - Optional optionalBodyType = bodyTypeRepository.findByName(bodyTypeName); - BodyType bodyType = optionalBodyType.orElseThrow(()-> new BodyTypeException(BodyTypeErrorStatus.BODY_TYPE_NOT_FOUND)); - return bodyType; + return bodyTypeRepository.findByName(bodyTypeName) + .orElseThrow(() -> new BodyTypeException(BodyTypeErrorStatus.BODY_TYPE_NOT_FOUND)); } } diff --git a/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeCommandServiceImpl.java b/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeCommandServiceImpl.java index 8ebd2b92..fe57be42 100644 --- a/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeCommandServiceImpl.java +++ b/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeCommandServiceImpl.java @@ -23,12 +23,9 @@ public class MemberBodyTypeCommandServiceImpl implements MemberBodyTypeCommandSe @Override public BodyTypeAnalysisResponse analyzeBodyType(Member member, String answers) { - // 사용자 정보(닉네임, 성별) 조회 - String nickname = member.getNickname(); - Gender gender = member.getGender(); // OpenAi API를 통한 체형 분석 - String content = chatGptService.getContent(nickname, gender, answers); + String content = chatGptService.getContent(member.getNickname(), member.getGender(), answers); BodyTypeAnalysisResponse bodyTypeAnalysisResponse = chatGptService.analyzeBodyType(content); // MemberBodyType을 DB에 저장 From 1e9f9b8d1f876ca9fca0aa01d948aee75a583d08 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 17:04:13 +0900 Subject: [PATCH 24/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20=EC=B2=B4?= =?UTF-8?q?=ED=98=95=20=EB=B6=84=EC=84=9D=20=EA=B2=B0=EA=B3=BC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20API=20=EC=B5=9C=EC=A0=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../memberbodytype/MemberBodyTypeQueryServiceImpl.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeQueryServiceImpl.java b/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeQueryServiceImpl.java index d2b64cb3..6888d1c7 100644 --- a/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeQueryServiceImpl.java +++ b/src/main/java/com/example/mody/domain/bodytype/service/memberbodytype/MemberBodyTypeQueryServiceImpl.java @@ -12,15 +12,13 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) public class MemberBodyTypeQueryServiceImpl implements MemberBodyTypeQueryService { private final MemberBodyTypeRepository memberBodyTypeRepository; - private final ObjectMapper objectMapper = new ObjectMapper(); + private final ObjectMapper objectMapper; @Override public BodyTypeAnalysisResponse getBodyTypeAnalysis(Member member) { @@ -37,7 +35,7 @@ public BodyTypeAnalysisResponse getBodyTypeAnalysis(Member member) { // Member로 MemberBodyType 조회 @Override public MemberBodyType getMemberBodyType(Member member) { - Optional optionalMemberBodyType = memberBodyTypeRepository.findTopByMemberOrderByCreatedAtDesc(member); - return optionalMemberBodyType.orElseThrow(() -> new BodyTypeException(BodyTypeErrorStatus.MEMBER_BODY_TYPE_NOT_FOUND)); + return memberBodyTypeRepository.findTopByMemberOrderByCreatedAtDesc(member) + .orElseThrow(() -> new BodyTypeException(BodyTypeErrorStatus.MEMBER_BODY_TYPE_NOT_FOUND)); } } From 7f3a354e8755d698cdc3f8c5c594ab201fd91344 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 17:13:24 +0900 Subject: [PATCH 25/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20refactor:?= =?UTF-8?q?=20ChatGptService=20=EC=BD=94=EB=93=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mody/domain/chatgpt/service/ChatGptService.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/mody/domain/chatgpt/service/ChatGptService.java b/src/main/java/com/example/mody/domain/chatgpt/service/ChatGptService.java index 69db1ef2..6b827b3c 100644 --- a/src/main/java/com/example/mody/domain/chatgpt/service/ChatGptService.java +++ b/src/main/java/com/example/mody/domain/chatgpt/service/ChatGptService.java @@ -33,8 +33,8 @@ public final class ChatGptService { private final OpenAiApiClient openAiApiClient; // ChatGPT API와의 통신을 담당 private final PromptManager promptManager; // 프롬프트 생성 - private final ObjectMapper objectMapper = new ObjectMapper(); // JSON 응답 변환 - private final CrawlerService crawlerService; + private final ObjectMapper objectMapper; // JSON 응답 변환 + private final CrawlerService crawlerService; // 크롤링 서비스 @Value("${openai.model}") private String model; // OpenAI 모델 @@ -71,7 +71,7 @@ private ChatGPTResponse getChatGPTResponse(String nickName, Gender gender, Strin String prompt = promptManager.createBodyTypeAnalysisPrompt(nickName, gender, answers); // OpenAI API 호출 - ChatGPTResponse response = openAiApiClient.sendRequestToModel( + return openAiApiClient.sendRequestToModel( model, List.of( new Message(systemRole, prompt) @@ -79,7 +79,6 @@ private ChatGPTResponse getChatGPTResponse(String nickName, Gender gender, Strin maxTokens, temperature ); - return response; } // 체형 분석 메서드 From 0f5c0d466b8784dd724a37352e328eca031b4829 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 17:40:49 +0900 Subject: [PATCH 26/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20=ED=95=80?= =?UTF-8?q?=ED=84=B0=EB=A0=88=EC=8A=A4=ED=8A=B8=20=ED=81=AC=EB=A1=A4?= =?UTF-8?q?=EB=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recommendation/service/CrawlerService.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/mody/domain/recommendation/service/CrawlerService.java b/src/main/java/com/example/mody/domain/recommendation/service/CrawlerService.java index f07883b2..16e7b380 100644 --- a/src/main/java/com/example/mody/domain/recommendation/service/CrawlerService.java +++ b/src/main/java/com/example/mody/domain/recommendation/service/CrawlerService.java @@ -21,24 +21,29 @@ @RequiredArgsConstructor public class CrawlerService { - public String getRandomImageUrl(String keyword) { + private static final String PINTEREST_SEARCH_URL_TEMPLATE = "https://kr.pinterest.com/search/pins/?q="; + private static final String IMAGE_XPATH = "//img[contains(@src, 'https')]"; + private static final int MAX_IMAGES = 10; + + public String getRandomImageUrl(String keyword) { WebDriver driver = getWebDriver(); WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); try { - String searchUrl = "https://kr.pinterest.com/search/pins/?q=" + URLEncoder.encode(keyword + " 스타일", StandardCharsets.UTF_8); + // 페이지 접속 + String searchUrl = PINTEREST_SEARCH_URL_TEMPLATE + URLEncoder.encode(keyword + " 스타일", StandardCharsets.UTF_8); driver.navigate().to(searchUrl); log.info("Pinterest 검색 URL 접속 완료: {}", searchUrl); // 이미지 태그 검색 결과 로드 - wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//img[contains(@src, 'https')]"))); + wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(IMAGE_XPATH))); log.info("이미지 태그 검색 결과 로드 완료"); Set imageUrls = new HashSet<>(); - List images = driver.findElements(By.xpath("//img[contains(@src, 'https')]")); + List images = driver.findElements(By.xpath(IMAGE_XPATH)); - int maxImages = Math.min(images.size(), 7); // 최대 이미지 7개(핀터레스트 첫 줄 사진이 7개) + int maxImages = Math.min(images.size(), MAX_IMAGES); for (int i = 0; i < maxImages; i++) { String url = images.get(i).getAttribute("src"); if (url != null && !url.isEmpty()) { @@ -61,8 +66,6 @@ public String getRandomImageUrl(String keyword) { } catch (Exception e) { log.error("크롤링 실패 (키워드: {}):", keyword); throw new RestApiException(CrawlerErrorStatus.CRAWLING_FAILED); - } finally { - driver.quit(); } } From abd4f1bff6277e00fe28ad0ce68c033ac110d1d7 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 17:47:25 +0900 Subject: [PATCH 27/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20refactor:?= =?UTF-8?q?=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/image/dto/request/PostPresignedUrlRequest.java | 2 -- .../image/dto/request/ProfilePresignedUrlRequest.java | 4 ---- .../com/example/mody/domain/image/service/S3Service.java | 8 -------- 3 files changed, 14 deletions(-) diff --git a/src/main/java/com/example/mody/domain/image/dto/request/PostPresignedUrlRequest.java b/src/main/java/com/example/mody/domain/image/dto/request/PostPresignedUrlRequest.java index b9695ddb..96f54da9 100644 --- a/src/main/java/com/example/mody/domain/image/dto/request/PostPresignedUrlRequest.java +++ b/src/main/java/com/example/mody/domain/image/dto/request/PostPresignedUrlRequest.java @@ -3,7 +3,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; import java.util.List; @@ -11,7 +10,6 @@ * 게시글 S3 presigned url 요청 DTO */ @Getter -@Setter @NoArgsConstructor public class PostPresignedUrlRequest { @Schema(description = "업로드할 파일 목록", example = "[\"a.png\", \"b.jpg\"]") diff --git a/src/main/java/com/example/mody/domain/image/dto/request/ProfilePresignedUrlRequest.java b/src/main/java/com/example/mody/domain/image/dto/request/ProfilePresignedUrlRequest.java index 6fd9d300..ceca5dd0 100644 --- a/src/main/java/com/example/mody/domain/image/dto/request/ProfilePresignedUrlRequest.java +++ b/src/main/java/com/example/mody/domain/image/dto/request/ProfilePresignedUrlRequest.java @@ -3,15 +3,11 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.NoArgsConstructor; -import lombok.Setter; - -import java.util.List; /** * 프로필 사진 S3 presigned url 요청 DTO */ @Getter -@Setter @NoArgsConstructor public class ProfilePresignedUrlRequest { @Schema(description = "업로드할 파일", example = "a.png") diff --git a/src/main/java/com/example/mody/domain/image/service/S3Service.java b/src/main/java/com/example/mody/domain/image/service/S3Service.java index 11cc3f7f..560cf89c 100644 --- a/src/main/java/com/example/mody/domain/image/service/S3Service.java +++ b/src/main/java/com/example/mody/domain/image/service/S3Service.java @@ -8,7 +8,6 @@ import com.amazonaws.services.s3.model.CannedAccessControlList; import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; import com.example.mody.domain.image.dto.response.PresignedUrlResponse; -import com.example.mody.domain.image.dto.response.S3UrlResponse; import com.example.mody.global.common.exception.RestApiException; import com.example.mody.global.common.exception.code.status.S3ErrorStatus; import lombok.RequiredArgsConstructor; @@ -114,11 +113,4 @@ public void deleteFile(List postImageUrls) { // 파일 삭제 실패해 private String extractKey(String imageUrl) { return imageUrl.substring(imageUrl.indexOf(".com/") + 5); // 해당 index + 5 값이 key 값의 시작 인덱스 값 } - -// // 프론트에서 전달받은 key를 이용해 S3 URL 생성 및 반환(테스트용) -// public S3UrlResponse getS3Url(String key) { -// String s3Url = String.format("https://%s.s3.%s.amazonaws.com/%s", bucket, region, key); -// log.info("s3Url: {}", s3Url); -// return S3UrlResponse.from(s3Url); -// } } \ No newline at end of file From 9f47f3283ec915e6ea358bf3f7bf2afa985f2496 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 17:54:18 +0900 Subject: [PATCH 28/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20refactor:?= =?UTF-8?q?=20setter=20->=20builder=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../image/dto/response/PresignedUrlResponse.java | 15 +++++++-------- .../domain/image/dto/response/S3UrlResponse.java | 14 +++++--------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/example/mody/domain/image/dto/response/PresignedUrlResponse.java b/src/main/java/com/example/mody/domain/image/dto/response/PresignedUrlResponse.java index 2fdf9219..d0896291 100644 --- a/src/main/java/com/example/mody/domain/image/dto/response/PresignedUrlResponse.java +++ b/src/main/java/com/example/mody/domain/image/dto/response/PresignedUrlResponse.java @@ -7,9 +7,8 @@ * S3 presigned url 응답 DTO */ @Getter -@Setter -@NoArgsConstructor -@EqualsAndHashCode +@Builder +@AllArgsConstructor @Schema(description = "S3 presigned url 응답 DTO") public class PresignedUrlResponse { @@ -18,10 +17,10 @@ public class PresignedUrlResponse { @Schema(description = "S3 key 값", example = "{folder}/{memberId}/{uuid}/{filename}") private String key; - public static PresignedUrlResponse of(String preSignedUrl, String key){ - PresignedUrlResponse response = new PresignedUrlResponse(); - response.setPresignedUrl(preSignedUrl); - response.setKey(key); - return response; + public static PresignedUrlResponse of(String preSignedUrl, String key) { + return PresignedUrlResponse.builder() + .presignedUrl(preSignedUrl) + .key(key) + .build(); } } diff --git a/src/main/java/com/example/mody/domain/image/dto/response/S3UrlResponse.java b/src/main/java/com/example/mody/domain/image/dto/response/S3UrlResponse.java index 9f30d03c..a3c44470 100644 --- a/src/main/java/com/example/mody/domain/image/dto/response/S3UrlResponse.java +++ b/src/main/java/com/example/mody/domain/image/dto/response/S3UrlResponse.java @@ -1,18 +1,14 @@ package com.example.mody.domain.image.dto.response; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; /** * S3 url 응답 DTO */ @Getter -@Setter +@Builder @AllArgsConstructor -@NoArgsConstructor @Schema(description = "S3 url 응답 DTO") public class S3UrlResponse { @@ -20,8 +16,8 @@ public class S3UrlResponse { private String s3Url; public static S3UrlResponse from(String s3Url){ - S3UrlResponse response = new S3UrlResponse(); - response.setS3Url(s3Url); - return response; + return S3UrlResponse.builder() + .s3Url(s3Url) + .build(); } } \ No newline at end of file From 10547d391b6603190afb6a43f00d92ada4bd7c9c Mon Sep 17 00:00:00 2001 From: yunseo02 <154687627+yunseo02@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:34:03 +0900 Subject: [PATCH 29/34] =?UTF-8?q?=F0=9F=8E=A8=20[#132]=20refactor:=20jwtAu?= =?UTF-8?q?thenticationFilter=EC=97=90=EC=84=9C=20=EB=A9=A4=EB=B2=84=20?= =?UTF-8?q?=EB=A6=AC=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=EB=A5=BC=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jwtAuthenticationFilter에서 멤버 리포지토리 대신 서비스를 사용하도록 코드를 변경하였습니다. --- .../mody/domain/auth/jwt/JwtAuthenticationFilter.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java b/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java index 19b5ad13..ea607add 100644 --- a/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/mody/domain/auth/jwt/JwtAuthenticationFilter.java @@ -35,7 +35,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtProvider jwtProvider; - private final MemberRepository memberRepository; + private final MemberQueryService memberQueryService; private final ObjectMapper objectMapper; @Override @@ -71,8 +71,7 @@ protected void doFilterInternal( // 만약 토큰이 있다면 if (token != null) { String memberId = jwtProvider.validateTokenAndGetSubject(token); - Member member = memberRepository.findById(Long.parseLong(memberId)) - .orElseThrow(() -> new RestApiException(AuthErrorStatus.INVALID_ACCESS_TOKEN)); + Member member = memberQueryService.findMemberById(Long.parseLong(memberId)); CustomUserDetails customUserDetails = new CustomUserDetails(member); From 5a7a0d010413ce750f3764692a37111a365c47c4 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 21:46:33 +0900 Subject: [PATCH 30/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20refactor:?= =?UTF-8?q?=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=B1=85=EC=9E=84=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/image/controller/S3Controller.java | 121 +--------------- .../controller/S3ControllerInterface.java | 131 ++++++++++++++++++ 2 files changed, 132 insertions(+), 120 deletions(-) create mode 100644 src/main/java/com/example/mody/domain/image/controller/S3ControllerInterface.java diff --git a/src/main/java/com/example/mody/domain/image/controller/S3Controller.java b/src/main/java/com/example/mody/domain/image/controller/S3Controller.java index bbb2da71..6bb70145 100644 --- a/src/main/java/com/example/mody/domain/image/controller/S3Controller.java +++ b/src/main/java/com/example/mody/domain/image/controller/S3Controller.java @@ -7,10 +7,6 @@ import com.example.mody.domain.image.service.S3Service; import com.example.mody.global.common.base.BaseResponse; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.ExampleObject; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -23,63 +19,12 @@ @RestController @RequiredArgsConstructor @RequestMapping("/image") -public class S3Controller { +public class S3Controller implements S3ControllerInterface { private final S3Service s3Service; @PostMapping(value = "/upload/posts") @Operation(summary = "게시글 presigned url 생성 API", description = "게시글 파일 업로드(put) presigned url을 생성하는 API 입니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",description = "presigned url 생성을 성공하였습니다."), - @ApiResponse( - responseCode = "401", - description = "Access Token이 필요합니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "COMMON401", - "message": "인증이 필요합니다." - } - """ - ) - ) - ), - @ApiResponse( - responseCode = "404", - description = "S3 버킷을 찾을 수 없습니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "S3_404", - "message": "지정된 S3 버킷을 찾을 수 없습니다." - } - """ - ) - ) - ), - @ApiResponse( - responseCode = "500", - description = "presigned url 생성을 실패하였습니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "S3_500", - "message": "S3 presigned url 생성 중 오류가 발생했습니다." - } - """ - ) - ) - ), - }) public BaseResponse> getPostPresignedUrl( @AuthenticationPrincipal CustomUserDetails customUserDetails, @Valid @RequestBody PostPresignedUrlRequest request @@ -90,57 +35,6 @@ public BaseResponse> getPostPresignedUrl( @PostMapping(value = "/upload/profiles") @Operation(summary = "프로필 사진 presigned url 생성 API", description = "프로필 사진 파일 업로드(put) presigned url을 생성하는 API 입니다.") - @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",description = "presigned url 생성을 성공하였습니다."), - @ApiResponse( - responseCode = "401", - description = "Access Token이 필요합니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "COMMON401", - "message": "인증이 필요합니다." - } - """ - ) - ) - ), - @ApiResponse( - responseCode = "404", - description = "S3 버킷을 찾을 수 없습니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "S3_404", - "message": "지정된 S3 버킷을 찾을 수 없습니다." - } - """ - ) - ) - ), - @ApiResponse( - responseCode = "500", - description = "presigned url 생성을 실패하였습니다.", - content = @Content( - mediaType = "application/json", - examples = @ExampleObject( - value = """ - { - "timestamp": "2025-01-26T15:15:54.334Z", - "code": "S3_500", - "message": "S3 presigned url 생성 중 오류가 발생했습니다." - } - """ - ) - ) - ), - }) public BaseResponse getProfilePresignedUrl( @AuthenticationPrincipal CustomUserDetails customUserDetails, @Valid @RequestBody ProfilePresignedUrlRequest request @@ -148,17 +42,4 @@ public BaseResponse getProfilePresignedUrl( PresignedUrlResponse presignedUrlResponse = s3Service.getProfilePresignedUrl(customUserDetails.getMember().getId(), request.getFilename()); return BaseResponse.onSuccess(presignedUrlResponse); } - -// // 테스트용(실제 사용 X) -// @GetMapping(value = "/getS3Url") -// @Operation(summary = "자체 S3 URL 조회 - 테스트용으로 API 연동 시 신경 안 써도 되는 API 입니다.", -// description = "프론트에서 S3에 파일 업로드 후 반환하는 S3 URL을 서버에서 생성해 확인해보는 테스트용 API 입니다.") -// @ApiResponses({ -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",description = "S3 url 반환 성공") -// }) -// public BaseResponse getS3Url(@RequestParam String key) { -// S3UrlResponse s3UrlResponse = s3Service.getS3Url(key); -// return BaseResponse.onSuccess(s3UrlResponse); -// } - } diff --git a/src/main/java/com/example/mody/domain/image/controller/S3ControllerInterface.java b/src/main/java/com/example/mody/domain/image/controller/S3ControllerInterface.java new file mode 100644 index 00000000..2f3d767a --- /dev/null +++ b/src/main/java/com/example/mody/domain/image/controller/S3ControllerInterface.java @@ -0,0 +1,131 @@ +package com.example.mody.domain.image.controller; + +import com.example.mody.domain.auth.security.CustomUserDetails; +import com.example.mody.domain.image.dto.request.PostPresignedUrlRequest; +import com.example.mody.domain.image.dto.request.ProfilePresignedUrlRequest; +import com.example.mody.domain.image.dto.response.PresignedUrlResponse; +import com.example.mody.global.common.base.BaseResponse; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.validation.Valid; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; + +public interface S3ControllerInterface { + + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",description = "presigned url 생성을 성공하였습니다."), + @ApiResponse( + responseCode = "401", + description = "Access Token이 필요합니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "COMMON401", + "message": "인증이 필요합니다." + } + """ + ) + ) + ), + @ApiResponse( + responseCode = "404", + description = "S3 버킷을 찾을 수 없습니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "S3_404", + "message": "지정된 S3 버킷을 찾을 수 없습니다." + } + """ + ) + ) + ), + @ApiResponse( + responseCode = "500", + description = "presigned url 생성을 실패하였습니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "S3_500", + "message": "S3 presigned url 생성 중 오류가 발생했습니다." + } + """ + ) + ) + ), + }) + BaseResponse> getPostPresignedUrl( + @AuthenticationPrincipal CustomUserDetails customUserDetails, + @Valid @RequestBody PostPresignedUrlRequest request + ); + + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",description = "presigned url 생성을 성공하였습니다."), + @ApiResponse( + responseCode = "401", + description = "Access Token이 필요합니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "COMMON401", + "message": "인증이 필요합니다." + } + """ + ) + ) + ), + @ApiResponse( + responseCode = "404", + description = "S3 버킷을 찾을 수 없습니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "S3_404", + "message": "지정된 S3 버킷을 찾을 수 없습니다." + } + """ + ) + ) + ), + @ApiResponse( + responseCode = "500", + description = "presigned url 생성을 실패하였습니다.", + content = @Content( + mediaType = "application/json", + examples = @ExampleObject( + value = """ + { + "timestamp": "2025-01-26T15:15:54.334Z", + "code": "S3_500", + "message": "S3 presigned url 생성 중 오류가 발생했습니다." + } + """ + ) + ) + ), + }) + BaseResponse getProfilePresignedUrl( + @AuthenticationPrincipal CustomUserDetails customUserDetails, + @Valid @RequestBody ProfilePresignedUrlRequest request + ); +} From 35c24c42a8760254f507b39abad6597665cab331 Mon Sep 17 00:00:00 2001 From: sshnote Date: Tue, 18 Feb 2025 22:08:07 +0900 Subject: [PATCH 31/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20[#135]=20refactor:?= =?UTF-8?q?=20S3Service=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mody/domain/image/service/S3Service.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/example/mody/domain/image/service/S3Service.java b/src/main/java/com/example/mody/domain/image/service/S3Service.java index 560cf89c..8f94809a 100644 --- a/src/main/java/com/example/mody/domain/image/service/S3Service.java +++ b/src/main/java/com/example/mody/domain/image/service/S3Service.java @@ -21,28 +21,28 @@ import java.util.Date; import java.util.List; import java.util.UUID; +import java.util.regex.Pattern; @Slf4j @Service @RequiredArgsConstructor -@Transactional(readOnly = true) public class S3Service { private final AmazonS3 amazonS3Client; @Value("${cloud.aws.s3.bucket}") private String bucket; - @Value("${cloud.aws.region.static}") - private String region; + private static final Pattern FILENAME_SANITIZE_PATTERN = Pattern.compile("[^/]+://[^/]+/"); + @Transactional(readOnly = true) public List getPostPresignedUrls(Long memberId, List filenames) { // 게시물당 하나의 UUID를 생성 String uuid = UUID.randomUUID().toString(); List presignedUrls = new ArrayList<>(); for (String filename : filenames) { - String sanitizedFilename = filename.replaceAll("[^/]+://[^/]+/", ""); - String key = String.format("post/%d/%s/%s", memberId, uuid, sanitizedFilename); + String sanitizedFilename = FILENAME_SANITIZE_PATTERN.matcher(filename).replaceAll(""); + String key = String.format("post/%d/%s/%s", memberId, uuid, sanitizedFilename); // key값 설정(post 디렉터리 + 멤버ID + 랜덤 값 + filename) Date expiration = getExpiration(); // 유효 기간 GeneratePresignedUrlRequest generatePresignedUrlRequest = generatePresignedUrl(key, expiration); @@ -52,10 +52,11 @@ public List getPostPresignedUrls(Long memberId, List postImageUrls) { // 파일 삭제 실패해도 다음 파일 삭제를 수행하도록 예외를 터뜨리는 것이 아닌 로그만 찍음 for (String imageUrl : postImageUrls) { From 8df44a768c03afbe88177d0baa9990f4f0fd98ee Mon Sep 17 00:00:00 2001 From: Sanghyo Seo <125882656+seoshinehyo@users.noreply.github.com> Date: Tue, 18 Feb 2025 22:20:43 +0900 Subject: [PATCH 32/34] =?UTF-8?q?=F0=9F=93=9D=20docs:=20README=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f6c73204..c3a33182 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,10 @@ +## 아키텍처 다이어그램 +![image](https://github.com/user-attachments/assets/25a84d99-a57e-42c9-afcf-1f9cb9adc9da) + + ## 협업 규칙 ### Github 협업 규칙 From 3e02e872aa87eee4b0b2824ee80c2d9b2ef28d5a Mon Sep 17 00:00:00 2001 From: yunseo02 <154687627+yunseo02@users.noreply.github.com> Date: Tue, 18 Feb 2025 22:44:10 +0900 Subject: [PATCH 33/34] =?UTF-8?q?=F0=9F=90=9B=20[137]=20fix:=20securityCon?= =?UTF-8?q?fig=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit securityConfig jwt인증 필터 생성자 수정 --- .../java/com/example/mody/global/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/mody/global/config/SecurityConfig.java b/src/main/java/com/example/mody/global/config/SecurityConfig.java index b4918dba..9da5a5c4 100644 --- a/src/main/java/com/example/mody/global/config/SecurityConfig.java +++ b/src/main/java/com/example/mody/global/config/SecurityConfig.java @@ -131,7 +131,7 @@ public CorsConfigurationSource corsConfigurationSource() { @Bean public JwtAuthenticationFilter jwtAuthenticationFilter() { - return new JwtAuthenticationFilter(jwtProvider, memberRepository, objectMapper); + return new JwtAuthenticationFilter(jwtProvider, memberQueryService, objectMapper); } @Bean From 5ea37507ef7771edb8763a6928e9e3eb91b5ba22 Mon Sep 17 00:00:00 2001 From: shimfff Date: Wed, 19 Feb 2025 17:07:25 +0900 Subject: [PATCH 34/34] =?UTF-8?q?:sparkles:=20feat=20:=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EA=B0=80=EC=9E=85=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mody/domain/auth/handler/OAuth2SuccessHandler.java | 6 +++--- .../mody/domain/auth/security/OAuth2UserService.java | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/mody/domain/auth/handler/OAuth2SuccessHandler.java b/src/main/java/com/example/mody/domain/auth/handler/OAuth2SuccessHandler.java index ff993dbf..9909a8d5 100644 --- a/src/main/java/com/example/mody/domain/auth/handler/OAuth2SuccessHandler.java +++ b/src/main/java/com/example/mody/domain/auth/handler/OAuth2SuccessHandler.java @@ -58,13 +58,13 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo Member member = memberRepository.findByProviderId(oAuth2User.getOAuth2Response().getProviderId()) .orElseGet(() -> saveMember(oAuth2User)); - // 새로 가입한 멤버인지 아닌지 확인 - boolean isNewMember = member.getCreatedAt().equals(member.getUpdatedAt()); +// // 새로 가입한 멤버인지 아닌지 확인 +// boolean isNewMember = member.getCreatedAt().equals(member.getUpdatedAt()); // Access Token, Refresh Token 발급 String newAccessToken = authCommandService.processLoginSuccess(member, response); - String tempUrl = (isNewMember || !member.isRegistrationCompleted()) ? FRONT_SIGNUP_URL : FRONT_HOME_URL; + String tempUrl = (!member.isRegistrationCompleted()) ? FRONT_SIGNUP_URL : FRONT_HOME_URL; String targetUrl = UriComponentsBuilder.fromUriString(tempUrl) .build().toUriString(); diff --git a/src/main/java/com/example/mody/domain/auth/security/OAuth2UserService.java b/src/main/java/com/example/mody/domain/auth/security/OAuth2UserService.java index b68246ab..1f5625c1 100644 --- a/src/main/java/com/example/mody/domain/auth/security/OAuth2UserService.java +++ b/src/main/java/com/example/mody/domain/auth/security/OAuth2UserService.java @@ -57,7 +57,6 @@ private Member saveMember(OAuth2Response oAuth2Response) { Member member = Member.builder() .providerId(oAuth2Response.getProviderId()) .provider(oAuth2Response.getProvider()) - .nickname(oAuth2Response.getName()) .status(Status.ACTIVE) .role(Role.ROLE_USER) .loginType(LoginType.KAKAO)