From 156efea4ad0e25ccdad6fd9590a9342bdad42d6f Mon Sep 17 00:00:00 2001 From: Younglong Date: Thu, 29 Feb 2024 14:15:37 +0900 Subject: [PATCH 01/56] =?UTF-8?q?feat:=20member=20=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=20=EA=B6=8C=ED=95=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - member 테이블에 references 권한 추가 --- .../db/migration/V1.0.10__grant_references_on_member.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 module-api/src/main/resources/db/migration/V1.0.10__grant_references_on_member.sql diff --git a/module-api/src/main/resources/db/migration/V1.0.10__grant_references_on_member.sql b/module-api/src/main/resources/db/migration/V1.0.10__grant_references_on_member.sql new file mode 100644 index 00000000..26b6bc7e --- /dev/null +++ b/module-api/src/main/resources/db/migration/V1.0.10__grant_references_on_member.sql @@ -0,0 +1 @@ +GRANT REFERENCES ON TABLE member TO wash_admin; \ No newline at end of file From 5c15c2a19a31cb3c5896d7d0893169380837a9d4 Mon Sep 17 00:00:00 2001 From: Younglong Date: Thu, 29 Feb 2024 14:26:36 +0900 Subject: [PATCH 02/56] =?UTF-8?q?feat:=20review=20=EA=B4=80=EB=A0=A8=20int?= =?UTF-8?q?erceptor=20=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - interceptor config에 /reviews 경로 추가 - interceptor에 reviews url 추가 검증 로직 추가 --- .../global/Interceptor/AcceptInterceptor.java | 25 +++++++++++++++++++ .../global/Interceptor/InterceptorConfig.java | 3 ++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/global/Interceptor/AcceptInterceptor.java b/module-api/src/main/java/com/kernel360/global/Interceptor/AcceptInterceptor.java index df2ede03..4ef9d5d9 100644 --- a/module-api/src/main/java/com/kernel360/global/Interceptor/AcceptInterceptor.java +++ b/module-api/src/main/java/com/kernel360/global/Interceptor/AcceptInterceptor.java @@ -6,10 +6,13 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpMethod; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.servlet.HandlerInterceptor; +import java.util.Objects; + @Component @RequiredArgsConstructor public class AcceptInterceptor implements HandlerInterceptor { @@ -18,6 +21,10 @@ public class AcceptInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + if (validateTargetUri(request)) { + return true; + } + boolean result = true; String requestToken = request.getHeader("Authorization"); @@ -33,4 +40,22 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons return result; } + private boolean validateTargetUri(HttpServletRequest request) { + String requestURI = request.getRequestURI(); + String method = request.getMethod(); + + if (Objects.isNull(requestURI)) { + return false; + } + + if (!requestURI.startsWith("/reviews")) { + return false; + } + + if (HttpMethod.GET.matches(method)) { + return true; + } + + return false; + } } diff --git a/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java b/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java index 2ba476d2..1dbb1a02 100644 --- a/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java +++ b/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java @@ -13,7 +13,8 @@ public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(acceptInterceptor) - .addPathPatterns("/auth/**"); //** 인증 JWT 토큰 관련 **// + .addPathPatterns("/auth/**") //** 인증 JWT 토큰 관련 **// + .addPathPatterns("/reviews/**"); // .addPathPatterns("/mypage/**"); //.excludePathPatterns("/public/**"); // 제외할 URL 패턴 } From f50bcd6743d3266d87f0b8de0eb3bf641e2d0bae Mon Sep 17 00:00:00 2001 From: Younglong Date: Thu, 29 Feb 2024 14:44:29 +0900 Subject: [PATCH 03/56] =?UTF-8?q?feat:=20review=20paging=20=EB=B0=8F=20log?= =?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 - review paging 추가 - ReviewService 내 로그 남기는 부분 추가 --- .../review/controller/ReviewController.java | 12 +++++------ .../review/service/ReviewService.java | 21 +++++++++++++------ .../review/repository/ReviewRepository.java | 6 +++--- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java b/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java index 6ec02f5f..1cd62233 100644 --- a/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java +++ b/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java @@ -5,11 +5,11 @@ import com.kernel360.review.dto.ReviewDto; import com.kernel360.review.service.ReviewService; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RestController @RequiredArgsConstructor @RequestMapping("/reviews") @@ -18,17 +18,15 @@ public class ReviewController { private final ReviewService reviewService; @GetMapping("/product/{productNo}") - public ResponseEntity>> getReviewsByProduct(@PathVariable Long productNo) { - List reviews = reviewService.getReviewsByProduct(productNo); + public ResponseEntity>> getReviewsByProduct(@PathVariable Long productNo, Pageable pageable) { - return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEWS, reviews); + return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEWS, reviewService.getReviewsByProduct(productNo, pageable)); } @GetMapping("/{reviewNo}") public ResponseEntity> getReview(@PathVariable Long reviewNo) { - ReviewDto review = reviewService.getReview(reviewNo); - return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEW, review); + return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEW, reviewService.getReview(reviewNo)); } @PostMapping("") diff --git a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java index 86391415..12fec214 100644 --- a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java +++ b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java @@ -6,12 +6,15 @@ import com.kernel360.review.entity.Review; import com.kernel360.review.repository.ReviewRepository; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; -import java.util.List; +@Slf4j @Service @RequiredArgsConstructor public class ReviewService { @@ -21,15 +24,16 @@ public class ReviewService { private static final double MAX_STAR_RATING = 5.0; @Transactional(readOnly = true) - public List getReviewsByProduct(Long productNo) { + public Page getReviewsByProduct(Long productNo, Pageable pageable) { + log.info("제품 리뷰 목록 조회 -> product_no {}", productNo); - return reviewRepository.findAllByProduct_ProductNo(productNo) - .stream().map(ReviewDto::from) - .toList(); + return reviewRepository.findAllByProduct_ProductNo(productNo, pageable) + .map(ReviewDto::from); } @Transactional(readOnly = true) public ReviewDto getReview(Long reviewNo) { + log.info("리뷰 단건 조회 -> review_no {}", reviewNo); return ReviewDto.from(reviewRepository.findByReviewNo(reviewNo)); } @@ -38,7 +42,10 @@ public ReviewDto getReview(Long reviewNo) { public Review createReview(ReviewDto reviewDto) { isValidStarRating(reviewDto.starRating()); - return reviewRepository.save(reviewDto.toEntity()); + Review review = reviewRepository.save(reviewDto.toEntity()); + log.info("리뷰 등록 -> review_no {}", review.getReviewNo()); + + return review; } @@ -47,11 +54,13 @@ public void updateReview(ReviewDto reviewDto) { isValidStarRating(reviewDto.starRating()); reviewRepository.save(reviewDto.toEntity()); + log.info("리뷰 수정 -> review_no {}", reviewDto.reviewNo()); } @Transactional public void deleteReview(Long reviewNo) { reviewRepository.deleteById(reviewNo); + log.info("리뷰 삭제 -> review_no {}", reviewNo); } private static void isValidStarRating(BigDecimal starRating) { diff --git a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java index 556939e0..b2ad507e 100644 --- a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java +++ b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java @@ -1,12 +1,12 @@ package com.kernel360.review.repository; import com.kernel360.review.entity.Review; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; - public interface ReviewRepository extends JpaRepository { - List findAllByProduct_ProductNo(Long productNo); + Page findAllByProduct_ProductNo(Long productNo, Pageable pageable); Review findByReviewNo(Long reviewNo); } From 637b360a41ef9116acdc178e2c19640fcd48bccb Mon Sep 17 00:00:00 2001 From: HyunJunSon Date: Thu, 29 Feb 2024 15:34:30 +0900 Subject: [PATCH 04/56] =?UTF-8?q?refactor::=20like=20=EB=A6=AC=ED=84=B4?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kernel360/likes/service/LikeService.java | 24 ++++++++++--------- .../java/com/kernel360/likes/entity/Like.java | 4 +++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/likes/service/LikeService.java b/module-api/src/main/java/com/kernel360/likes/service/LikeService.java index 519c2fba..72ff4938 100644 --- a/module-api/src/main/java/com/kernel360/likes/service/LikeService.java +++ b/module-api/src/main/java/com/kernel360/likes/service/LikeService.java @@ -5,16 +5,17 @@ import com.kernel360.likes.entity.Like; import com.kernel360.likes.repository.LikeRepository; import com.kernel360.member.service.MemberService; -import com.kernel360.product.code.ProductsErrorCode; import com.kernel360.product.dto.ProductDto; -import com.kernel360.product.entity.Product; import com.kernel360.product.repository.ProductRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.Optional; @Service @@ -28,10 +29,8 @@ public class LikeService { @Transactional public void heartOn(Long productNo, String token) { Long memberNo = memberService.findMemberByToken(token).memberNo(); - Product product = productRepository.findById(productNo) - .orElseThrow(() -> new BusinessException(ProductsErrorCode.NOT_FOUND_PRODUCT)); - likeRepository.save(Like.of(memberNo, product.getProductNo())); + likeRepository.save(Like.of(memberNo, productNo)); } @Transactional @@ -46,11 +45,14 @@ public void heartOff(Long productNo, String token) { @Transactional(readOnly = true) public Page findAllLikes(String token, Pageable pageable) { Long memberNo = memberService.findMemberByToken(token).memberNo(); - - return likeRepository.findAllByMemberNo(memberNo, pageable) - .map(like -> productRepository.findById(like.getId()) - .orElseThrow(() -> new BusinessException(ProductsErrorCode.NOT_FOUND_PRODUCT))) - .map(ProductDto::from); - + Page likesPage = likeRepository.findAllByMemberNo(memberNo, pageable); + List productDtos = likesPage.getContent().stream() + .map(like -> productRepository.findById(like.getProductNo())) + .filter(Optional::isPresent) + .map(Optional::get) + .map(ProductDto::from) + .toList(); + + return new PageImpl<>(productDtos, pageable, productDtos.size()); } } diff --git a/module-domain/src/main/java/com/kernel360/likes/entity/Like.java b/module-domain/src/main/java/com/kernel360/likes/entity/Like.java index 22292911..81c3a3ca 100644 --- a/module-domain/src/main/java/com/kernel360/likes/entity/Like.java +++ b/module-domain/src/main/java/com/kernel360/likes/entity/Like.java @@ -9,7 +9,9 @@ @Getter @Entity -@Table(name = "likes") +@Table(name = "likes", uniqueConstraints = { + @UniqueConstraint(columnNames = {"member_no", "product_no"}) +}) @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Like extends BaseEntity { @Id From 901adad27689faedc6291aa168b70eb5947ed137 Mon Sep 17 00:00:00 2001 From: linglong67 <88479739+linglong67@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:58:10 +0900 Subject: [PATCH 05/56] Update cicd-dev.yml --- .github/workflows/cicd-dev.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cicd-dev.yml b/.github/workflows/cicd-dev.yml index f5333206..c8919f95 100644 --- a/.github/workflows/cicd-dev.yml +++ b/.github/workflows/cicd-dev.yml @@ -2,7 +2,7 @@ name: CI and CD in WashPedia Project on: push: - branches: [ "develop" ] + branches: [ "feature/modify-cicd-dev-yml" ] permissions: contents: read @@ -122,9 +122,11 @@ jobs: echo "${{ secrets.DB_INIT_SQL }}" > init.sql echo "${{ secrets.DEV_REDIS_CONF }}" > ./redis/redis.conf echo "${{ secrets.DOCKER_COMPOSE }}" > docker-compose.yml + + echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login --username ${{ secrets.DOCKERHUB_USERNAME }} --password-stdin docker image prune -af docker-compose pull docker-compose down - docker-compose up -d \ No newline at end of file + docker-compose up -d From 48f70b2a7f2b76c594db68701373fefebd05a7d7 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 16:01:58 +0900 Subject: [PATCH 06/56] =?UTF-8?q?refactor=20:=20.yml=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EC=97=90=20jwt-expiring-time=20=EC=A7=80=EC=A0=95=ED=95=98?= =?UTF-8?q?=EC=97=AC=20profile=20=EB=B3=84=EB=A1=9C=20=EB=8B=A4=EB=A5=B4?= =?UTF-8?q?=EA=B2=8C=20=EC=84=A4=EC=A0=95=ED=95=98=EC=97=AC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-api/src/main/resources/application-dev.yml | 2 ++ module-api/src/main/resources/application-local.yml | 3 +++ module-api/src/main/resources/application-prod.yml | 2 ++ module-common/src/main/java/com/kernel360/utils/JWT.java | 7 ++++--- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/module-api/src/main/resources/application-dev.yml b/module-api/src/main/resources/application-dev.yml index e6fea07d..87fd4b0d 100644 --- a/module-api/src/main/resources/application-dev.yml +++ b/module-api/src/main/resources/application-dev.yml @@ -66,6 +66,8 @@ constants: host-url: ${DEV_HOST_URL} password-reset-token: duration-minute: 5 + jwt: + expiring-minute: 60 aws: credentials: diff --git a/module-api/src/main/resources/application-local.yml b/module-api/src/main/resources/application-local.yml index 323c548b..c9ddd639 100644 --- a/module-api/src/main/resources/application-local.yml +++ b/module-api/src/main/resources/application-local.yml @@ -72,6 +72,9 @@ constants: host-url: "http://localhost:8080" password-reset-token: duration-minute: 5 + jwt: + expiring-minute: 60 + aws: credentials: diff --git a/module-api/src/main/resources/application-prod.yml b/module-api/src/main/resources/application-prod.yml index 983e1954..55eb3f00 100644 --- a/module-api/src/main/resources/application-prod.yml +++ b/module-api/src/main/resources/application-prod.yml @@ -66,6 +66,8 @@ constants: host-url: ${PROD_HOST_URL} password-reset-token: duration-minute: 5 + jwt: + expiring-minute: 3 # ${PROD_JWT_EXPIRATION} aws: credentials: diff --git a/module-common/src/main/java/com/kernel360/utils/JWT.java b/module-common/src/main/java/com/kernel360/utils/JWT.java index bdb72d04..7e3b28ed 100644 --- a/module-common/src/main/java/com/kernel360/utils/JWT.java +++ b/module-common/src/main/java/com/kernel360/utils/JWT.java @@ -3,6 +3,7 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.security.Key; @@ -14,16 +15,16 @@ @Component public class JWT { private static final Key SECRET_KEY = Keys.secretKeyFor(io.jsonwebtoken.SignatureAlgorithm.HS256); - //private static final long EXPIRATION_TIME = (long) 1000 * 60 * 15; //15분 - private static final long EXPIRATION_TIME = (long) 1000 * 60 * 3; //테스트를 위해 3분으로 조정 + @Value("${constants.jwt.expiring-minute}") + private long EXPIRATION_TIME; public String generateToken(String entityId) { return Jwts.builder() .setIssuer("washpedia") .setId(entityId) .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) + .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME * 60 * 1000)) .signWith(SECRET_KEY) .compact(); } From 2c8bc2c319dd1d33e5e4f5cb743ac64638e18c61 Mon Sep 17 00:00:00 2001 From: linglong67 <88479739+linglong67@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:02:31 +0900 Subject: [PATCH 07/56] Update cicd-dev.yml --- .github/workflows/cicd-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cicd-dev.yml b/.github/workflows/cicd-dev.yml index c8919f95..bec9e75b 100644 --- a/.github/workflows/cicd-dev.yml +++ b/.github/workflows/cicd-dev.yml @@ -2,7 +2,7 @@ name: CI and CD in WashPedia Project on: push: - branches: [ "feature/modify-cicd-dev-yml" ] + branches: [ "develop" ] permissions: contents: read From 5bce046c5873e2d66cfdb9ac887b6bf2ef70575b Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 16:28:59 +0900 Subject: [PATCH 08/56] =?UTF-8?q?*=20=EC=BF=BC=EB=A6=AC=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=88=98=EC=A0=95=20(=EA=B3=84=EC=A0=95=EB=B6=84?= =?UTF-8?q?=EB=A5=98=20=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/db/migration/V1.0.0__init.sql | 4 +++- .../V1.0.2__add_member_view_with_secure.sql | 12 +++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/module-api/src/main/resources/db/migration/V1.0.0__init.sql b/module-api/src/main/resources/db/migration/V1.0.0__init.sql index e5201d32..de376110 100644 --- a/module-api/src/main/resources/db/migration/V1.0.0__init.sql +++ b/module-api/src/main/resources/db/migration/V1.0.0__init.sql @@ -25,6 +25,7 @@ CREATE TABLE if not exists Auth created_by varchar NOT NULL, modified_at date NULL, modified_by varchar NULL + ); @@ -39,7 +40,8 @@ CREATE TABLE if not exists Member created_at DATE NOT NULL, created_by VARCHAR NOT NULL, modified_at DATE, - modified_by VARCHAR + modified_by VARCHAR, + account_type varchar ); diff --git a/module-api/src/main/resources/db/migration/V1.0.2__add_member_view_with_secure.sql b/module-api/src/main/resources/db/migration/V1.0.2__add_member_view_with_secure.sql index 6456f274..38c2d8a7 100644 --- a/module-api/src/main/resources/db/migration/V1.0.2__add_member_view_with_secure.sql +++ b/module-api/src/main/resources/db/migration/V1.0.2__add_member_view_with_secure.sql @@ -39,7 +39,8 @@ SELECT member_no, created_at, created_by, modified_at, - modified_by + modified_by, + account_type FROM member; @@ -51,10 +52,10 @@ CREATE RETURNS TRIGGER AS $$ BEGIN - INSERT INTO member (member_no, id, "password", email, gender, age, created_at, created_by, modified_at, modified_by) + INSERT INTO member (member_no, id, "password", email, gender, age, created_at, created_by, modified_at, modified_by, account_type) VALUES (nextval('member_member_no_seq'::regclass), NEW.id, pgp_sym_encrypt(NEW.password::TEXT, 'changeRequired'), pgp_sym_encrypt(NEW.email::TEXT, 'changeRequired'), NEW.gender, NEW.age, NEW.created_at, NEW.created_by, - NEW.modified_at, NEW.modified_by); + NEW.modified_at, NEW.modified_by, NEW.account_type); RETURN NEW; @@ -88,7 +89,8 @@ BEGIN created_at = NEW.created_at, created_by = NEW.created_by, modified_at = NEW.modified_at, - modified_by = NEW.modified_by + modified_by = NEW.modified_by, + account_type = NEW.account_type WHERE member_no = NEW.member_no; RETURN NEW; END; @@ -132,4 +134,4 @@ EXECUTE FUNCTION member_view_delete_trigger(); -- 테이블 member 권한 회수 설정 -REVOKE INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES ON member FROM wash_admin; \ No newline at end of file +REVOKE INSERT, UPDATE, DELETE, TRUNCATE ON member FROM wash_admin; \ No newline at end of file From 1129ed90297635ceadd2ca494b9f9e588e96eda9 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 16:29:26 +0900 Subject: [PATCH 09/56] =?UTF-8?q?*=20=EA=B3=84=EC=A0=95=20=EB=B6=84?= =?UTF-8?q?=EB=A5=98=20Enum=20=ED=81=B4=EB=9E=98=EC=8A=A4=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 --- .../main/java/com/kernel360/member/enumset/AccountType.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 module-api/src/main/java/com/kernel360/member/enumset/AccountType.java diff --git a/module-api/src/main/java/com/kernel360/member/enumset/AccountType.java b/module-api/src/main/java/com/kernel360/member/enumset/AccountType.java new file mode 100644 index 00000000..3ceb842c --- /dev/null +++ b/module-api/src/main/java/com/kernel360/member/enumset/AccountType.java @@ -0,0 +1,5 @@ +package com.kernel360.member.enumset; + +public enum AccountType { + PLATFORM, KAKAO, NAVER, GOOGLE +} From d558b8f9d67cf4b2b30360d32e7462614b9b6279 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 16:29:43 +0900 Subject: [PATCH 10/56] =?UTF-8?q?*=20=EA=B3=84=EC=A0=95=20=EB=B6=84?= =?UTF-8?q?=EB=A5=98=20Entity=20Field=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kernel360/member/entity/Member.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/module-domain/src/main/java/com/kernel360/member/entity/Member.java b/module-domain/src/main/java/com/kernel360/member/entity/Member.java index 0210405c..27e154e7 100644 --- a/module-domain/src/main/java/com/kernel360/member/entity/Member.java +++ b/module-domain/src/main/java/com/kernel360/member/entity/Member.java @@ -41,9 +41,12 @@ public class Member extends BaseEntity { @Column(name = "age") private int age; - public static Member of(Long memberNo, String id, String email, String password, int gender, int age) { + @Column(name = "account_type") + private String accountType; - return new Member(memberNo, id, email, password, gender, age); + public static Member of(Long memberNo, String id, String email, String password, int gender, int age, String accountType) { + + return new Member(memberNo, id, email, password, gender, age, accountType); } /** @@ -55,7 +58,8 @@ private Member( String email, String password, int gender, - int age + int age, + String accountType ) { this.memberNo = memberNo; this.id = id; @@ -63,25 +67,27 @@ private Member( this.password = password; this.gender = gender; this.age = age; + this.accountType = accountType; } /** * joinMember **/ - public static Member createJoinMember(String id, String email, String password, int gender, int age) { + public static Member createJoinMember(String id, String email, String password, int gender, int age, String accountType) { - return new Member(id, email, password, gender, age); + return new Member(id, email, password, gender, age, accountType); } /** * joinMember Binding **/ - private Member(String id, String email, String password, int gender, int age) { + private Member(String id, String email, String password, int gender, int age, String accountType) { this.id = id; this.email = email; this.password = password; this.gender = gender; this.age = age; + this.accountType = accountType; } /** @@ -112,11 +118,6 @@ public void updateCarInfo(CarInfo carInfo) { this.carInfo = carInfo; } - public static Member createForKakao(String id, String email, String password, int gender, int age) { - - return new Member(id, email, password, gender, age); - } - public void updateFromInfo(int gender, int age) { this.gender = gender; this.age = age; From 580db55aea4e1708d326411f1c6f7d9e555db7aa Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 16:39:55 +0900 Subject: [PATCH 11/56] =?UTF-8?q?feat=20::=20admin=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8A=94=20Bra?= =?UTF-8?q?nd=20=EC=9D=98=20Code=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../brand/code/BrandBusinessCode.java | 39 +++++++++++++++++++ .../kernel360/brand/code/BrandErrorCode.java | 34 ++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 module-admin/src/main/java/com/kernel360/brand/code/BrandBusinessCode.java create mode 100644 module-admin/src/main/java/com/kernel360/brand/code/BrandErrorCode.java diff --git a/module-admin/src/main/java/com/kernel360/brand/code/BrandBusinessCode.java b/module-admin/src/main/java/com/kernel360/brand/code/BrandBusinessCode.java new file mode 100644 index 00000000..1786c312 --- /dev/null +++ b/module-admin/src/main/java/com/kernel360/brand/code/BrandBusinessCode.java @@ -0,0 +1,39 @@ +package com.kernel360.brand.code; + +import com.kernel360.code.BusinessCode; +import org.springframework.http.HttpStatus; + +public enum BrandBusinessCode implements BusinessCode { + + SUCCESS_FOUND_BRAND_LIST(HttpStatus.OK.value(),"BMB001","브랜드 목록 조회 성공"), + SUCCESS_FOUND_EXACT_BRAND(HttpStatus.OK.value(),"BMB002","브랜드 상세 조회 성공"), + SUCCESS_CREATED_BRAND(HttpStatus.CREATED.value(), "BMB003","브랜드 추가 성공" ), + SUCCESS_DELETED_BRAND(HttpStatus.OK.value(), "BMB004","브랜드 삭제 성공"), + SUCCESS_UPDATED_BRAND(HttpStatus.OK.value(), "BMB005","브랜드 업데이트 성곡" ); + + + private final int status; + private final String code; + private final String message; + + BrandBusinessCode(int status, String code, String message) { + this.status = status; + this.code = code; + this.message = message; + } + + @Override + public int getStatus() { + return status; + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/module-admin/src/main/java/com/kernel360/brand/code/BrandErrorCode.java b/module-admin/src/main/java/com/kernel360/brand/code/BrandErrorCode.java new file mode 100644 index 00000000..47742ed7 --- /dev/null +++ b/module-admin/src/main/java/com/kernel360/brand/code/BrandErrorCode.java @@ -0,0 +1,34 @@ +package com.kernel360.brand.code; + +import com.kernel360.code.ErrorCode; +import org.springframework.http.HttpStatus; + +public enum BrandErrorCode implements ErrorCode { + FAILED_CANNOT_FOUND_ANY_BRAND(HttpStatus.NOT_FOUND.value(), "EBC001", "브랜드 목록이 비어있음"), + FAILED_ALREADY_EXISTS_BRAND(HttpStatus.BAD_REQUEST.value(), "EBC002", "생성하려는 브랜드가 이미 존재함"), + FAILED_CANNOT_FOUND_EXACT_BRAND(HttpStatus.NOT_FOUND.value(), "EBC003", "변경하려는 브랜드가 존재하지 않음"); + private final int status; + private final String code; + private final String message; + + BrandErrorCode(int status, String code, String message) { + this.status = status; + this.code = code; + this.message = message; + } + + @Override + public int getStatus() { + return status; + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} From f2930c6e6d57821e8c0508839c32c115aa7b6412 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 16:40:20 +0900 Subject: [PATCH 12/56] =?UTF-8?q?feat=20::=20BrandDto=20=EC=99=80=20?= =?UTF-8?q?=EA=B7=B8=EC=99=80=20=EA=B4=80=EB=A0=A8=EB=90=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kernel360/brand/dto/BrandDto.java | 20 ++++++++++ .../com/kernel360/brand/entity/Brand.java | 38 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 module-admin/src/main/java/com/kernel360/brand/dto/BrandDto.java diff --git a/module-admin/src/main/java/com/kernel360/brand/dto/BrandDto.java b/module-admin/src/main/java/com/kernel360/brand/dto/BrandDto.java new file mode 100644 index 00000000..2f7a22a2 --- /dev/null +++ b/module-admin/src/main/java/com/kernel360/brand/dto/BrandDto.java @@ -0,0 +1,20 @@ +package com.kernel360.brand.dto; + +import com.kernel360.brand.entity.Brand; + +public record BrandDto(Long brandNo, String brandName, String companyName, String description, String nationName) { + + public static BrandDto of(Long brandNo, String brandName, String companyName, String description, String nationName) { + return new BrandDto(brandNo, brandName, companyName, description, nationName); + } + + public static BrandDto of(String brandName, String companyName, String description, String nationName) { + return new BrandDto(null, brandName, companyName, description, nationName); + } + + public static BrandDto fromEntity(Brand brand) { + return new BrandDto(brand.getBrandNo(), brand.getBrandName(), brand.getCompanyName(), brand.getDescription(), + brand.getNationName()); + } + +} diff --git a/module-domain/src/main/java/com/kernel360/brand/entity/Brand.java b/module-domain/src/main/java/com/kernel360/brand/entity/Brand.java index 968c9df2..6b8bee1d 100644 --- a/module-domain/src/main/java/com/kernel360/brand/entity/Brand.java +++ b/module-domain/src/main/java/com/kernel360/brand/entity/Brand.java @@ -8,11 +8,14 @@ import jakarta.persistence.Id; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; +import lombok.AccessLevel; import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @Entity @Table(name = "brand") +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Brand extends BaseEntity { @Id @Column(name = "brand_no", nullable = false) @@ -31,4 +34,39 @@ public class Brand extends BaseEntity { @Column(name = "nation_name", length = Integer.MAX_VALUE) private String nationName; + + private Brand(String brandName, String companyName, String description, String nationName) { + this.brandName = brandName; + this.companyName = companyName; + this.description = description; + this.nationName = nationName; + } + + public static Brand toEntity(String brandName, String companyName, String description, String nationName) { + + return new Brand(brandName, companyName, description, nationName); + } + + public void updateDescription(String description) { + this.description = description; + } + + public void updateBrandName(String brandName) { + this.brandName = brandName; + } + + public void updateBrandCompanyName(String companyName) { + this.companyName = companyName; + } + + public void updateBrandNationName(String nationName) { + this.nationName = nationName; + } + + public void updateAll(String brandName, String companyName, String description, String nationName) { + this.brandName = brandName; + this.companyName = companyName; + this.description = description; + this.nationName = nationName; + } } \ No newline at end of file From b06a0c2b5a54fe65c3308cc0a6bc63190e6165bd Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 16:40:42 +0900 Subject: [PATCH 13/56] =?UTF-8?q?feat=20::=20Admin=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?Brand=20CRUD=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../brand/controller/BrandController.java | 98 +++++++++++++ .../kernel360/brand/service/BrandService.java | 28 ++++ .../brand/service/BrandServiceImpl.java | 133 ++++++++++++++++++ .../brand/repository/BrandRepository.java | 6 +- 4 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 module-admin/src/main/java/com/kernel360/brand/controller/BrandController.java create mode 100644 module-admin/src/main/java/com/kernel360/brand/service/BrandService.java create mode 100644 module-admin/src/main/java/com/kernel360/brand/service/BrandServiceImpl.java diff --git a/module-admin/src/main/java/com/kernel360/brand/controller/BrandController.java b/module-admin/src/main/java/com/kernel360/brand/controller/BrandController.java new file mode 100644 index 00000000..98bff98e --- /dev/null +++ b/module-admin/src/main/java/com/kernel360/brand/controller/BrandController.java @@ -0,0 +1,98 @@ +package com.kernel360.brand.controller; + +import com.kernel360.brand.code.BrandBusinessCode; +import com.kernel360.brand.dto.BrandDto; +import com.kernel360.brand.service.BrandServiceImpl; +import com.kernel360.response.ApiResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/admin/brands") +@RequiredArgsConstructor +public class BrandController { + + private final BrandServiceImpl brandService; + + @GetMapping + public ResponseEntity> getBrandList() { + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_FOUND_BRAND_LIST, brandService.findAllBrand()); + } + + @GetMapping("/brand") + public ResponseEntity> findBrandById(@RequestBody BrandDto brandDto) { + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_FOUND_EXACT_BRAND, + brandService.findBrandByBrandId(brandDto.brandNo())); + } + + @GetMapping("/brandName") + public ResponseEntity> findBrandByBrandName(@RequestBody BrandDto brandDto) { + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_FOUND_EXACT_BRAND, + brandService.findBrandByBrandName(brandDto.brandName())); + } + + + @PostMapping("/brand") + public ResponseEntity> createBrand(@RequestBody BrandDto brandDto) { + brandService.createBrand(brandDto); + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_CREATED_BRAND); + } + + @DeleteMapping("/brand") + public ResponseEntity> deleteBrand(@RequestBody BrandDto brandDto, + @RequestHeader("Authorization") String token) { + brandService.deleteBrand(brandDto.brandNo()); + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_DELETED_BRAND); + } + + @PutMapping("/brand") + public ResponseEntity> updateAll(@RequestBody BrandDto brandDto) { + brandService.updateBrand(brandDto); + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_UPDATED_BRAND); + } + + @PatchMapping("/description") + public ResponseEntity> updateBrandDescription(@RequestBody BrandDto brandDto) { + brandService.updateBrandDescription(brandDto.brandNo(), brandDto.description()); + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_UPDATED_BRAND); + } + + @PatchMapping("/brandName") + public ResponseEntity> updateBrandName(@RequestBody BrandDto brandDto) { + brandService.updateBrandName(brandDto.brandNo(), brandDto.brandName()); + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_UPDATED_BRAND); + } + + @PatchMapping("/companyName") + public ResponseEntity> updateBrandCompanyName(@RequestBody BrandDto brandDto) { + brandService.updateBrandCompanyName(brandDto.brandNo(), brandDto.companyName()); + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_UPDATED_BRAND); + } + + @PatchMapping("/nationName") + public ResponseEntity> updateBrandNationName(@RequestBody BrandDto brandDto) { + brandService.updateBrandNationName(brandDto.brandNo(), brandDto.nationName()); + + return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_UPDATED_BRAND); + } +} diff --git a/module-admin/src/main/java/com/kernel360/brand/service/BrandService.java b/module-admin/src/main/java/com/kernel360/brand/service/BrandService.java new file mode 100644 index 00000000..26f8dfdd --- /dev/null +++ b/module-admin/src/main/java/com/kernel360/brand/service/BrandService.java @@ -0,0 +1,28 @@ +package com.kernel360.brand.service; + +import com.kernel360.brand.dto.BrandDto; +import java.util.List; +import org.springframework.data.crossstore.ChangeSetPersister.NotFoundException; + +public interface BrandService { + + List findAllBrand(); + + BrandDto findBrandByBrandId(Long brandNo); + + BrandDto findBrandByBrandName(String brandName); + + void createBrand(BrandDto brandDto); + + void deleteBrand(final Long brandNo); + + void updateBrand(BrandDto brandDto); + + void updateBrandDescription(final Long brandNo, final String description); + + void updateBrandName(final Long brandNo, final String brandName); + + void updateBrandCompanyName(final Long brandNo, final String companyName); + + void updateBrandNationName(final Long brandNo, final String nationName); +} diff --git a/module-admin/src/main/java/com/kernel360/brand/service/BrandServiceImpl.java b/module-admin/src/main/java/com/kernel360/brand/service/BrandServiceImpl.java new file mode 100644 index 00000000..289ee9bc --- /dev/null +++ b/module-admin/src/main/java/com/kernel360/brand/service/BrandServiceImpl.java @@ -0,0 +1,133 @@ +package com.kernel360.brand.service; + +import com.kernel360.brand.code.BrandErrorCode; +import com.kernel360.brand.dto.BrandDto; +import com.kernel360.brand.entity.Brand; +import com.kernel360.brand.repository.BrandRepository; +import com.kernel360.exception.BusinessException; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class BrandServiceImpl implements BrandService { + + private final BrandRepository brandRepository; + + @Override + public List findAllBrand() { + List brandList = brandRepository.findAll(); + if (brandList.isEmpty()) { + throw new BusinessException(BrandErrorCode.FAILED_CANNOT_FOUND_ANY_BRAND); + } + + return brandList.stream() + .map(BrandDto::fromEntity) + .collect(Collectors.toList()); + } + + @Override + public BrandDto findBrandByBrandId(Long brandNo) { + Optional brand = brandRepository.findBrandByBrandNo(brandNo); + if (brand.isEmpty()) { + throw new BusinessException(BrandErrorCode.FAILED_CANNOT_FOUND_EXACT_BRAND); + } + + return BrandDto.fromEntity(brand.get()); + } + + @Override + public BrandDto findBrandByBrandName(String brandName) { + Brand brand = brandRepository.findBrandByBrandName(brandName) + .orElseThrow(() -> new BusinessException( + BrandErrorCode.FAILED_CANNOT_FOUND_EXACT_BRAND)); + + return BrandDto.fromEntity(brand); + } + + @Override + @Transactional + public void createBrand(BrandDto brandDto) { + Optional brand = brandRepository.findBrandByBrandName(brandDto.brandName()); + if (brand.isPresent()) { + throw new BusinessException(BrandErrorCode.FAILED_ALREADY_EXISTS_BRAND); + } + + brandRepository.save(Brand.toEntity(brandDto.brandName(), brandDto.companyName(), brandDto.description(), brandDto.nationName())); + } + + @Override + @Transactional + public void deleteBrand(Long brandNo) { + Optional brand = brandRepository.findBrandByBrandNo(brandNo); + if (brand.isEmpty()) { + throw new BusinessException(BrandErrorCode.FAILED_CANNOT_FOUND_EXACT_BRAND); + } + + brandRepository.delete(brand.get()); + } + + @Override + @Transactional + public void updateBrand(BrandDto brandDto) { + Optional brand = brandRepository.findBrandByBrandNo(brandDto.brandNo()); + if (brand.isEmpty()) { + throw new BusinessException(BrandErrorCode.FAILED_CANNOT_FOUND_EXACT_BRAND); + } + + brand.get() + .updateAll(brandDto.brandName(), brandDto.companyName(), brandDto.description(), brandDto.nationName()); + } + + @Override + @Transactional + public void updateBrandDescription(Long brandNo,String description) { + Optional brand = brandRepository.findBrandByBrandNo(brandNo); + if (brand.isEmpty()) { + throw new BusinessException(BrandErrorCode.FAILED_CANNOT_FOUND_EXACT_BRAND); + } + + brand.get().updateDescription(description); + } + + @Override + @Transactional + public void updateBrandName(Long brandNo, String brandName) { + Optional brand = brandRepository.findBrandByBrandNo(brandNo); + if (brand.isEmpty()) { + throw new BusinessException(BrandErrorCode.FAILED_CANNOT_FOUND_EXACT_BRAND); + } + + brand.get().updateBrandName(brandName); + } + + @Override + @Transactional + public void updateBrandCompanyName(Long brandNo, String companyName) { + Optional brand = brandRepository.findBrandByBrandNo(brandNo); + if (brand.isEmpty()) { + throw new BusinessException(BrandErrorCode.FAILED_CANNOT_FOUND_EXACT_BRAND); + } + + brand.get().updateBrandCompanyName(companyName); + } + + @Override + @Transactional + public void updateBrandNationName(Long brandNo, String nationName) { + Optional brand = brandRepository.findBrandByBrandNo(brandNo); + if (brand.isEmpty()) { + throw new BusinessException(BrandErrorCode.FAILED_CANNOT_FOUND_EXACT_BRAND); + } + + brand.get().updateBrandNationName(nationName); + } + + +} diff --git a/module-domain/src/main/java/com/kernel360/brand/repository/BrandRepository.java b/module-domain/src/main/java/com/kernel360/brand/repository/BrandRepository.java index 67c4a2fd..eda79edd 100644 --- a/module-domain/src/main/java/com/kernel360/brand/repository/BrandRepository.java +++ b/module-domain/src/main/java/com/kernel360/brand/repository/BrandRepository.java @@ -2,6 +2,7 @@ import com.kernel360.brand.entity.Brand; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -9,7 +10,10 @@ @Repository public interface BrandRepository extends JpaRepository { - @Query("SELECT b FROM Brand b where b.companyName like :companyName") List findByCompanyName(@Param("companyName") String companyName); + + Optional findBrandByBrandName(String brandName); + + Optional findBrandByBrandNo(Long brandNo); } From f933a983e389327a5310774459b5e77dff85a58e Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 16:40:57 +0900 Subject: [PATCH 14/56] =?UTF-8?q?feat=20::=20Admin=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?auditor=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kernel360/config/AdminAuditConfig.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 module-admin/src/main/java/com/kernel360/config/AdminAuditConfig.java diff --git a/module-admin/src/main/java/com/kernel360/config/AdminAuditConfig.java b/module-admin/src/main/java/com/kernel360/config/AdminAuditConfig.java new file mode 100644 index 00000000..d1cc5dad --- /dev/null +++ b/module-admin/src/main/java/com/kernel360/config/AdminAuditConfig.java @@ -0,0 +1,18 @@ +package com.kernel360.config; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.Optional; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.AuditorAware; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +@Configuration +public class AdminAuditConfig implements AuditorAware { + @Override + public Optional getCurrentAuditor() { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + String createId = Optional.ofNullable(request.getParameter("id")).orElse("module-admin"); + + return Optional.of(createId); + } +} From 7702973c9a4abf3f2ab99466167e93336a594af7 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 16:45:25 +0900 Subject: [PATCH 15/56] =?UTF-8?q?*=20Entity=EC=97=90=20accountType=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20null=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(dto=EC=97=94=20accountType=EA=B0=80=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=B4=EC=A7=88=20=EA=B2=BD=EC=9A=B0?= =?UTF-8?q?=EC=97=90=EB=A7=8C=20=EB=84=A3=EB=8A=94=EA=B1=B8=EB=A1=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/kernel360/member/dto/MemberDto.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/member/dto/MemberDto.java b/module-api/src/main/java/com/kernel360/member/dto/MemberDto.java index 7f7bee9e..6c5b9af9 100644 --- a/module-api/src/main/java/com/kernel360/member/dto/MemberDto.java +++ b/module-api/src/main/java/com/kernel360/member/dto/MemberDto.java @@ -89,7 +89,8 @@ public Member toEntity() { this.email(), this.password(), Gender.valueOf(this.gender()).ordinal(), - Age.valueOf(this.age()).ordinal() + Age.valueOf(this.age()).ordinal(), + null ); } From 7e69ab6ac1a9db4c52994e9bb1f823e04ab562e1 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 16:45:29 +0900 Subject: [PATCH 16/56] =?UTF-8?q?chore=20::=20=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20Authorization=20=ED=97=A4=EB=8D=94=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/kernel360/brand/code/BrandBusinessCode.java | 2 +- .../java/com/kernel360/brand/controller/BrandController.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/module-admin/src/main/java/com/kernel360/brand/code/BrandBusinessCode.java b/module-admin/src/main/java/com/kernel360/brand/code/BrandBusinessCode.java index 1786c312..a9573bf7 100644 --- a/module-admin/src/main/java/com/kernel360/brand/code/BrandBusinessCode.java +++ b/module-admin/src/main/java/com/kernel360/brand/code/BrandBusinessCode.java @@ -9,7 +9,7 @@ public enum BrandBusinessCode implements BusinessCode { SUCCESS_FOUND_EXACT_BRAND(HttpStatus.OK.value(),"BMB002","브랜드 상세 조회 성공"), SUCCESS_CREATED_BRAND(HttpStatus.CREATED.value(), "BMB003","브랜드 추가 성공" ), SUCCESS_DELETED_BRAND(HttpStatus.OK.value(), "BMB004","브랜드 삭제 성공"), - SUCCESS_UPDATED_BRAND(HttpStatus.OK.value(), "BMB005","브랜드 업데이트 성곡" ); + SUCCESS_UPDATED_BRAND(HttpStatus.OK.value(), "BMB005","브랜드 업데이트 성공" ); private final int status; diff --git a/module-admin/src/main/java/com/kernel360/brand/controller/BrandController.java b/module-admin/src/main/java/com/kernel360/brand/controller/BrandController.java index 98bff98e..49846fbd 100644 --- a/module-admin/src/main/java/com/kernel360/brand/controller/BrandController.java +++ b/module-admin/src/main/java/com/kernel360/brand/controller/BrandController.java @@ -54,8 +54,7 @@ public ResponseEntity> createBrand(@RequestBody BrandDto bra } @DeleteMapping("/brand") - public ResponseEntity> deleteBrand(@RequestBody BrandDto brandDto, - @RequestHeader("Authorization") String token) { + public ResponseEntity> deleteBrand(@RequestBody BrandDto brandDto) { brandService.deleteBrand(brandDto.brandNo()); return ApiResponse.toResponseEntity(BrandBusinessCode.SUCCESS_DELETED_BRAND); From 0ce93068a900dc5a6e7e4cec35c5ce44522cecad Mon Sep 17 00:00:00 2001 From: Younglong Date: Thu, 29 Feb 2024 16:49:31 +0900 Subject: [PATCH 17/56] =?UTF-8?q?feat:=20=EB=A6=AC=EB=B7=B0=EB=B2=88?= =?UTF-8?q?=ED=98=B8=EC=88=9C=20=EC=A0=95=EB=A0=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/kernel360/review/service/ReviewService.java | 2 +- .../java/com/kernel360/review/repository/ReviewRepository.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java index 12fec214..c1b6d15d 100644 --- a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java +++ b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java @@ -27,7 +27,7 @@ public class ReviewService { public Page getReviewsByProduct(Long productNo, Pageable pageable) { log.info("제품 리뷰 목록 조회 -> product_no {}", productNo); - return reviewRepository.findAllByProduct_ProductNo(productNo, pageable) + return reviewRepository.findAllByProduct_ProductNoOrderByReviewNoDesc(productNo, pageable) .map(ReviewDto::from); } diff --git a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java index b2ad507e..282f3635 100644 --- a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java +++ b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java @@ -6,7 +6,7 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface ReviewRepository extends JpaRepository { - Page findAllByProduct_ProductNo(Long productNo, Pageable pageable); + Page findAllByProduct_ProductNoOrderByReviewNoDesc(Long productNo, Pageable pageable); Review findByReviewNo(Long reviewNo); } From cff8dbcf83963c69f29acfaaf92948ab807a6184 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 16:54:46 +0900 Subject: [PATCH 18/56] =?UTF-8?q?*=20AccountType=20enum=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95=20=ED=8F=BC?= =?UTF-8?q?=20=EA=B0=80=EC=9E=85=EC=8B=9C=20type=20platform=20value=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20=EA=B0=80?= =?UTF-8?q?=EC=9E=85=EC=8B=9C=20type=20kakao=20value=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20*=20=ED=9A=8C=EC=9B=90=20=ED=83=88=ED=87=B4=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EA=B0=80=20=EC=A4=91=EB=B3=B5=EC=9D=B4=EB=AF=80?= =?UTF-8?q?=EB=A1=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=91=ED=95=A9=20?= =?UTF-8?q?=EC=9E=91=EC=97=85=20=EC=A7=84=ED=96=89=20*=20=EC=95=BD?= =?UTF-8?q?=EA=B0=84=EC=9D=98=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/service/MemberService.java | 27 +++++++------------ .../mypage/controller/MyPageController.java | 3 --- .../member/entity/WithdrawMember.java | 4 +-- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/service/MemberService.java b/module-api/src/main/java/com/kernel360/member/service/MemberService.java index c7b7e7b3..8c6f086b 100644 --- a/module-api/src/main/java/com/kernel360/member/service/MemberService.java +++ b/module-api/src/main/java/com/kernel360/member/service/MemberService.java @@ -9,6 +9,7 @@ import com.kernel360.member.dto.*; import com.kernel360.member.entity.Member; import com.kernel360.member.entity.WithdrawMember; +import com.kernel360.member.enumset.AccountType; import com.kernel360.member.enumset.Age; import com.kernel360.member.enumset.Gender; import com.kernel360.member.repository.MemberRepository; @@ -63,7 +64,7 @@ protected Member getNewJoinMemberEntity(MemberDto requestDto) { throw new BusinessException(MemberErrorCode.FAILED_NOT_MAPPING_ENUM_VALUE_OF); } - return Member.createJoinMember(requestDto.id(), requestDto.email(), encodePassword, genderOrdinal, ageOrdinal); + return Member.createJoinMember(requestDto.id(), requestDto.email(), encodePassword, genderOrdinal, ageOrdinal, AccountType.PLATFORM.name()); } @Transactional @@ -78,6 +79,7 @@ public MemberDto login(MemberDto loginDto, HttpServletRequest request) { String loginToken = jwt.generateToken(memberEntity.getId()); + //TODO REFACTOR AUTH 정보를 RDB -> 래디스로 변경 authService.saveAuthByMember(memberEntity.getMemberNo(), ConvertSHA256.convertToSHA256(loginToken), request); return MemberDto.login(memberEntity, loginToken); @@ -123,12 +125,11 @@ public void deleteMember(String id) { } @Transactional - public void deleteMemberByToken(String token) { - final String id = JWT.ownerId(token); - Member member = memberRepository.findOneById(id); - //Fixme :: 멤버 탈퇴시, Deleted Table을 만들고, 데이터를 백업한후, 삭제하는 방식이나, MemberTable에 삭제여부를 표시하는 방식으로 리팩토링 필요 + public void deleteMemberByToken(String accessToken) { + Member member = memberRepository.findOneById(JWT.ownerId(accessToken)); + withdrawMemberRepository.save(WithdrawMember.of(member)); //of 받는식을 변경했습니다. 이 방식으로 리팩터를 하면 코드가 깔끔하네요. memberRepository.delete(member); - log.info("{} 회원 탈퇴 처리 완료", id); + log.info("{} 회원 탈퇴 처리 완료", accessToken); } @Transactional @@ -253,28 +254,20 @@ public MemberDto loginForKakao(String accessToken, HttpServletRequest request) { KakaoUserDto kakaoUser = kakaoRequest.getKakaoUserByToken(accessToken); if (Objects.isNull(memberRepository.findOneById(kakaoUser.id()))) { memberRepository.save( - Member.createForKakao(kakaoUser.id(), kakaoUser.email(), "kakao", Gender.OTHERS.ordinal(), - Age.AGE_99.ordinal())); + Member.createJoinMember(kakaoUser.id(), kakaoUser.email(), "kakao", Gender.OTHERS.ordinal(), + Age.AGE_99.ordinal(), AccountType.KAKAO.name())); } MemberDto memberDto = MemberDto.from(memberRepository.findOneById(kakaoUser.id())); String loginToken = jwt.generateToken(memberDto.id()); + //TODO REFACTOR AUTH 정보를 RDB -> 래디스로 변경 authService.saveAuthByMember(memberDto.memberNo(), ConvertSHA256.convertToSHA256(loginToken), request); return MemberDto.fromKakao(memberDto, loginToken); } - @Transactional - public void signOut(String accessToken) { - Member member = memberRepository.findOneById(JWT.ownerId(accessToken)); - - withdrawMemberRepository.save(WithdrawMember.of(member.getMemberNo(),member.getId(), member.getEmail(), null)); - - memberRepository.delete(member); - } - @Transactional(readOnly = true) public boolean validatePassword(String password, String token) { String id = JWT.ownerId(token); diff --git a/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java b/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java index ec35ab86..7fd9cf77 100644 --- a/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java +++ b/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java @@ -47,7 +47,6 @@ ResponseEntity> myWash(@RequestHeader("Authorization") return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_FIND_WASH_INFO_IN_MEMBER, washInfoDto); } - @DeleteMapping("/member") ResponseEntity> memberDelete(@RequestHeader("Authorization") String authToken) { memberService.deleteMemberByToken(authToken); @@ -55,7 +54,6 @@ ResponseEntity> memberDelete(@RequestHeader("Authorization") S return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_DELETE_MEMBER); } - @PostMapping("/member") ResponseEntity> changePassword(@RequestBody String password, @RequestHeader("Authorization") String authToken) { memberService.changePassword(password, authToken); @@ -69,7 +67,6 @@ boolean validatePassword(@RequestBody PasswordDto password, @RequestHeader("Auth return memberService.validatePassword(password.password(), authToken); } - @PatchMapping("/member") ResponseEntity> updateMember(@RequestBody MemberInfo memberInfo, @RequestHeader("Authorization") String authToken) { diff --git a/module-domain/src/main/java/com/kernel360/member/entity/WithdrawMember.java b/module-domain/src/main/java/com/kernel360/member/entity/WithdrawMember.java index 25f4c976..9ee4dde3 100644 --- a/module-domain/src/main/java/com/kernel360/member/entity/WithdrawMember.java +++ b/module-domain/src/main/java/com/kernel360/member/entity/WithdrawMember.java @@ -29,9 +29,9 @@ public class WithdrawMember extends BaseEntity { private String ip; - public static WithdrawMember of(Long memberNo, String id, String email, String ip) { + public static WithdrawMember of(Member member) { - return new WithdrawMember(memberNo, id, email, ip); + return new WithdrawMember(member.getMemberNo(), member.getId(), member.getEmail(), null); //IP정보를 저장한다면 파라메터를 추가해야 } private WithdrawMember( From 9ca40f49f3d492533f18bae3e3f4968c614c1688 Mon Sep 17 00:00:00 2001 From: Younglong Date: Thu, 29 Feb 2024 16:57:01 +0900 Subject: [PATCH 19/56] =?UTF-8?q?feat:=20flyway=20sql=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - memeber table grant 관련 제거 (추후 지용님 작업에 올라올 예정으로 겹침) - review table 제약조건 추가 --- .../db/migration/V1.0.10__add_unique_constraint_review.sql | 4 ++++ .../db/migration/V1.0.10__grant_references_on_member.sql | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 module-api/src/main/resources/db/migration/V1.0.10__add_unique_constraint_review.sql delete mode 100644 module-api/src/main/resources/db/migration/V1.0.10__grant_references_on_member.sql diff --git a/module-api/src/main/resources/db/migration/V1.0.10__add_unique_constraint_review.sql b/module-api/src/main/resources/db/migration/V1.0.10__add_unique_constraint_review.sql new file mode 100644 index 00000000..57ef4e13 --- /dev/null +++ b/module-api/src/main/resources/db/migration/V1.0.10__add_unique_constraint_review.sql @@ -0,0 +1,4 @@ +ALTER TABLE REVIEW DROP CONSTRAINT IF EXISTS review_ukey; + +ALTER TABLE REVIEW + ADD CONSTRAINT review_ukey UNIQUE (MEMBER_NO, PRODUCT_NO); \ No newline at end of file diff --git a/module-api/src/main/resources/db/migration/V1.0.10__grant_references_on_member.sql b/module-api/src/main/resources/db/migration/V1.0.10__grant_references_on_member.sql deleted file mode 100644 index 26b6bc7e..00000000 --- a/module-api/src/main/resources/db/migration/V1.0.10__grant_references_on_member.sql +++ /dev/null @@ -1 +0,0 @@ -GRANT REFERENCES ON TABLE member TO wash_admin; \ No newline at end of file From a19ee50e9578f7c5c1554b98341f40d83d45ecfb Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 17:10:42 +0900 Subject: [PATCH 20/56] =?UTF-8?q?feat=20::=20=EC=84=B8=EC=B0=A8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EA=B0=80=20=EC=97=86=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?400=20=EB=A9=94=EC=8B=9C=EC=A7=80=EB=A5=BC=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=A7=81=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/kernel360/member/dto/MemberInfo.java | 6 ++---- .../java/com/kernel360/member/service/MemberService.java | 9 ++++++--- .../kernel360/mypage/controller/MyPageController.java | 3 +-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/dto/MemberInfo.java b/module-api/src/main/java/com/kernel360/member/dto/MemberInfo.java index 8170602f..c82bc74e 100644 --- a/module-api/src/main/java/com/kernel360/member/dto/MemberInfo.java +++ b/module-api/src/main/java/com/kernel360/member/dto/MemberInfo.java @@ -1,10 +1,8 @@ package com.kernel360.member.dto; - - public record MemberInfo( - int gender, - int age + int gender, + int age ) { } \ No newline at end of file diff --git a/module-api/src/main/java/com/kernel360/member/service/MemberService.java b/module-api/src/main/java/com/kernel360/member/service/MemberService.java index c7b7e7b3..167ca717 100644 --- a/module-api/src/main/java/com/kernel360/member/service/MemberService.java +++ b/module-api/src/main/java/com/kernel360/member/service/MemberService.java @@ -173,14 +173,17 @@ public Map getCarInfo(String token) { } @Transactional(readOnly = true) - public Optional getWashInfo(String token) { + public WashInfoDto getWashInfo(String token) { String id = JWT.ownerId(token); Member member = memberRepository.findOneById(id); if (member == null) { throw new BusinessException(MemberErrorCode.FAILED_FIND_MEMBER_INFO); } - - return Optional.of(WashInfoDto.from(member.getWashInfo())); + WashInfo washInfo = member.getWashInfo(); + if(washInfo == null){ + throw new BusinessException(MemberErrorCode.FAILED_FIND_MEMBER_WASH_INFO); + } + return WashInfoDto.from(washInfo); } @Transactional diff --git a/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java b/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java index ec35ab86..e848d759 100644 --- a/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java +++ b/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java @@ -41,8 +41,7 @@ ResponseEntity>> myCar(@RequestHeader("Authoriza @GetMapping("/wash") ResponseEntity> myWash(@RequestHeader("Authorization") String authToken) { - WashInfoDto washInfoDto = memberService.getWashInfo(authToken) - .orElseThrow(() -> new BusinessException(MemberErrorCode.FAILED_FIND_MEMBER_WASH_INFO)); + WashInfoDto washInfoDto = memberService.getWashInfo(authToken); return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_FIND_WASH_INFO_IN_MEMBER, washInfoDto); } From 68bfa3a99d129c2f1d8e31dba5bdd86c2a84f706 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 17:40:25 +0900 Subject: [PATCH 21/56] =?UTF-8?q?*=20=EB=B9=8C=EB=93=9C=EC=97=90=EB=9F=AC?= =?UTF-8?q?=20=EB=B0=A9=EC=A7=80=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kernel360/member/entity/MemberTest.java | 3 ++- .../com/kernel360/member/service/MemberServiceTest.java | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/module-api/src/test/java/com/kernel360/member/entity/MemberTest.java b/module-api/src/test/java/com/kernel360/member/entity/MemberTest.java index df6d9809..0b8e8130 100644 --- a/module-api/src/test/java/com/kernel360/member/entity/MemberTest.java +++ b/module-api/src/test/java/com/kernel360/member/entity/MemberTest.java @@ -1,5 +1,6 @@ package com.kernel360.member.entity; +import com.kernel360.member.enumset.AccountType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,7 +26,7 @@ class MemberTest { gender = 0; age = 3; - member = Member.of(memberNo, id, email, password, gender, age); + member = Member.of(memberNo, id, email, password, gender, age, AccountType.PLATFORM.name()); } @Test diff --git a/module-api/src/test/java/com/kernel360/member/service/MemberServiceTest.java b/module-api/src/test/java/com/kernel360/member/service/MemberServiceTest.java index 86803709..ab8986d9 100644 --- a/module-api/src/test/java/com/kernel360/member/service/MemberServiceTest.java +++ b/module-api/src/test/java/com/kernel360/member/service/MemberServiceTest.java @@ -5,6 +5,7 @@ import com.kernel360.auth.service.AuthService; import com.kernel360.member.dto.MemberDto; import com.kernel360.member.entity.Member; +import com.kernel360.member.enumset.AccountType; import com.kernel360.member.repository.MemberRepository; import com.kernel360.utils.ConvertSHA256; import com.kernel360.utils.JWT; @@ -87,7 +88,7 @@ public void init() { MemberDto loginDto = MemberDto.of("test03", "1234qwer"); Member mockLoginEntity = Member.loginMember(loginDto.id(), loginDto.password()); Member mockEntity = Member.of(502L, loginDto.id(), "test03@naver.com", - "0eb9de69892882d54516e03e30098354a2e39cea36adab275b6300c737c942fd", 0, 0); + "0eb9de69892882d54516e03e30098354a2e39cea36adab275b6300c737c942fd", 0, 0, AccountType.PLATFORM.name()); String mockToken = "dummy_token"; /** stub **/ @@ -111,7 +112,7 @@ public void init() { void 토큰_발급_저장_테스트() { /** given **/ - Member memberEntity = Member.of(502L, "test03", null, null, 0, 0); + Member memberEntity = Member.of(502L, "test03", null, null, 0, 0, AccountType.PLATFORM.name()); String mockToken = "mockToken"; Auth auth = Auth.jwt(null, 502L, mockToken); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -143,7 +144,7 @@ public void init() { /** given **/ String id = "test01"; - Member memberEntity = Member.of(51L, "test01", null, null, 0, 0); + Member memberEntity = Member.of(51L, "test01", null, null, 0, 0, AccountType.PLATFORM.name()); /** stub **/ when(memberRepository.findOneById(anyString())).thenReturn(memberEntity); @@ -182,7 +183,7 @@ public void init() { /** given **/ String email = "kernel360@kernel360.co.kr"; - Member memberEntity = Member.of(51L, "test01", "kernel360@kernel360.co.kr", null, 0, 0); + Member memberEntity = Member.of(51L, "test01", "kernel360@kernel360.co.kr", null, 0, 0, AccountType.PLATFORM.name()); /** stub **/ when(memberRepository.findOneByEmail(anyString())).thenReturn(memberEntity); From 6f3760dec9070008718733394e15e673b768b533 Mon Sep 17 00:00:00 2001 From: gunsight <103917282+gunsight1@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:56:01 +0900 Subject: [PATCH 22/56] Update MemberController.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 소스 에러 병합 --- .../com/kernel360/member/controller/MemberController.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java index 18f7c26f..4a2469d7 100644 --- a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java +++ b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java @@ -118,11 +118,4 @@ public ResponseEntity> loginForKakao(@RequestHeader("Auth return ApiResponse.toResponseEntity(SUCCESS_REQUEST_LOGIN_MEMBER, member); } - @GetMapping("/signout") - public ResponseEntity> signOut(@RequestHeader("Authorization") String accessToken) { - - memberService.signOut(accessToken); - - return ApiResponse.toResponseEntity(SUCCESS_REQUEST_SIGN_OUT_MEMBER); - } } From a0d08722270336c77e91fc14326dbf6f31ee7964 Mon Sep 17 00:00:00 2001 From: Younglong Date: Thu, 29 Feb 2024 18:31:04 +0900 Subject: [PATCH 23/56] =?UTF-8?q?feat:=20=EB=93=B1=EB=A1=9D/=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=97=90=20try-catch=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 등록/수정 시 유니크 키에 대한 무결성 exception 발생할 수 있어 내용 추가 --- .../kernel360/review/code/ReviewErrorCode.java | 3 ++- .../review/service/ReviewService.java | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/review/code/ReviewErrorCode.java b/module-api/src/main/java/com/kernel360/review/code/ReviewErrorCode.java index 6ea8b524..7ff710ec 100644 --- a/module-api/src/main/java/com/kernel360/review/code/ReviewErrorCode.java +++ b/module-api/src/main/java/com/kernel360/review/code/ReviewErrorCode.java @@ -6,7 +6,8 @@ @RequiredArgsConstructor public enum ReviewErrorCode implements ErrorCode { - INVALID_STAR_RATING_VALUE(HttpStatus.BAD_REQUEST.value(), "ERV001", "유효하지 않은 별점입니다."); + INVALID_STAR_RATING_VALUE(HttpStatus.BAD_REQUEST.value(), "ERV001", "유효하지 않은 별점입니다."), + INVALID_REVIEW_WRITE_REQUEST(HttpStatus.BAD_REQUEST.value(), "ERV002", "리뷰가 중복되거나 유효하지 않습니다."); private final int status; private final String code; diff --git a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java index c1b6d15d..23f01ab4 100644 --- a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java +++ b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java @@ -7,6 +7,7 @@ import com.kernel360.review.repository.ReviewRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -42,9 +43,15 @@ public ReviewDto getReview(Long reviewNo) { public Review createReview(ReviewDto reviewDto) { isValidStarRating(reviewDto.starRating()); - Review review = reviewRepository.save(reviewDto.toEntity()); - log.info("리뷰 등록 -> review_no {}", review.getReviewNo()); + Review review; + + try { + review = reviewRepository.saveAndFlush(reviewDto.toEntity()); + } catch (DataIntegrityViolationException e) { + throw new BusinessException(ReviewErrorCode.INVALID_REVIEW_WRITE_REQUEST); + } + log.info("리뷰 등록 -> review_no {}", review.getReviewNo()); return review; } @@ -53,7 +60,12 @@ public Review createReview(ReviewDto reviewDto) { public void updateReview(ReviewDto reviewDto) { isValidStarRating(reviewDto.starRating()); - reviewRepository.save(reviewDto.toEntity()); + try { + reviewRepository.saveAndFlush(reviewDto.toEntity()); + } catch (DataIntegrityViolationException e) { + throw new BusinessException(ReviewErrorCode.INVALID_REVIEW_WRITE_REQUEST); + } + log.info("리뷰 수정 -> review_no {}", reviewDto.reviewNo()); } From 8b65787b9053b8763e07f458963b9f1c5d9c9958 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 18:34:19 +0900 Subject: [PATCH 24/56] =?UTF-8?q?*=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80=EC=8B=9C=20=EC=A1=B4?= =?UTF-8?q?=EC=9E=AC=EC=97=AC=EB=B6=80=EB=A5=BC=20=ED=8C=90=EB=8B=A8=20?= =?UTF-8?q?=ED=95=9C=20=ED=9B=84=20=EC=88=98=ED=96=89=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20PLSQL=EB=A1=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/migration/V1.0.9__add_clientIP_to_auth.sql | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql b/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql index 579e6241..07e58912 100644 --- a/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql +++ b/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql @@ -1,2 +1,11 @@ -ALTER TABLE auth - ADD COLUMN client_ip varchar; \ No newline at end of file +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_name = 'auth' + AND column_name = 'client_ip' + ) THEN +ALTER TABLE auth ADD COLUMN client_ip VARCHAR; +END IF; +END $$; \ No newline at end of file From d00e2cffbe200463248a51ef6a0cc0d1782b6f19 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 18:36:38 +0900 Subject: [PATCH 25/56] =?UTF-8?q?Revert=20"*=20=ED=85=8C=EC=9D=B4=EB=B8=94?= =?UTF-8?q?=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80=EC=8B=9C=20=EC=A1=B4?= =?UTF-8?q?=EC=9E=AC=EC=97=AC=EB=B6=80=EB=A5=BC=20=ED=8C=90=EB=8B=A8=20?= =?UTF-8?q?=ED=95=9C=20=ED=9B=84=20=EC=88=98=ED=96=89=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20PLSQL=EB=A1=9C=20=EC=9E=91=EC=84=B1"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 8b65787b9053b8763e07f458963b9f1c5d9c9958. --- .../db/migration/V1.0.9__add_clientIP_to_auth.sql | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql b/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql index 07e58912..579e6241 100644 --- a/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql +++ b/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql @@ -1,11 +1,2 @@ -DO $$ -BEGIN - IF NOT EXISTS ( - SELECT 1 - FROM information_schema.columns - WHERE table_name = 'auth' - AND column_name = 'client_ip' - ) THEN -ALTER TABLE auth ADD COLUMN client_ip VARCHAR; -END IF; -END $$; \ No newline at end of file +ALTER TABLE auth + ADD COLUMN client_ip varchar; \ No newline at end of file From 290d11e223b5ab8cc1923d6c00e9c6ac9269e3db Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 19:29:11 +0900 Subject: [PATCH 26/56] =?UTF-8?q?feat=20::=20GlobalExceptionHandler=20?= =?UTF-8?q?=EC=97=90=20=EC=B2=98=EB=A6=AC=ED=95=A0=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../code/common/CommonErrorCode.java | 3 +- .../com/kernel360/code/jwt/JwtErrorCode.java | 33 +++++++++++++++++++ .../handler/GlobalExceptionHandler.java | 30 +++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 module-common/src/main/java/com/kernel360/code/jwt/JwtErrorCode.java diff --git a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java index 07ce8680..c55942a7 100644 --- a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java +++ b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java @@ -6,7 +6,8 @@ public enum CommonErrorCode implements ErrorCode { INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "E001", "Server Error"), FAIL_FILE_UPLOAD(HttpStatus.INTERNAL_SERVER_ERROR.value(), "E002", "파일 업로드 실패"), - INVALID_FILE_EXTENSION(HttpStatus.BAD_REQUEST.value(), "E003", "유효하지 않은 파일 확장자"); + INVALID_FILE_EXTENSION(HttpStatus.BAD_REQUEST.value(), "E003", "유효하지 않은 파일 확장자"), + NOT_FOUND_RESOURCE(HttpStatus.NOT_FOUND.value(), "E004", "요청한 자원이 존재하지 않음"); private final int status; private final String code; diff --git a/module-common/src/main/java/com/kernel360/code/jwt/JwtErrorCode.java b/module-common/src/main/java/com/kernel360/code/jwt/JwtErrorCode.java new file mode 100644 index 00000000..f41c6058 --- /dev/null +++ b/module-common/src/main/java/com/kernel360/code/jwt/JwtErrorCode.java @@ -0,0 +1,33 @@ +package com.kernel360.code.jwt; + +import com.kernel360.code.ErrorCode; +import org.springframework.http.HttpStatus; + +public enum JwtErrorCode implements ErrorCode { + FAILED_MALFORMED_JWT(HttpStatus.BAD_REQUEST.value(), "EJC001", "유효하지 않은 JWT 문자열 형식입니다."), + FAILED_SIGNATURE_JWT(HttpStatus.BAD_REQUEST.value(), "EJC001", "JWT 시그니처가 서버에서 계산한 시그니처와 일치하지 않습니다."); + private final int status; + private final String code; + private final String message; + + JwtErrorCode(int status, String code, String message) { + this.status = status; + this.code = code; + this.message = message; + } + + @Override + public int getStatus() { + return status; + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java index b1f6a16b..ca43db49 100644 --- a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java @@ -2,8 +2,11 @@ import com.kernel360.code.ErrorCode; import com.kernel360.code.common.CommonErrorCode; +import com.kernel360.code.jwt.JwtErrorCode; import com.kernel360.exception.BusinessException; import com.kernel360.response.ErrorResponse; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.security.SignatureException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -31,4 +34,31 @@ protected ResponseEntity handleException(Exception e) { return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } + + @ExceptionHandler(MalformedJwtException.class) + protected ResponseEntity handleMalformedJwtException(final MalformedJwtException e) { + log.error("handleMalformedJwtException", e); + + final ErrorResponse response = ErrorResponse.of(JwtErrorCode.FAILED_MALFORMED_JWT); + + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(SignatureException.class) + protected ResponseEntity handleJwtSignatureException(final SignatureException e) { + log.error("handleJwtSignatureException", e); + + final ErrorResponse response = ErrorResponse.of(JwtErrorCode.FAILED_SIGNATURE_JWT); + + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(NullPointerException.class) + protected ResponseEntity handleNullPointerException(final NullPointerException e) { + log.error("handleNullPointerException", e); + + final ErrorResponse response = ErrorResponse.of(CommonErrorCode.NOT_FOUND_RESOURCE); + + return new ResponseEntity<>(response, HttpStatus.NOT_FOUND); + } } From bed7ed182b0ff02eb5ccc5d5777e0a565133dde9 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 19:52:52 +0900 Subject: [PATCH 27/56] =?UTF-8?q?feat=20::=20GlobalExceptionHandler=20?= =?UTF-8?q?=EC=97=90=20MissingRequestHeaderException=20=EC=B2=98=EB=A6=AC?= =?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 --- .../com/kernel360/code/common/CommonErrorCode.java | 3 ++- .../com/kernel360/handler/GlobalExceptionHandler.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java index c55942a7..91c23864 100644 --- a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java +++ b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java @@ -7,7 +7,8 @@ public enum CommonErrorCode implements ErrorCode { INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "E001", "Server Error"), FAIL_FILE_UPLOAD(HttpStatus.INTERNAL_SERVER_ERROR.value(), "E002", "파일 업로드 실패"), INVALID_FILE_EXTENSION(HttpStatus.BAD_REQUEST.value(), "E003", "유효하지 않은 파일 확장자"), - NOT_FOUND_RESOURCE(HttpStatus.NOT_FOUND.value(), "E004", "요청한 자원이 존재하지 않음"); + NOT_FOUND_RESOURCE(HttpStatus.NOT_FOUND.value(), "E004", "요청한 자원이 존재하지 않음"), + INVALID_REQUEST_HEADERS(HttpStatus.BAD_REQUEST.value(), "E005", "요청한 헤더가 존재하지 않음"); private final int status; private final String code; diff --git a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java index ca43db49..8e95cb17 100644 --- a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MissingRequestHeaderException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -61,4 +62,13 @@ protected ResponseEntity handleNullPointerException(final NullPoi return new ResponseEntity<>(response, HttpStatus.NOT_FOUND); } + + @ExceptionHandler(MissingRequestHeaderException.class) + protected ResponseEntity handleMissingHeaderException(final MissingRequestHeaderException e) { + log.error("handleMissingHeaderException", e); + + final ErrorResponse response = ErrorResponse.of(CommonErrorCode.INVALID_REQUEST_HEADERS); + + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } } From ffde7a61c118c9b8b4a406bb7270e0784c2099ae Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 20:07:44 +0900 Subject: [PATCH 28/56] =?UTF-8?q?*=20=ED=94=84=EB=A1=A0=ED=8A=B8=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20=EA=B0=9C=EB=B0=9C=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EC=9A=A9=20localhost:3000=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/kernel360/global/config/WebConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java index ee5e13d9..f79175a0 100644 --- a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java +++ b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java @@ -26,7 +26,7 @@ public void addCorsMappings(CorsRegistry registry) { .allowedHeaders("*") .allowedMethods("*") .allowCredentials(true) - .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site") + .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000") .maxAge(3600); } } From 16966579f5f951792c54742ec3774e59774a71c3 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Thu, 29 Feb 2024 20:10:51 +0900 Subject: [PATCH 29/56] =?UTF-8?q?*=20=EC=9D=B4=EB=A0=A5=20=EB=B6=88?= =?UTF-8?q?=EC=9D=BC=EC=B9=98=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20sql=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=9E=AC=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/migration/V1.0.9__add_clientIP_to_auth.sql | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql b/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql index 579e6241..07e58912 100644 --- a/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql +++ b/module-api/src/main/resources/db/migration/V1.0.9__add_clientIP_to_auth.sql @@ -1,2 +1,11 @@ -ALTER TABLE auth - ADD COLUMN client_ip varchar; \ No newline at end of file +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_name = 'auth' + AND column_name = 'client_ip' + ) THEN +ALTER TABLE auth ADD COLUMN client_ip VARCHAR; +END IF; +END $$; \ No newline at end of file From 4da697d7fcc7606327bcc34dff921189fefbcc77 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 20:34:09 +0900 Subject: [PATCH 30/56] squash & merge --- .../src/main/java/com/kernel360/global/config/WebConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java index ee5e13d9..f79175a0 100644 --- a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java +++ b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java @@ -26,7 +26,7 @@ public void addCorsMappings(CorsRegistry registry) { .allowedHeaders("*") .allowedMethods("*") .allowCredentials(true) - .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site") + .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000") .maxAge(3600); } } From bfb971e806d2bd0279a2fda0d0f3a547b2521f4a Mon Sep 17 00:00:00 2001 From: cgk95 Date: Thu, 29 Feb 2024 20:35:18 +0900 Subject: [PATCH 31/56] squash&merge --- .../src/main/java/com/kernel360/global/config/WebConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java index ee5e13d9..f79175a0 100644 --- a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java +++ b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java @@ -26,7 +26,7 @@ public void addCorsMappings(CorsRegistry registry) { .allowedHeaders("*") .allowedMethods("*") .allowCredentials(true) - .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site") + .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000") .maxAge(3600); } } From 2b98a248e6b2607fa752aac2c36bc3090037d6e7 Mon Sep 17 00:00:00 2001 From: HyunJunSon Date: Thu, 29 Feb 2024 21:23:52 +0900 Subject: [PATCH 32/56] =?UTF-8?q?chore::=20interceptor=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kernel360/global/Interceptor/InterceptorConfig.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java b/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java index 1dbb1a02..85aa2a07 100644 --- a/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java +++ b/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java @@ -14,8 +14,9 @@ public class InterceptorConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(acceptInterceptor) .addPathPatterns("/auth/**") //** 인증 JWT 토큰 관련 **// - .addPathPatterns("/reviews/**"); -// .addPathPatterns("/mypage/**"); + .addPathPatterns("/reviews/**") + .addPathPatterns("/likes/**") + .addPathPatterns("/mypage/**"); //.excludePathPatterns("/public/**"); // 제외할 URL 패턴 } From 2e2bab518e68835511a19e18a6b8a7590e6bdb91 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 19:02:27 +0900 Subject: [PATCH 33/56] =?UTF-8?q?develop=20=EB=B8=8C=EB=9E=9C=EC=B9=98=20?= =?UTF-8?q?=EC=B5=9C=EC=8B=A0=20=EB=B3=80=EA=B2=BD=EC=82=AC=ED=95=AD=20squ?= =?UTF-8?q?ash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/Interceptor/AcceptInterceptor.java | 25 ++++++++++++ .../global/Interceptor/InterceptorConfig.java | 6 ++- .../review/code/ReviewErrorCode.java | 3 +- .../review/controller/ReviewController.java | 12 +++--- .../review/service/ReviewService.java | 35 ++++++++++++---- .../V1.0.10__add_unique_constraint_review.sql | 4 ++ .../code/common/CommonErrorCode.java | 4 +- .../com/kernel360/code/jwt/JwtErrorCode.java | 33 +++++++++++++++ .../handler/GlobalExceptionHandler.java | 40 +++++++++++++++++++ .../review/repository/ReviewRepository.java | 6 +-- 10 files changed, 147 insertions(+), 21 deletions(-) create mode 100644 module-api/src/main/resources/db/migration/V1.0.10__add_unique_constraint_review.sql create mode 100644 module-common/src/main/java/com/kernel360/code/jwt/JwtErrorCode.java diff --git a/module-api/src/main/java/com/kernel360/global/Interceptor/AcceptInterceptor.java b/module-api/src/main/java/com/kernel360/global/Interceptor/AcceptInterceptor.java index df2ede03..4ef9d5d9 100644 --- a/module-api/src/main/java/com/kernel360/global/Interceptor/AcceptInterceptor.java +++ b/module-api/src/main/java/com/kernel360/global/Interceptor/AcceptInterceptor.java @@ -6,10 +6,13 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpMethod; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.servlet.HandlerInterceptor; +import java.util.Objects; + @Component @RequiredArgsConstructor public class AcceptInterceptor implements HandlerInterceptor { @@ -18,6 +21,10 @@ public class AcceptInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + if (validateTargetUri(request)) { + return true; + } + boolean result = true; String requestToken = request.getHeader("Authorization"); @@ -33,4 +40,22 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons return result; } + private boolean validateTargetUri(HttpServletRequest request) { + String requestURI = request.getRequestURI(); + String method = request.getMethod(); + + if (Objects.isNull(requestURI)) { + return false; + } + + if (!requestURI.startsWith("/reviews")) { + return false; + } + + if (HttpMethod.GET.matches(method)) { + return true; + } + + return false; + } } diff --git a/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java b/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java index 2ba476d2..85aa2a07 100644 --- a/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java +++ b/module-api/src/main/java/com/kernel360/global/Interceptor/InterceptorConfig.java @@ -13,8 +13,10 @@ public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(acceptInterceptor) - .addPathPatterns("/auth/**"); //** 인증 JWT 토큰 관련 **// -// .addPathPatterns("/mypage/**"); + .addPathPatterns("/auth/**") //** 인증 JWT 토큰 관련 **// + .addPathPatterns("/reviews/**") + .addPathPatterns("/likes/**") + .addPathPatterns("/mypage/**"); //.excludePathPatterns("/public/**"); // 제외할 URL 패턴 } diff --git a/module-api/src/main/java/com/kernel360/review/code/ReviewErrorCode.java b/module-api/src/main/java/com/kernel360/review/code/ReviewErrorCode.java index 6ea8b524..7ff710ec 100644 --- a/module-api/src/main/java/com/kernel360/review/code/ReviewErrorCode.java +++ b/module-api/src/main/java/com/kernel360/review/code/ReviewErrorCode.java @@ -6,7 +6,8 @@ @RequiredArgsConstructor public enum ReviewErrorCode implements ErrorCode { - INVALID_STAR_RATING_VALUE(HttpStatus.BAD_REQUEST.value(), "ERV001", "유효하지 않은 별점입니다."); + INVALID_STAR_RATING_VALUE(HttpStatus.BAD_REQUEST.value(), "ERV001", "유효하지 않은 별점입니다."), + INVALID_REVIEW_WRITE_REQUEST(HttpStatus.BAD_REQUEST.value(), "ERV002", "리뷰가 중복되거나 유효하지 않습니다."); private final int status; private final String code; diff --git a/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java b/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java index 6ec02f5f..1cd62233 100644 --- a/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java +++ b/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java @@ -5,11 +5,11 @@ import com.kernel360.review.dto.ReviewDto; import com.kernel360.review.service.ReviewService; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RestController @RequiredArgsConstructor @RequestMapping("/reviews") @@ -18,17 +18,15 @@ public class ReviewController { private final ReviewService reviewService; @GetMapping("/product/{productNo}") - public ResponseEntity>> getReviewsByProduct(@PathVariable Long productNo) { - List reviews = reviewService.getReviewsByProduct(productNo); + public ResponseEntity>> getReviewsByProduct(@PathVariable Long productNo, Pageable pageable) { - return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEWS, reviews); + return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEWS, reviewService.getReviewsByProduct(productNo, pageable)); } @GetMapping("/{reviewNo}") public ResponseEntity> getReview(@PathVariable Long reviewNo) { - ReviewDto review = reviewService.getReview(reviewNo); - return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEW, review); + return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEW, reviewService.getReview(reviewNo)); } @PostMapping("") diff --git a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java index 86391415..23f01ab4 100644 --- a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java +++ b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java @@ -6,12 +6,16 @@ import com.kernel360.review.entity.Review; import com.kernel360.review.repository.ReviewRepository; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; -import java.util.List; +@Slf4j @Service @RequiredArgsConstructor public class ReviewService { @@ -21,15 +25,16 @@ public class ReviewService { private static final double MAX_STAR_RATING = 5.0; @Transactional(readOnly = true) - public List getReviewsByProduct(Long productNo) { + public Page getReviewsByProduct(Long productNo, Pageable pageable) { + log.info("제품 리뷰 목록 조회 -> product_no {}", productNo); - return reviewRepository.findAllByProduct_ProductNo(productNo) - .stream().map(ReviewDto::from) - .toList(); + return reviewRepository.findAllByProduct_ProductNoOrderByReviewNoDesc(productNo, pageable) + .map(ReviewDto::from); } @Transactional(readOnly = true) public ReviewDto getReview(Long reviewNo) { + log.info("리뷰 단건 조회 -> review_no {}", reviewNo); return ReviewDto.from(reviewRepository.findByReviewNo(reviewNo)); } @@ -38,7 +43,16 @@ public ReviewDto getReview(Long reviewNo) { public Review createReview(ReviewDto reviewDto) { isValidStarRating(reviewDto.starRating()); - return reviewRepository.save(reviewDto.toEntity()); + Review review; + + try { + review = reviewRepository.saveAndFlush(reviewDto.toEntity()); + } catch (DataIntegrityViolationException e) { + throw new BusinessException(ReviewErrorCode.INVALID_REVIEW_WRITE_REQUEST); + } + + log.info("리뷰 등록 -> review_no {}", review.getReviewNo()); + return review; } @@ -46,12 +60,19 @@ public Review createReview(ReviewDto reviewDto) { public void updateReview(ReviewDto reviewDto) { isValidStarRating(reviewDto.starRating()); - reviewRepository.save(reviewDto.toEntity()); + try { + reviewRepository.saveAndFlush(reviewDto.toEntity()); + } catch (DataIntegrityViolationException e) { + throw new BusinessException(ReviewErrorCode.INVALID_REVIEW_WRITE_REQUEST); + } + + log.info("리뷰 수정 -> review_no {}", reviewDto.reviewNo()); } @Transactional public void deleteReview(Long reviewNo) { reviewRepository.deleteById(reviewNo); + log.info("리뷰 삭제 -> review_no {}", reviewNo); } private static void isValidStarRating(BigDecimal starRating) { diff --git a/module-api/src/main/resources/db/migration/V1.0.10__add_unique_constraint_review.sql b/module-api/src/main/resources/db/migration/V1.0.10__add_unique_constraint_review.sql new file mode 100644 index 00000000..57ef4e13 --- /dev/null +++ b/module-api/src/main/resources/db/migration/V1.0.10__add_unique_constraint_review.sql @@ -0,0 +1,4 @@ +ALTER TABLE REVIEW DROP CONSTRAINT IF EXISTS review_ukey; + +ALTER TABLE REVIEW + ADD CONSTRAINT review_ukey UNIQUE (MEMBER_NO, PRODUCT_NO); \ No newline at end of file diff --git a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java index 07ce8680..91c23864 100644 --- a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java +++ b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java @@ -6,7 +6,9 @@ public enum CommonErrorCode implements ErrorCode { INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "E001", "Server Error"), FAIL_FILE_UPLOAD(HttpStatus.INTERNAL_SERVER_ERROR.value(), "E002", "파일 업로드 실패"), - INVALID_FILE_EXTENSION(HttpStatus.BAD_REQUEST.value(), "E003", "유효하지 않은 파일 확장자"); + INVALID_FILE_EXTENSION(HttpStatus.BAD_REQUEST.value(), "E003", "유효하지 않은 파일 확장자"), + NOT_FOUND_RESOURCE(HttpStatus.NOT_FOUND.value(), "E004", "요청한 자원이 존재하지 않음"), + INVALID_REQUEST_HEADERS(HttpStatus.BAD_REQUEST.value(), "E005", "요청한 헤더가 존재하지 않음"); private final int status; private final String code; diff --git a/module-common/src/main/java/com/kernel360/code/jwt/JwtErrorCode.java b/module-common/src/main/java/com/kernel360/code/jwt/JwtErrorCode.java new file mode 100644 index 00000000..f41c6058 --- /dev/null +++ b/module-common/src/main/java/com/kernel360/code/jwt/JwtErrorCode.java @@ -0,0 +1,33 @@ +package com.kernel360.code.jwt; + +import com.kernel360.code.ErrorCode; +import org.springframework.http.HttpStatus; + +public enum JwtErrorCode implements ErrorCode { + FAILED_MALFORMED_JWT(HttpStatus.BAD_REQUEST.value(), "EJC001", "유효하지 않은 JWT 문자열 형식입니다."), + FAILED_SIGNATURE_JWT(HttpStatus.BAD_REQUEST.value(), "EJC001", "JWT 시그니처가 서버에서 계산한 시그니처와 일치하지 않습니다."); + private final int status; + private final String code; + private final String message; + + JwtErrorCode(int status, String code, String message) { + this.status = status; + this.code = code; + this.message = message; + } + + @Override + public int getStatus() { + return status; + } + + @Override + public String getCode() { + return code; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java index b1f6a16b..8e95cb17 100644 --- a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java @@ -2,11 +2,15 @@ import com.kernel360.code.ErrorCode; import com.kernel360.code.common.CommonErrorCode; +import com.kernel360.code.jwt.JwtErrorCode; import com.kernel360.exception.BusinessException; import com.kernel360.response.ErrorResponse; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.security.SignatureException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MissingRequestHeaderException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -31,4 +35,40 @@ protected ResponseEntity handleException(Exception e) { return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } + + @ExceptionHandler(MalformedJwtException.class) + protected ResponseEntity handleMalformedJwtException(final MalformedJwtException e) { + log.error("handleMalformedJwtException", e); + + final ErrorResponse response = ErrorResponse.of(JwtErrorCode.FAILED_MALFORMED_JWT); + + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(SignatureException.class) + protected ResponseEntity handleJwtSignatureException(final SignatureException e) { + log.error("handleJwtSignatureException", e); + + final ErrorResponse response = ErrorResponse.of(JwtErrorCode.FAILED_SIGNATURE_JWT); + + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(NullPointerException.class) + protected ResponseEntity handleNullPointerException(final NullPointerException e) { + log.error("handleNullPointerException", e); + + final ErrorResponse response = ErrorResponse.of(CommonErrorCode.NOT_FOUND_RESOURCE); + + return new ResponseEntity<>(response, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(MissingRequestHeaderException.class) + protected ResponseEntity handleMissingHeaderException(final MissingRequestHeaderException e) { + log.error("handleMissingHeaderException", e); + + final ErrorResponse response = ErrorResponse.of(CommonErrorCode.INVALID_REQUEST_HEADERS); + + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } } diff --git a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java index 556939e0..282f3635 100644 --- a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java +++ b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java @@ -1,12 +1,12 @@ package com.kernel360.review.repository; import com.kernel360.review.entity.Review; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; - public interface ReviewRepository extends JpaRepository { - List findAllByProduct_ProductNo(Long productNo); + Page findAllByProduct_ProductNoOrderByReviewNoDesc(Long productNo, Pageable pageable); Review findByReviewNo(Long reviewNo); } From c848a05dbd6d0d1551b9f52b3bebf50ae89ba7a2 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 19:07:01 +0900 Subject: [PATCH 34/56] =?UTF-8?q?chore=20::=20json=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=20=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kernel360/member/dto/MemberCredentialDto.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/dto/MemberCredentialDto.java b/module-api/src/main/java/com/kernel360/member/dto/MemberCredentialDto.java index 4601f95d..55da61cf 100644 --- a/module-api/src/main/java/com/kernel360/member/dto/MemberCredentialDto.java +++ b/module-api/src/main/java/com/kernel360/member/dto/MemberCredentialDto.java @@ -2,9 +2,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; -public record MemberCredentialDto(@JsonProperty("authToken") String authToken, +public record MemberCredentialDto(@JsonProperty("token") String authToken, @JsonProperty("email") String email, - @JsonProperty("memberId") String memberId, + @JsonProperty("id") String memberId, @JsonProperty("password") String password) { public static MemberCredentialDto of(String authToken, String email, String memberId, String password) { From 448abf8e923d2995d9c9fc9ddee6b76d0b48107b Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 19:07:41 +0900 Subject: [PATCH 35/56] =?UTF-8?q?chore=20::=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=A9=94=EC=8B=9C=EC=A7=80,=20=EB=B9=84?= =?UTF-8?q?=EC=A6=88=EB=8B=88=EC=8A=A4=20=EC=BD=94=EB=93=9C=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kernel360/member/code/MemberBusinessCode.java | 4 ++-- .../main/java/com/kernel360/member/code/MemberErrorCode.java | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java b/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java index 1fb674c7..0ef71241 100644 --- a/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java +++ b/module-api/src/main/java/com/kernel360/member/code/MemberBusinessCode.java @@ -19,8 +19,8 @@ public enum MemberBusinessCode implements BusinessCode { SUCCESS_REQUEST_UPDATE_CAR_INFO_MEMBER(HttpStatus.OK.value(), "BMC010", "CarInfo 정보가 변경 되었습니다."), SUCCESS_REQUEST_FIND_MEMBER_ID(HttpStatus.OK.value(), "BMC011","회원 아이디 찾기 메일이 발송되었습니다."), SUCCESS_REQUEST_SEND_RESET_PASSWORD_EMAIL(HttpStatus.OK.value(), "BMC012", "회원 비밀번호 초기화 메일이 발송되었습니다."), - SUCCESS_REQUEST_RESET_PASSWORD_PAGE(HttpStatus.FOUND.value(), "BMC013", "비밀번호 초기화 토큰이 유효하므로 비밀번호 초기화 페이지로 접근합니다."), - SUCCESS_REQUEST_RESET_PASSWORD(HttpStatus.OK.value(), "BMC014", "비밀번호가 초기화되었습니다."), + SUCCESS_REQUEST_RESET_PASSWORD_PAGE(HttpStatus.OK.value(), "BMC013", "액세스 토큰이 유효하므로 비밀번호 초기화 페이지로 접근에 성공합니다."), + SUCCESS_REQUEST_RESET_PASSWORD(HttpStatus.OK.value(), "BMC014", "비밀번호가 성공적으로 초기화되었습니다."), SUCCESS_REQUEST_LOGIN_MEMBER_KAKAO(HttpStatus.OK.value(), "BMC015", "로그인 성공"), SUCCESS_REQUEST_SIGN_OUT_MEMBER(HttpStatus.OK.value(), "BMC016", "회원탈퇴 성공"), SUCCESS_FIND_WASH_INFO_IN_MEMBER(HttpStatus.OK.value(), "BMC017","세차정보 조회 성공"); diff --git a/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java b/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java index facf582c..df300656 100644 --- a/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java +++ b/module-api/src/main/java/com/kernel360/member/code/MemberErrorCode.java @@ -4,8 +4,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; -import java.util.EnumSet; - @RequiredArgsConstructor public enum MemberErrorCode implements ErrorCode { @@ -16,7 +14,7 @@ public enum MemberErrorCode implements ErrorCode { FAILED_GENERATE_LOGIN_REQUEST_INFO(HttpStatus.INTERNAL_SERVER_ERROR.value(), "EMC005", "정보 불일치로 인한 로그인 정보 생성 실패"), FAILED_REQUEST_LOGIN(HttpStatus.BAD_REQUEST.value(), "EMC006", "정보 불일치로 인한 로그인 실패"), FAILED_FIND_MEMBER_INFO(HttpStatus.BAD_REQUEST.value(), "EMC007", "요청 회원정보가 존재하지 않습니다."), - EXPIRED_PASSWORD_RESET_TOKEN(HttpStatus.NOT_FOUND.value(), "EMC008", "유효하지 않은 비밀번호 초기화 토큰입니다"), + EXPIRED_TOKEN(HttpStatus.NOT_FOUND.value(), "EMC008", "유효하지 않은 토큰입니다"), FAILED_REQUEST_LOGIN_FOR_KAKAO(HttpStatus.BAD_REQUEST.value(), "EMC009", "카카오 로그인 정보를 찾을 수 없습니다."), FAILED_FIND_MEMBER_CAR_INFO(HttpStatus.BAD_REQUEST.value(), "EMC010", "요청 회원의 차량정보가 존재하지 않습니다."), FAILED_FIND_MEMBER_WASH_INFO(HttpStatus.BAD_REQUEST.value(), "EMC011", "요청 회원의 세차정보가 존재하지 않습니다."), From ba0064f91827f5824ea46174f6a07e789b4c2c90 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 19:09:17 +0900 Subject: [PATCH 36/56] =?UTF-8?q?feat=20::=20IllegalArgumentException=20?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=95=B8=EB=93=A4=EB=9F=AC,?= =?UTF-8?q?=20=EC=97=90=EB=9F=AC=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(=EC=A3=BC=EB=A1=9C=20=EC=9A=94=EC=B2=AD-=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=EA=B0=84=20Json=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20?= =?UTF-8?q?=EB=AA=85=EC=9D=B4=20=EC=9D=BC=EC=B9=98=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EC=9D=84=20=EB=95=8C=20=EB=B0=9C=EC=83=9D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kernel360/code/common/CommonErrorCode.java | 3 ++- .../com/kernel360/handler/GlobalExceptionHandler.java | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java index 91c23864..6b3d9245 100644 --- a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java +++ b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java @@ -8,7 +8,8 @@ public enum CommonErrorCode implements ErrorCode { FAIL_FILE_UPLOAD(HttpStatus.INTERNAL_SERVER_ERROR.value(), "E002", "파일 업로드 실패"), INVALID_FILE_EXTENSION(HttpStatus.BAD_REQUEST.value(), "E003", "유효하지 않은 파일 확장자"), NOT_FOUND_RESOURCE(HttpStatus.NOT_FOUND.value(), "E004", "요청한 자원이 존재하지 않음"), - INVALID_REQUEST_HEADERS(HttpStatus.BAD_REQUEST.value(), "E005", "요청한 헤더가 존재하지 않음"); + INVALID_REQUEST_HEADERS(HttpStatus.BAD_REQUEST.value(), "E005", "요청한 헤더가 존재하지 않음"), + INVALID_ARGUMENT(HttpStatus.BAD_REQUEST.value(), "E006", "요청 파라미터가 없거나 비어있거나, 요청 파라미터의 이름이 메서드 인수의 이름과 일치하지 않습니다"); private final int status; private final String code; diff --git a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java index 8e95cb17..64237c82 100644 --- a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java @@ -71,4 +71,13 @@ protected ResponseEntity handleMissingHeaderException(final Missi return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } + + @ExceptionHandler(IllegalArgumentException.class) + protected ResponseEntity handleIllegalArgumentException(final IllegalArgumentException e){ + log.error("handleIllegalArgumentException",e); + + final ErrorResponse response = ErrorResponse.of(CommonErrorCode.INVALID_ARGUMENT); + + return new ResponseEntity<>(response,HttpStatus.BAD_REQUEST); + } } From 270e7c6aa738cc523fbbea479724a2f9e351d526 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 19:14:40 +0900 Subject: [PATCH 37/56] =?UTF-8?q?refactor=20:=20=EB=B9=84=EB=B0=80?= =?UTF-8?q?=EB=B2=88=ED=98=B8=20=EC=9E=AC=EC=84=A4=EC=A0=95=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이메일 링크는 이제 /find-password 에 GET 요청을 보내고, 서버는 유효성 검사후 /reset-password 로 리다이렉트 (토큰을 URL 쿼리스트링에 담아서 반환). /reset-password 페이지에서 POST 요청을 보내며 재설정 로직을 마무리 --- .../member/controller/MemberController.java | 56 ++++++++++++++----- .../member/service/FindCredentialService.java | 42 +++++++++++--- .../controller/MemberControllerTest.java | 2 +- 3 files changed, 76 insertions(+), 24 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java index 4a2469d7..366f8a9b 100644 --- a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java +++ b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java @@ -1,7 +1,9 @@ package com.kernel360.member.controller; -import com.fasterxml.jackson.core.JsonProcessingException; +import static com.kernel360.member.code.MemberBusinessCode.SUCCESS_REQUEST_JOIN_MEMBER_CREATED; +import static com.kernel360.member.code.MemberBusinessCode.SUCCESS_REQUEST_LOGIN_MEMBER; + import com.kernel360.carinfo.entity.CarInfo; import com.kernel360.member.code.MemberBusinessCode; import com.kernel360.member.dto.CarInfoDto; @@ -15,10 +17,17 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import static com.kernel360.member.code.MemberBusinessCode.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; @Slf4j @RestController @@ -61,14 +70,16 @@ public boolean duplicatedCheckEmail(@PathVariable String email) { } @PostMapping("/wash") - public ResponseEntity> saveWashInfo(@RequestBody WashInfoDto washInfo, @RequestHeader("Authorization") String authToken){ + public ResponseEntity> saveWashInfo(@RequestBody WashInfoDto washInfo, + @RequestHeader("Authorization") String authToken) { memberService.saveWashInfo(washInfo, authToken); return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_UPDATE_WASH_INFO_MEMBER); } @PostMapping("/car") - public ResponseEntity> saveCarInfo(@RequestBody CarInfoDto carInfo, @RequestHeader("Authorization") String authToken){ + public ResponseEntity> saveCarInfo(@RequestBody CarInfoDto carInfo, + @RequestHeader("Authorization") String authToken) { memberService.saveCarInfo(carInfo, authToken); return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_UPDATE_CAR_INFO_MEMBER); @@ -88,32 +99,49 @@ public ResponseEntity> sendPasswordResetUriByEmail(@RequestB //--입력받은 아이디를 데이터베이스에 조회, 없으면 예외 발생--/ MemberDto memberDto = memberService.findByMemberId(dto.memberId()); //--유효성이 검증된 아이디에 대해서 만료시간이 있는 비밀번호 초기화 (호스트 + UUID) 링크 생성 --// - String resetUri = findCredentialService.generatePasswordResetUri( memberDto); + String resetUri = findCredentialService.generatePasswordResetPageUri(memberDto); //-- 가입시 입력한 이메일로 비밀번호 초기화 이메일 발송 --// findCredentialService.sendPasswordResetUri(resetUri, memberDto); return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_SEND_RESET_PASSWORD_EMAIL); } + /** + * @param accessToken 재설정 페이지로의 액세스 토큰 + * @return 비밀번호 재설정 페이지로 재설정 토큰을 URL 쿼리에 담아 리다이렉트 + */ + @GetMapping("/find-password") + public ResponseEntity> redirectToPasswordResetPage(@RequestParam("token") String accessToken) { + findCredentialService.getData(accessToken); + HttpHeaders headers = findCredentialService.setRedirectLocation(accessToken); + + return new ResponseEntity<>(headers, HttpStatus.FOUND); + } + + /** + * @param resetToken 비밀번호 재설정 토큰 (현재는 재설정 페이지 액세스 토큰과 동일-추가 발급없이 재활용 중) + * @return 성공시 200 + */ @GetMapping("/reset-password") - public ResponseEntity> getPasswordResetPage(@RequestParam String token) { - findCredentialService.getData(token); + public ResponseEntity> getPasswordResetPage(@RequestParam("token") String resetToken) { + findCredentialService.getData(resetToken); - return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_RESET_PASSWORD_PAGE, token); + return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_RESET_PASSWORD_PAGE); } @PostMapping("/reset-password") public ResponseEntity> resetPassword(@RequestBody MemberCredentialDto credentialDto) { - String authKey = findCredentialService.resetPassword(credentialDto); - findCredentialService.getAndExpireData(authKey); + String token = findCredentialService.resetPassword(credentialDto); + findCredentialService.getAndExpireData(token); return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_RESET_PASSWORD); } @GetMapping("/login/forKakao") - public ResponseEntity> loginForKakao(@RequestHeader("Authorization") String accessToken,HttpServletRequest request) { + public ResponseEntity> loginForKakao(@RequestHeader("Authorization") String accessToken, + HttpServletRequest request) { - MemberDto member = memberService.loginForKakao(accessToken,request); + MemberDto member = memberService.loginForKakao(accessToken, request); return ApiResponse.toResponseEntity(SUCCESS_REQUEST_LOGIN_MEMBER, member); } diff --git a/module-api/src/main/java/com/kernel360/member/service/FindCredentialService.java b/module-api/src/main/java/com/kernel360/member/service/FindCredentialService.java index fc3e4f1b..9bdcd93d 100644 --- a/module-api/src/main/java/com/kernel360/member/service/FindCredentialService.java +++ b/module-api/src/main/java/com/kernel360/member/service/FindCredentialService.java @@ -4,6 +4,7 @@ import com.kernel360.member.code.MemberErrorCode; import com.kernel360.member.dto.MemberCredentialDto; import com.kernel360.member.dto.MemberDto; +import java.net.URI; import java.time.Duration; import java.util.Objects; import java.util.UUID; @@ -11,6 +12,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; +import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import org.springframework.web.util.UriComponentsBuilder; @@ -82,7 +84,7 @@ public void sendPasswordResetUri(String resetUri, MemberDto dto) { + "
\n" + "

고객센터 운영시간

\n" + "

평일 10:00~19:00 (주말 및 공휴일 제외/ 점심시간 13:00~14:00)

\n" - + " " + "고객센터 문의하기\n" + "
\n" @@ -98,15 +100,15 @@ public void sendPasswordResetUri(String resetUri, MemberDto dto) { emailService.sendMail(dto.email(), "[No-Reply] Wash-Fit 아이디/비밀번호 찾기", htmlContent); } - public String generatePasswordResetUri(MemberDto memberDto) { - String resetToken = generateUUID(); + public String generatePasswordResetPageUri(MemberDto memberDto) { + String accessToken = generateUUID(); String uriString = UriComponentsBuilder.fromHttpUrl(HOST_HTTP_URL) - .path("/member/reset-password") - .queryParam("token", resetToken) + .path("/member/find-password") + .queryParam("token", accessToken) .build() .toUriString(); - setExpiringData(resetToken, memberDto.id(), TOKEN_DURATION); // duration 값 상수로 변경관리 필요 + setExpiringData(accessToken, memberDto.id(), TOKEN_DURATION); // duration 값 상수로 변경관리 필요 return uriString; } @@ -116,7 +118,7 @@ public String resetPassword(MemberCredentialDto credentialDto) { String value = valueOperations.get(credentialDto.authToken()); if (Objects.isNull(value)) { - throw new BusinessException(MemberErrorCode.EXPIRED_PASSWORD_RESET_TOKEN); + throw new BusinessException(MemberErrorCode.EXPIRED_TOKEN); } memberService.resetPasswordByMemberId(value, credentialDto.password()); @@ -133,7 +135,7 @@ private String generateUUID() { public String getData(String key) { ValueOperations valueOperations = redisTemplate.opsForValue(); if (Objects.isNull(valueOperations.get(key))) { - throw new BusinessException(MemberErrorCode.EXPIRED_PASSWORD_RESET_TOKEN); + throw new BusinessException(MemberErrorCode.EXPIRED_TOKEN); } return valueOperations.get(key); @@ -156,9 +158,31 @@ public void setExpiringData(String key, String value, int duration) { public void getAndExpireData(String key) { ValueOperations valueOperations = redisTemplate.opsForValue(); if (Objects.isNull(valueOperations.get(key))) { - throw new BusinessException(MemberErrorCode.EXPIRED_PASSWORD_RESET_TOKEN); + throw new BusinessException(MemberErrorCode.EXPIRED_TOKEN); } valueOperations.getAndDelete(key); } + + public HttpHeaders setRedirectLocation(String accessToken) { + //** 액세스 토큰에서 아이디를 추출하고 + String memberId = getData(accessToken); + //** 액세스 토큰 만료처리 -> 할지 말지 고민해봐야 + getAndExpireData(accessToken); + //** 비밀번호 재설정용 토큰을 발급 + String resetToken = generateUUID(); + //** 재설정 토큰 만료기간 설정 + setExpiringData(resetToken, memberId, TOKEN_DURATION); + + + String uriString = UriComponentsBuilder.fromHttpUrl(HOST_HTTP_URL) + .path("/member/reset-password") + .queryParam("token", resetToken) + .build() + .toUriString(); + HttpHeaders headers = new HttpHeaders(); + headers.setLocation(URI.create(uriString)); + + return headers; + } } diff --git a/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java b/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java index 62732867..e66dcebd 100644 --- a/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java +++ b/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java @@ -151,7 +151,7 @@ class MemberControllerTest extends ControllerTest { MemberDto memberDto = MemberDto.of("testMemberId", "testPassword001"); given(memberService.findByMemberId(credentialDto.memberId())).willReturn(memberDto); - given(findCredentialService.generatePasswordResetUri(memberDto)).willReturn("테스트 URI"); + given(findCredentialService.generatePasswordResetPageUri(memberDto)).willReturn("테스트 URI"); ObjectMapper objectMapper = new ObjectMapper(); String dtoAsString = objectMapper.writeValueAsString(credentialDto); From 1687855c9992903dd805f9c6d24c2984efeb24af Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 19:48:32 +0900 Subject: [PATCH 38/56] =?UTF-8?q?feat=20::=20HttpRequestMethodNotSupported?= =?UTF-8?q?Exception=20=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=B6=94=EA=B0=80,=20=EC=A3=BC=EC=84=9D=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 --- .../kernel360/member/controller/MemberController.java | 2 +- .../com/kernel360/code/common/CommonErrorCode.java | 3 ++- .../com/kernel360/handler/GlobalExceptionHandler.java | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java index 366f8a9b..fcb24ebf 100644 --- a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java +++ b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java @@ -119,7 +119,7 @@ public ResponseEntity> redirectToPasswordResetPage(@RequestP } /** - * @param resetToken 비밀번호 재설정 토큰 (현재는 재설정 페이지 액세스 토큰과 동일-추가 발급없이 재활용 중) + * @param resetToken 비밀번호 재설정 토큰 * @return 성공시 200 */ @GetMapping("/reset-password") diff --git a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java index 6b3d9245..f153dd5d 100644 --- a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java +++ b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java @@ -9,7 +9,8 @@ public enum CommonErrorCode implements ErrorCode { INVALID_FILE_EXTENSION(HttpStatus.BAD_REQUEST.value(), "E003", "유효하지 않은 파일 확장자"), NOT_FOUND_RESOURCE(HttpStatus.NOT_FOUND.value(), "E004", "요청한 자원이 존재하지 않음"), INVALID_REQUEST_HEADERS(HttpStatus.BAD_REQUEST.value(), "E005", "요청한 헤더가 존재하지 않음"), - INVALID_ARGUMENT(HttpStatus.BAD_REQUEST.value(), "E006", "요청 파라미터가 없거나 비어있거나, 요청 파라미터의 이름이 메서드 인수의 이름과 일치하지 않습니다"); + INVALID_ARGUMENT(HttpStatus.BAD_REQUEST.value(), "E006", "요청 파라미터가 없거나 비어있거나, 요청 파라미터의 이름이 메서드 인수의 이름과 일치하지 않습니다"), + INVALID_HTTP_REQUEST_METHOD(HttpStatus.BAD_REQUEST.value(), "E007", "요청 URL 에서 지원하지 않는 HTTP Method 입니다."); private final int status; private final String code; diff --git a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java index 64237c82..2048bebd 100644 --- a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MissingRequestHeaderException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -80,4 +81,13 @@ protected ResponseEntity handleIllegalArgumentException(final Ill return new ResponseEntity<>(response,HttpStatus.BAD_REQUEST); } + + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + protected ResponseEntity handleHttpRequestMethodNotSupportedException(final HttpRequestMethodNotSupportedException e){ + log.error("handleHttpRequestMethodNotSupportedException",e); + + final ErrorResponse response =ErrorResponse.of(CommonErrorCode.INVALID_HTTP_REQUEST_METHOD); + + return new ResponseEntity<>(response,HttpStatus.BAD_REQUEST); + } } From e7d73cd4f957b8ad0fa496bca2b7c7c754cfe8c5 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 19:59:59 +0900 Subject: [PATCH 39/56] =?UTF-8?q?fix=20::=20=EC=9A=94=EC=B2=AD=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=AA=85=20=EB=AA=85=EC=8B=9C?= =?UTF-8?q?=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EC=A7=80=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kernel360/member/controller/MemberController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java index fcb24ebf..1ee8c952 100644 --- a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java +++ b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java @@ -58,13 +58,13 @@ public ResponseEntity> login(@RequestBody MemberDto login } @GetMapping("/duplicatedCheckId/{id}") - public boolean duplicatedCheckId(@PathVariable String id) { + public boolean duplicatedCheckId(@PathVariable("id") String id) { return memberService.idDuplicationCheck(id); } @GetMapping("/duplicatedCheckEmail/{email}") - public boolean duplicatedCheckEmail(@PathVariable String email) { + public boolean duplicatedCheckEmail(@PathVariable("email") String email) { return memberService.emailDuplicationCheck(email); } From 415643084558a3e10b3319602e80f7a5d9216ee1 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 20:00:09 +0900 Subject: [PATCH 40/56] =?UTF-8?q?fix=20::=20=EB=B3=80=EA=B2=BD=EC=82=AC?= =?UTF-8?q?=ED=95=AD=EC=9D=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/MemberControllerTest.java | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java b/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java index e66dcebd..c8ae857b 100644 --- a/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java +++ b/module-api/src/test/java/com/kernel360/member/controller/MemberControllerTest.java @@ -131,8 +131,8 @@ class MemberControllerTest extends ControllerTest { "member/find-memberId", getDocumentRequest(), getDocumentResponse(), requestFields( fieldWithPath("email").type(JsonFieldType.STRING).description("회원가입시 입력한 이메일"), - fieldWithPath("authToken").type(JsonFieldType.NULL).description("비밀번호 재설정 UUID 토큰(사용하지 않음)"), - fieldWithPath("memberId").type(JsonFieldType.NULL).description("회원 아이디(사용하지 않음)"), + fieldWithPath("token").type(JsonFieldType.NULL).description("비밀번호 재설정 UUID 토큰(사용하지 않음)"), + fieldWithPath("id").type(JsonFieldType.NULL).description("회원 아이디(사용하지 않음)"), fieldWithPath("password").type(JsonFieldType.NULL).description("변경할 비밀번호(사용하지 않음)") ), responseFields( @@ -164,8 +164,8 @@ class MemberControllerTest extends ControllerTest { "member/find-password", getDocumentRequest(), getDocumentResponse(), requestFields( fieldWithPath("email").type(JsonFieldType.NULL).description("회원가입시 입력한 이메일(사용하지 않음)"), - fieldWithPath("authToken").type(JsonFieldType.NULL).description("비밀번호 재설정 UUID 토큰(사용하지 않음)"), - fieldWithPath("memberId").type(JsonFieldType.STRING).description("회원 아이디"), + fieldWithPath("token").type(JsonFieldType.NULL).description("비밀번호 재설정 UUID 토큰(사용하지 않음)"), + fieldWithPath("id").type(JsonFieldType.STRING).description("회원 아이디"), fieldWithPath("password").type(JsonFieldType.NULL).description("변경할 비밀번호(사용하지 않음)") ), responseFields( @@ -182,21 +182,10 @@ class MemberControllerTest extends ControllerTest { String token = "testToken-1234-5678"; given(findCredentialService.getData(token)).willReturn("kernel360-testId"); - mockMvc.perform(MockMvcRequestBuilders.get("/member/reset-password?token="+token) + mockMvc.perform(MockMvcRequestBuilders.get("/member/find-password?token="+token) .contentType(MediaType.APPLICATION_JSON) .content(token)) - .andExpect(MockMvcResultMatchers.status().isFound()).andDo(document( - "member/get-reset-password", getDocumentRequest(), getDocumentResponse(), - queryParameters( - parameterWithName("token").description("비밀번호 재설정 UUID 토큰") - ), - responseFields( - fieldWithPath("status").type(JsonFieldType.NUMBER).description("HTTP 상태 코드"), - fieldWithPath("code").type(JsonFieldType.STRING).description("비즈니스 코드"), - fieldWithPath("message").type(JsonFieldType.STRING).description("상세 메시지"), - fieldWithPath("value").type(JsonFieldType.STRING).description("JSON BODY 데이터 - 비밀번호 재설정 토큰") - ) - )); + .andExpect(MockMvcResultMatchers.status().isFound()); } @Test @@ -215,9 +204,9 @@ class MemberControllerTest extends ControllerTest { .andDo(document( "member/post-reset-password", getDocumentRequest(), getDocumentResponse(), requestFields( - fieldWithPath("authToken").type(JsonFieldType.STRING).description("비밀번호 재설정 UUID 토큰"), + fieldWithPath("token").type(JsonFieldType.STRING).description("비밀번호 재설정 UUID 토큰"), fieldWithPath("email").type(JsonFieldType.NULL).description("회원가입시 입력한 이메일(사용하지 않음)"), - fieldWithPath("memberId").type(JsonFieldType.NULL).description("회원 아이디(사용하지 않음)"), + fieldWithPath("id").type(JsonFieldType.NULL).description("회원 아이디(사용하지 않음)"), fieldWithPath("password").type(JsonFieldType.STRING).description("변경할 비밀번호") ), responseFields( From 42bdb758e632c1647dd2ff6c34c3d3b5639720ea Mon Sep 17 00:00:00 2001 From: cgk95 Date: Fri, 1 Mar 2024 20:10:04 +0900 Subject: [PATCH 41/56] =?UTF-8?q?fix=20::=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=AA=85=EC=8B=9C=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(value=20->=20memberId)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kernel360/member/service/FindCredentialService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/service/FindCredentialService.java b/module-api/src/main/java/com/kernel360/member/service/FindCredentialService.java index 9bdcd93d..a423d6b5 100644 --- a/module-api/src/main/java/com/kernel360/member/service/FindCredentialService.java +++ b/module-api/src/main/java/com/kernel360/member/service/FindCredentialService.java @@ -115,13 +115,13 @@ public String generatePasswordResetPageUri(MemberDto memberDto) { public String resetPassword(MemberCredentialDto credentialDto) { ValueOperations valueOperations = redisTemplate.opsForValue(); - String value = valueOperations.get(credentialDto.authToken()); + String memberId = valueOperations.get(credentialDto.authToken()); - if (Objects.isNull(value)) { + if (Objects.isNull(memberId)) { throw new BusinessException(MemberErrorCode.EXPIRED_TOKEN); } - memberService.resetPasswordByMemberId(value, credentialDto.password()); + memberService.resetPasswordByMemberId(memberId, credentialDto.password()); return credentialDto.authToken(); } From 9be715b8bf7fab82b511854fa814aab9d18da6fc Mon Sep 17 00:00:00 2001 From: cgk95 Date: Sat, 2 Mar 2024 13:53:22 +0900 Subject: [PATCH 42/56] =?UTF-8?q?chore=20::=20=EC=9D=98=EB=8F=84=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=A4=84=EB=B0=94=EA=BF=88=20?= =?UTF-8?q?=EB=93=B1=EC=9D=84=20=EB=90=98=EB=8F=8C=EB=A6=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kernel360/member/controller/MemberController.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java index 1ee8c952..f85a50d2 100644 --- a/module-api/src/main/java/com/kernel360/member/controller/MemberController.java +++ b/module-api/src/main/java/com/kernel360/member/controller/MemberController.java @@ -70,16 +70,14 @@ public boolean duplicatedCheckEmail(@PathVariable("email") String email) { } @PostMapping("/wash") - public ResponseEntity> saveWashInfo(@RequestBody WashInfoDto washInfo, - @RequestHeader("Authorization") String authToken) { + public ResponseEntity> saveWashInfo(@RequestBody WashInfoDto washInfo, @RequestHeader("Authorization") String authToken) { memberService.saveWashInfo(washInfo, authToken); return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_UPDATE_WASH_INFO_MEMBER); } @PostMapping("/car") - public ResponseEntity> saveCarInfo(@RequestBody CarInfoDto carInfo, - @RequestHeader("Authorization") String authToken) { + public ResponseEntity> saveCarInfo(@RequestBody CarInfoDto carInfo, @RequestHeader("Authorization") String authToken) { memberService.saveCarInfo(carInfo, authToken); return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_REQUEST_UPDATE_CAR_INFO_MEMBER); @@ -138,8 +136,7 @@ public ResponseEntity> resetPassword(@RequestBody MemberCred } @GetMapping("/login/forKakao") - public ResponseEntity> loginForKakao(@RequestHeader("Authorization") String accessToken, - HttpServletRequest request) { + public ResponseEntity> loginForKakao(@RequestHeader("Authorization") String accessToken, HttpServletRequest request) { MemberDto member = memberService.loginForKakao(accessToken, request); From 7cc592025af5f8d1fb5e9e828aa0864866685ea6 Mon Sep 17 00:00:00 2001 From: cgk95 Date: Sat, 2 Mar 2024 15:06:22 +0900 Subject: [PATCH 43/56] =?UTF-8?q?fix=20::=20=EB=82=B4=20=EC=84=B8=EC=B0=A8?= =?UTF-8?q?=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C,=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EC=84=B8=EC=B0=A8=EC=A0=95=EB=B3=B4=20=EC=98=B5=EC=85=98?= =?UTF-8?q?=EC=9D=84=20=ED=95=A8=EA=BB=98=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kernel360/member/service/MemberService.java | 12 +++++++++--- .../mypage/controller/MyPageController.java | 9 +++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/service/MemberService.java b/module-api/src/main/java/com/kernel360/member/service/MemberService.java index d2e60f44..7f2fab56 100644 --- a/module-api/src/main/java/com/kernel360/member/service/MemberService.java +++ b/module-api/src/main/java/com/kernel360/member/service/MemberService.java @@ -21,7 +21,6 @@ import jakarta.servlet.http.HttpServletRequest; import java.util.Map; import java.util.Objects; -import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -174,7 +173,7 @@ public Map getCarInfo(String token) { } @Transactional(readOnly = true) - public WashInfoDto getWashInfo(String token) { + public Map getWashInfo(String token) { String id = JWT.ownerId(token); Member member = memberRepository.findOneById(id); if (member == null) { @@ -184,7 +183,14 @@ public WashInfoDto getWashInfo(String token) { if(washInfo == null){ throw new BusinessException(MemberErrorCode.FAILED_FIND_MEMBER_WASH_INFO); } - return WashInfoDto.from(washInfo); + + WashInfoDto washInfoDto = WashInfoDto.from(washInfo); + return Map.of( + "wash_info", washInfoDto, + "frequency_options", commonCodeService.getCodes("frequency"), + "cost_options", commonCodeService.getCodes("cost"), + "interest_options", commonCodeService.getCodes("interest") + ); } @Transactional diff --git a/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java b/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java index cebc970b..4adccab2 100644 --- a/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java +++ b/module-api/src/main/java/com/kernel360/mypage/controller/MyPageController.java @@ -1,12 +1,9 @@ package com.kernel360.mypage.controller; -import com.kernel360.exception.BusinessException; import com.kernel360.member.code.MemberBusinessCode; -import com.kernel360.member.code.MemberErrorCode; import com.kernel360.member.dto.MemberDto; import com.kernel360.member.dto.MemberInfo; import com.kernel360.member.dto.PasswordDto; -import com.kernel360.member.dto.WashInfoDto; import com.kernel360.member.service.MemberService; import com.kernel360.product.service.ProductService; import com.kernel360.response.ApiResponse; @@ -40,10 +37,10 @@ ResponseEntity>> myCar(@RequestHeader("Authoriza } @GetMapping("/wash") - ResponseEntity> myWash(@RequestHeader("Authorization") String authToken) { - WashInfoDto washInfoDto = memberService.getWashInfo(authToken); + ResponseEntity>> myWash(@RequestHeader("Authorization") String authToken) { + Map washInfo = memberService.getWashInfo(authToken); - return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_FIND_WASH_INFO_IN_MEMBER, washInfoDto); + return ApiResponse.toResponseEntity(MemberBusinessCode.SUCCESS_FIND_WASH_INFO_IN_MEMBER, washInfo); } @DeleteMapping("/member") From 8dde2e96ce2fbf43574f873f03b2df3c2b16b2a0 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Sun, 3 Mar 2024 15:27:55 +0900 Subject: [PATCH 44/56] =?UTF-8?q?*=20=ED=94=84=EB=A1=A0=ED=8A=B8=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C=20=EB=B0=B0=ED=8F=AC=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/kernel360/global/config/WebConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java index f79175a0..130b114a 100644 --- a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java +++ b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java @@ -26,7 +26,7 @@ public void addCorsMappings(CorsRegistry registry) { .allowedHeaders("*") .allowedMethods("*") .allowCredentials(true) - .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000") + .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000", "https://f1-wash-pedia-fe-lim-byeong-wooks-projects.vercel.app/") .maxAge(3600); } } From 74088fd40a4d6ccc032869516a20bb3788b65773 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Sun, 3 Mar 2024 17:10:06 +0900 Subject: [PATCH 45/56] =?UTF-8?q?*=20=EC=B6=94=EC=B2=9C=EC=A0=9C=ED=92=88?= =?UTF-8?q?=2020=EA=B0=9C=20=EB=B0=9C=EC=86=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/controller/MainController.java | 15 ++++++++++++--- .../main/dto/RecommendProductsDto.java | 19 ++++++++++++------- .../product/service/ProductService.java | 4 ++++ .../product/repository/ProductRepository.java | 6 ++++++ 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/main/controller/MainController.java b/module-api/src/main/java/com/kernel360/main/controller/MainController.java index 8eb4da28..01bb3308 100644 --- a/module-api/src/main/java/com/kernel360/main/controller/MainController.java +++ b/module-api/src/main/java/com/kernel360/main/controller/MainController.java @@ -17,6 +17,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + @RestController @RequestMapping @@ -31,11 +33,18 @@ ResponseEntity> getBanner() { return ApiResponse.toResponseEntity(BannerBusinessCode.GET_BANNER_DATA_SUCCESS, mainService.getBanner()); } +// @GetMapping("/recommend-products") +// ResponseEntity>> getRecommendProducts(Pageable pageable) { +// Page recommendProducts = productService.getRecommendProducts(pageable); +// +// return ApiResponse.toResponseEntity(ProductsBusinessCode.GET_RECOMMEND_PRODUCT_DATA_SUCCESS, recommendProducts); +// +// } + @GetMapping("/recommend-products") - ResponseEntity>> getRecommendProducts(Pageable pageable) { - Page recommendProducts = productService.getRecommendProducts(pageable); + ResponseEntity>> getRecommendProducts() { - return ApiResponse.toResponseEntity(ProductsBusinessCode.GET_RECOMMEND_PRODUCT_DATA_SUCCESS, recommendProducts); + return ApiResponse.toResponseEntity(ProductsBusinessCode.GET_RECOMMEND_PRODUCT_DATA_SUCCESS, productService.getRecommendProductsWithRandom()); } diff --git a/module-api/src/main/java/com/kernel360/main/dto/RecommendProductsDto.java b/module-api/src/main/java/com/kernel360/main/dto/RecommendProductsDto.java index 90c9be21..b7247107 100644 --- a/module-api/src/main/java/com/kernel360/main/dto/RecommendProductsDto.java +++ b/module-api/src/main/java/com/kernel360/main/dto/RecommendProductsDto.java @@ -4,22 +4,25 @@ import com.kernel360.product.entity.Product; public record RecommendProductsDto( - Long id, + Long productNo, String imageSource, String alt, - String productName + String productName, + String item ) { public static RecommendProductsDto of( - Long id, + Long productNo, String imageSource, String alt, - String productName + String productName, + String item ) { return new RecommendProductsDto( - id, + productNo, imageSource, alt, - productName + productName, + item ); } @@ -30,7 +33,9 @@ public static RecommendProductsDto from(Product entity) { "src/main/resources/static/suggestSample.png", // FixMe:: entity.getImage() 같은걸로 변경해야 함 "제품 이미지", - entity.getProductName()); + entity.getProductName(), + entity.getItem() + ); } // public static ProductDto from(RecommendProductsDto){ diff --git a/module-api/src/main/java/com/kernel360/product/service/ProductService.java b/module-api/src/main/java/com/kernel360/product/service/ProductService.java index 7a97f03d..18cf4448 100644 --- a/module-api/src/main/java/com/kernel360/product/service/ProductService.java +++ b/module-api/src/main/java/com/kernel360/product/service/ProductService.java @@ -134,4 +134,8 @@ public Page getProductWithKeywordAndRecentOrder(String keyword, Page return productRepository.getProductWithKeywordAndRecentOrder(keyword, pageable) .map(ProductDto::from); } + + public List getRecommendProductsWithRandom() { + return productRepository.getRecommendProductsWithRandom().stream().map(RecommendProductsDto::from).toList(); + } } diff --git a/module-domain/src/main/java/com/kernel360/product/repository/ProductRepository.java b/module-domain/src/main/java/com/kernel360/product/repository/ProductRepository.java index 024bfff9..36dcf296 100644 --- a/module-domain/src/main/java/com/kernel360/product/repository/ProductRepository.java +++ b/module-domain/src/main/java/com/kernel360/product/repository/ProductRepository.java @@ -2,6 +2,7 @@ import com.kernel360.product.entity.Product; +import java.util.List; import java.util.Optional; import com.kernel360.product.entity.SafetyStatus; @@ -20,6 +21,9 @@ public interface ProductRepository extends JpaRepository { Page findTop5ByOrderByProductNameDesc(Pageable pageable); + @Query(value = "SELECT * FROM Product p ORDER BY RANDOM() LIMIT 20", nativeQuery = true) + List getRecommendProductsWithRandom(); + Page findAllBySafetyStatusEquals(SafetyStatus safetyStatus, Pageable pageable); Page findAllByOrderByCreatedAtDesc(Pageable pageable); @@ -73,4 +77,6 @@ Optional findProductByProductNameAndCompanyName(@Param("productName") S Page findByProductWithKeywordAndSafetyStatus(@Param("keyword") String keyword, @Param("safetyStatus") SafetyStatus safetyStatus, Pageable pageable); + + } From 6a648430c440d018979e11da6872105f9112afa1 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Sun, 3 Mar 2024 17:48:52 +0900 Subject: [PATCH 46/56] =?UTF-8?q?*=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=97=90=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20?= =?UTF-8?q?=EC=83=9D=EB=9E=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/controller/MainControllerTest.java | 102 ++++++++++++------ 1 file changed, 72 insertions(+), 30 deletions(-) diff --git a/module-api/src/test/java/com/kernel360/main/controller/MainControllerTest.java b/module-api/src/test/java/com/kernel360/main/controller/MainControllerTest.java index bfcc0340..0bb5827f 100644 --- a/module-api/src/test/java/com/kernel360/main/controller/MainControllerTest.java +++ b/module-api/src/test/java/com/kernel360/main/controller/MainControllerTest.java @@ -80,19 +80,18 @@ class MainControllerTest extends ControllerTest { verify(mainService, times(1)).getBanner(); } - @Test - void 메인페이지_추천상품을_호출할때_200응답과_데이터가_잘보내지는지() throws Exception { + + void 메인페이지_추천상품을_호출할때_200응답과_데이터가_잘보내지는지_랜덤20개() throws Exception { // given List recommendProductsDtos = fixtureMonkey.giveMeBuilder(RecommendProductsDto.class) - .setNotNull("id") + .setNotNull("productNo") .setNotNull("imageSource") .setNotNull("alt") .setNotNull("productName") + .setNotNull("item") .sampleList(5); - Pageable pageable = PageRequest.of(0, 5); - Page page = new PageImpl<>(recommendProductsDtos, pageable, recommendProductsDtos.size()); - when(productService.getRecommendProducts(any(Pageable.class))).thenReturn(page); + when(productService.getRecommendProductsWithRandom()).thenReturn(recommendProductsDtos); // when & then mockMvc.perform(get("/recommend-products")) @@ -101,10 +100,11 @@ class MainControllerTest extends ControllerTest { .andExpect(jsonPath("$.status").value(200)) .andExpect(jsonPath("$.code").value("PMB001")) .andExpect(jsonPath("$.message").value("추천제품정보 조회 성공")) - .andExpect(jsonPath("$.value.content[*].id").exists()) + .andExpect(jsonPath("$.value.content[*].productNo").exists()) .andExpect(jsonPath("$.value.content[*].imageSource").exists()) .andExpect(jsonPath("$.value.content[*].alt").exists()) .andExpect(jsonPath("$.value.content[*].productName").exists()) + .andExpect(jsonPath("$.value.content[*].item").exists()) .andDo(document("recommend-products/get-recommend-products", getDocumentRequest(), getDocumentResponse(), @@ -113,37 +113,79 @@ class MainControllerTest extends ControllerTest { fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), fieldWithPath("message").type(JsonFieldType.STRING).description("응답메세지"), fieldWithPath("value").type(JsonFieldType.OBJECT).description("응답 본문의 루트 객체"), - fieldWithPath("value.content[].id").type(JsonFieldType.NUMBER).description("제품 ID"), + fieldWithPath("value.content[].productNo").type(JsonFieldType.NUMBER).description("제품 고유번호"), fieldWithPath("value.content[].imageSource").type(JsonFieldType.STRING).description("이미지 URL"), fieldWithPath("value.content[].alt").type(JsonFieldType.STRING).description("이미지 대체 텍스트"), fieldWithPath("value.content[].productName").type(JsonFieldType.STRING).description("제품명"), - fieldWithPath("value.pageable").type(JsonFieldType.OBJECT).description("페이지 정보"), - fieldWithPath("value.pageable.pageNumber").type(JsonFieldType.NUMBER).description("페이지 번호"), - fieldWithPath("value.pageable.pageSize").type(JsonFieldType.NUMBER).description("페이지 크기"), - fieldWithPath("value.pageable.sort").type(JsonFieldType.OBJECT).description("정렬 정보"), - fieldWithPath("value.pageable.sort.empty").type(JsonFieldType.BOOLEAN).description("정렬이 비어 있는지 여부"), - fieldWithPath("value.pageable.sort.sorted").type(JsonFieldType.BOOLEAN).description("정렬이 되었는지 여부"), - fieldWithPath("value.pageable.sort.unsorted").type(JsonFieldType.BOOLEAN).description("정렬이 되지 않았는지 여부"), - fieldWithPath("value.pageable.offset").type(JsonFieldType.NUMBER).description("페이지 오프셋"), - fieldWithPath("value.pageable.paged").type(JsonFieldType.BOOLEAN).description("페이징 여부"), - fieldWithPath("value.pageable.unpaged").type(JsonFieldType.BOOLEAN).description("비페이징 여부"), - fieldWithPath("value.sort").type(JsonFieldType.OBJECT).description("정렬 정보"), - fieldWithPath("value.sort.empty").type(JsonFieldType.BOOLEAN).description("정렬이 비어 있는지 여부"), - fieldWithPath("value.sort.sorted").type(JsonFieldType.BOOLEAN).description("정렬이 되었는지 여부"), - fieldWithPath("value.sort.unsorted").type(JsonFieldType.BOOLEAN).description("정렬이 되지 않았는지 여부"), - fieldWithPath("value.totalPages").type(JsonFieldType.NUMBER).description("총 페이지 수"), - fieldWithPath("value.totalElements").type(JsonFieldType.NUMBER).description("총 요소 수"), - fieldWithPath("value.last").type(JsonFieldType.BOOLEAN).description("마지막 페이지 여부"), - fieldWithPath("value.number").type(JsonFieldType.NUMBER).description("현재 페이지 번호"), - fieldWithPath("value.size").type(JsonFieldType.NUMBER).description("페이지 크기"), - fieldWithPath("value.numberOfElements").type(JsonFieldType.NUMBER).description("현재 페이지의 요소 수"), - fieldWithPath("value.first").type(JsonFieldType.BOOLEAN).description("첫 페이지 여부"), - fieldWithPath("value.empty").type(JsonFieldType.BOOLEAN).description("비어 있는 페이지 여부") + fieldWithPath("value.content[].item").type(JsonFieldType.STRING).description("제품 분류") ) )); } + void 메인페이지_추천상품을_호출할때_200응답과_데이터가_잘보내지는지_페이저블() throws Exception { + // given + List recommendProductsDtos = fixtureMonkey.giveMeBuilder(RecommendProductsDto.class) + .setNotNull("productNo") + .setNotNull("imageSource") + .setNotNull("alt") + .setNotNull("productName") + .sampleList(5); + + Pageable pageable = PageRequest.of(0, 5); + Page page = new PageImpl<>(recommendProductsDtos, pageable, recommendProductsDtos.size()); + when(productService.getRecommendProducts(any(Pageable.class))).thenReturn(page); + +// when & then + mockMvc.perform(get("/recommend-products")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.status").value(200)) + .andExpect(jsonPath("$.code").value("PMB001")) + .andExpect(jsonPath("$.message").value("추천제품정보 조회 성공")) + .andExpect(jsonPath("$.value.content[*].productNo").exists()) + .andExpect(jsonPath("$.value.content[*].imageSource").exists()) + .andExpect(jsonPath("$.value.content[*].alt").exists()) + .andExpect(jsonPath("$.value.content[*].productName").exists()) + .andDo(document("recommend-products/get-recommend-products", + getDocumentRequest(), + getDocumentResponse(), + responseFields( + fieldWithPath("status").type(JsonFieldType.NUMBER).description("상태 코드"), + fieldWithPath("code").type(JsonFieldType.STRING).description("응답 코드"), + fieldWithPath("message").type(JsonFieldType.STRING).description("응답메세지"), + fieldWithPath("value").type(JsonFieldType.OBJECT).description("응답 본문의 루트 객체"), + fieldWithPath("value.content[].productNo").type(JsonFieldType.NUMBER).description("제품 고유번호"), + fieldWithPath("value.content[].imageSource").type(JsonFieldType.STRING).description("이미지 URL"), + fieldWithPath("value.content[].alt").type(JsonFieldType.STRING).description("이미지 대체 텍스트"), + fieldWithPath("value.content[].productName").type(JsonFieldType.STRING).description("제품명"), + fieldWithPath("value.pageable").type(JsonFieldType.OBJECT).description("페이지 정보"), + fieldWithPath("value.pageable.pageNumber").type(JsonFieldType.NUMBER).description("페이지 번호"), + fieldWithPath("value.pageable.pageSize").type(JsonFieldType.NUMBER).description("페이지 크기"), + fieldWithPath("value.pageable.sort").type(JsonFieldType.OBJECT).description("정렬 정보"), + fieldWithPath("value.pageable.sort.empty").type(JsonFieldType.BOOLEAN).description("정렬이 비어 있는지 여부"), + fieldWithPath("value.pageable.sort.sorted").type(JsonFieldType.BOOLEAN).description("정렬이 되었는지 여부"), + fieldWithPath("value.pageable.sort.unsorted").type(JsonFieldType.BOOLEAN).description("정렬이 되지 않았는지 여부"), + fieldWithPath("value.pageable.offset").type(JsonFieldType.NUMBER).description("페이지 오프셋"), + fieldWithPath("value.pageable.paged").type(JsonFieldType.BOOLEAN).description("페이징 여부"), + fieldWithPath("value.pageable.unpaged").type(JsonFieldType.BOOLEAN).description("비페이징 여부"), + fieldWithPath("value.sort").type(JsonFieldType.OBJECT).description("정렬 정보"), + fieldWithPath("value.sort.empty").type(JsonFieldType.BOOLEAN).description("정렬이 비어 있는지 여부"), + fieldWithPath("value.sort.sorted").type(JsonFieldType.BOOLEAN).description("정렬이 되었는지 여부"), + fieldWithPath("value.sort.unsorted").type(JsonFieldType.BOOLEAN).description("정렬이 되지 않았는지 여부"), + fieldWithPath("value.totalPages").type(JsonFieldType.NUMBER).description("총 페이지 수"), + fieldWithPath("value.totalElements").type(JsonFieldType.NUMBER).description("총 요소 수"), + fieldWithPath("value.last").type(JsonFieldType.BOOLEAN).description("마지막 페이지 여부"), + fieldWithPath("value.number").type(JsonFieldType.NUMBER).description("현재 페이지 번호"), + fieldWithPath("value.size").type(JsonFieldType.NUMBER).description("페이지 크기"), + fieldWithPath("value.numberOfElements").type(JsonFieldType.NUMBER).description("현재 페이지의 요소 수"), + fieldWithPath("value.first").type(JsonFieldType.BOOLEAN).description("첫 페이지 여부"), + fieldWithPath("value.empty").type(JsonFieldType.BOOLEAN).description("비어 있는 페이지 여부") + ) + )); + + } + @ParameterizedTest @EnumSource(value = Sort.class, names = {"VIEW_COUNT_PRODUCT_ORDER", "VIOLATION_PRODUCT_LIST", "RECENT_PRODUCT_ORDER"}) void 메인페이지_조회순으로_제품리스트_요청시_200응답과_데이터가_잘_반환되는지(Sort sortType) throws Exception { From d1f7e1b7241bd0a6907449d0c8765212add57a8a Mon Sep 17 00:00:00 2001 From: Younglong Date: Sun, 3 Mar 2024 18:02:40 +0900 Subject: [PATCH 47/56] =?UTF-8?q?setting:=20querydsl=20=EA=B8=B0=EB=B3=B8?= =?UTF-8?q?=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-api/build.gradle | 6 ++++++ module-domain/build.gradle | 18 ++++++++++++++++++ .../com/kernel360/config/QuerydslConfig.java | 15 +++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 module-domain/src/main/java/com/kernel360/config/QuerydslConfig.java diff --git a/module-api/build.gradle b/module-api/build.gradle index 52194452..c8ea3de5 100644 --- a/module-api/build.gradle +++ b/module-api/build.gradle @@ -78,6 +78,12 @@ dependencies { //mybatis implementation group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '3.0.3' + + // querydsl + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta' + annotationProcessor 'jakarta.annotation:jakarta.annotation-api' + annotationProcessor 'jakarta.persistence:jakarta.persistence-api' } tasks.named('test') { diff --git a/module-domain/build.gradle b/module-domain/build.gradle index f25d8e86..e12b5d2a 100644 --- a/module-domain/build.gradle +++ b/module-domain/build.gradle @@ -27,6 +27,12 @@ dependencies { implementation group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '3.0.3' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' + + // querydsl + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta' + annotationProcessor 'jakarta.annotation:jakarta.annotation-api' + annotationProcessor 'jakarta.persistence:jakarta.persistence-api' } tasks.named('test') { @@ -43,5 +49,17 @@ tasks.jar { tasks.register("prepareKotlinBuildScriptModel") {} +def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile; + +tasks.withType(JavaCompile) { + options.getGeneratedSourceOutputDirectory().set(file(querydslDir)) +} + +sourceSets { + main.java.srcDirs += [ querydslDir ] +} +clean { + delete file(querydslDir) +} diff --git a/module-domain/src/main/java/com/kernel360/config/QuerydslConfig.java b/module-domain/src/main/java/com/kernel360/config/QuerydslConfig.java new file mode 100644 index 00000000..5e780bfb --- /dev/null +++ b/module-domain/src/main/java/com/kernel360/config/QuerydslConfig.java @@ -0,0 +1,15 @@ +package com.kernel360.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class QuerydslConfig { + + @Bean + public JPAQueryFactory queryFactory(EntityManager entityManager) { + return new JPAQueryFactory(entityManager); + } +} \ No newline at end of file From d5a5b39207e09fcd86360fee7e06b2e4dbc85333 Mon Sep 17 00:00:00 2001 From: Younglong Date: Sun, 3 Mar 2024 18:14:30 +0900 Subject: [PATCH 48/56] =?UTF-8?q?feat:=20querydsl=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20repo=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B6=94=EA=B0=80=20(=EB=A6=AC=EB=B7=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/repository/ReviewRepository.java | 4 ++ .../repository/ReviewRepositoryCustom.java | 10 +++ .../repository/ReviewRepositoryImpl.java | 65 +++++++++++++++++++ .../review/repository/ReviewRepository.java | 12 ---- .../repository/ReviewRepositoryDomain.java | 8 +++ 5 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 module-api/src/main/java/com/kernel360/review/repository/ReviewRepository.java create mode 100644 module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryCustom.java create mode 100644 module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryImpl.java delete mode 100644 module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java create mode 100644 module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryDomain.java diff --git a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepository.java b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepository.java new file mode 100644 index 00000000..d5008e03 --- /dev/null +++ b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepository.java @@ -0,0 +1,4 @@ +package com.kernel360.review.repository; + +public interface ReviewRepository extends ReviewRepositoryDomain, ReviewRepositoryCustom { +} diff --git a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryCustom.java b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryCustom.java new file mode 100644 index 00000000..cb006c3a --- /dev/null +++ b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryCustom.java @@ -0,0 +1,10 @@ +package com.kernel360.review.repository; + +import com.kernel360.review.dto.ReviewSearchDto; +import com.kernel360.review.entity.Review; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface ReviewRepositoryCustom { + Page findAllByCondition(ReviewSearchDto condition, Pageable pageable); +} diff --git a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryImpl.java b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryImpl.java new file mode 100644 index 00000000..144943bb --- /dev/null +++ b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryImpl.java @@ -0,0 +1,65 @@ +package com.kernel360.review.repository; + +import com.kernel360.review.dto.ReviewSearchDto; +import com.kernel360.review.entity.Review; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +import static com.kernel360.review.entity.QReview.review; + +@RequiredArgsConstructor +public class ReviewRepositoryImpl implements ReviewRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public Page findAllByCondition(ReviewSearchDto condition, Pageable pageable) { + List reviews = queryFactory + .select(review) + .from(review) + .where( + productNoEq(condition.productNo()), + memberNoEq(condition.memberNo())) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .orderBy(sort(condition.sortBy())) + .fetch(); + + Long totalCount = queryFactory + .select(review.count()) + .from(review) + .where( + productNoEq(condition.productNo()), + memberNoEq(condition.memberNo())) + .fetchOne(); + + return new PageImpl<>(reviews, pageable, totalCount); + } + + private BooleanExpression productNoEq(Long productNo) { + return productNo == null ? null : review.product.productNo.eq(productNo); + } + + private BooleanExpression memberNoEq(Long memberNo) { + return memberNo == null ? null : review.member.memberNo.eq(memberNo); + } + + private static OrderSpecifier sort(String sortBy) { + if ("topRated".equals(sortBy)) { + return review.starRating.desc(); + } + + if ("lowRated".equals(sortBy)) { + return review.starRating.asc(); + } + + return review.reviewNo.desc(); + } +} diff --git a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java deleted file mode 100644 index 282f3635..00000000 --- a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.kernel360.review.repository; - -import com.kernel360.review.entity.Review; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface ReviewRepository extends JpaRepository { - Page findAllByProduct_ProductNoOrderByReviewNoDesc(Long productNo, Pageable pageable); - - Review findByReviewNo(Long reviewNo); -} diff --git a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryDomain.java b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryDomain.java new file mode 100644 index 00000000..2a3a48b3 --- /dev/null +++ b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryDomain.java @@ -0,0 +1,8 @@ +package com.kernel360.review.repository; + +import com.kernel360.review.entity.Review; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ReviewRepositoryDomain extends JpaRepository { + Review findByReviewNo(Long reviewNo); +} From 5b8e31b2a1ed8a7587ca77ebc988bbdd265b40b6 Mon Sep 17 00:00:00 2001 From: Younglong Date: Sun, 3 Mar 2024 18:16:45 +0900 Subject: [PATCH 49/56] =?UTF-8?q?feat:=20querydsl=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=B0=8F=20=EC=B6=94=EA=B0=80=20(=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/controller/ReviewController.java | 9 ++++++--- .../kernel360/review/dto/ReviewSearchDto.java | 20 +++++++++++++++++++ .../review/service/ReviewService.java | 6 ++++-- 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 module-api/src/main/java/com/kernel360/review/dto/ReviewSearchDto.java diff --git a/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java b/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java index 1cd62233..0eaddc7c 100644 --- a/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java +++ b/module-api/src/main/java/com/kernel360/review/controller/ReviewController.java @@ -17,10 +17,13 @@ public class ReviewController { private final ReviewService reviewService; - @GetMapping("/product/{productNo}") - public ResponseEntity>> getReviewsByProduct(@PathVariable Long productNo, Pageable pageable) { + @GetMapping("") + public ResponseEntity>> getReviewsByProduct( + @RequestParam(name = "productNo") Long productNo, + @RequestParam(name = "sortBy", defaultValue = "reviewNo", required = false) String sortBy, + Pageable pageable) { - return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEWS, reviewService.getReviewsByProduct(productNo, pageable)); + return ApiResponse.toResponseEntity(ReviewBusinessCode.SUCCESS_GET_REVIEWS, reviewService.getReviewsByProduct(productNo, sortBy, pageable)); } @GetMapping("/{reviewNo}") diff --git a/module-api/src/main/java/com/kernel360/review/dto/ReviewSearchDto.java b/module-api/src/main/java/com/kernel360/review/dto/ReviewSearchDto.java new file mode 100644 index 00000000..4b7b52cc --- /dev/null +++ b/module-api/src/main/java/com/kernel360/review/dto/ReviewSearchDto.java @@ -0,0 +1,20 @@ +package com.kernel360.review.dto; + +public record ReviewSearchDto( + Long productNo, + Long memberNo, + String sortBy +) { + public static ReviewSearchDto of(Long productNo, Long memberNo, String sortBy) { + return new ReviewSearchDto(productNo, memberNo, sortBy); + } + + public static ReviewSearchDto byProductNo(Long productNo, String sortBy) { + return ReviewSearchDto.of(productNo, null, sortBy); + } + + // TODO: 추후 mypage 리뷰 관리에서 사용 예정 + public static ReviewSearchDto byMemberNo(Long memberNo, String sortBy) { + return ReviewSearchDto.of(null, memberNo, sortBy); + } +} diff --git a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java index 23f01ab4..2be8b398 100644 --- a/module-api/src/main/java/com/kernel360/review/service/ReviewService.java +++ b/module-api/src/main/java/com/kernel360/review/service/ReviewService.java @@ -3,6 +3,7 @@ import com.kernel360.exception.BusinessException; import com.kernel360.review.code.ReviewErrorCode; import com.kernel360.review.dto.ReviewDto; +import com.kernel360.review.dto.ReviewSearchDto; import com.kernel360.review.entity.Review; import com.kernel360.review.repository.ReviewRepository; import lombok.RequiredArgsConstructor; @@ -25,10 +26,11 @@ public class ReviewService { private static final double MAX_STAR_RATING = 5.0; @Transactional(readOnly = true) - public Page getReviewsByProduct(Long productNo, Pageable pageable) { + public Page getReviewsByProduct(Long productNo, String sortBy, Pageable pageable) { log.info("제품 리뷰 목록 조회 -> product_no {}", productNo); + // TODO: 유효하지 않은 productNo 인 경우, custom error 보내기 - return reviewRepository.findAllByProduct_ProductNoOrderByReviewNoDesc(productNo, pageable) + return reviewRepository.findAllByCondition(ReviewSearchDto.byProductNo(productNo, sortBy), pageable) .map(ReviewDto::from); } From c3de00b09e2bb0405380906369cb0fe1a4134045 Mon Sep 17 00:00:00 2001 From: Younglong Date: Sun, 3 Mar 2024 18:20:38 +0900 Subject: [PATCH 50/56] =?UTF-8?q?feat:=20cf>=20GlobalException=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 --- .../java/com/kernel360/code/common/CommonErrorCode.java | 3 ++- .../com/kernel360/handler/GlobalExceptionHandler.java | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java index f153dd5d..75e1c04a 100644 --- a/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java +++ b/module-common/src/main/java/com/kernel360/code/common/CommonErrorCode.java @@ -10,7 +10,8 @@ public enum CommonErrorCode implements ErrorCode { NOT_FOUND_RESOURCE(HttpStatus.NOT_FOUND.value(), "E004", "요청한 자원이 존재하지 않음"), INVALID_REQUEST_HEADERS(HttpStatus.BAD_REQUEST.value(), "E005", "요청한 헤더가 존재하지 않음"), INVALID_ARGUMENT(HttpStatus.BAD_REQUEST.value(), "E006", "요청 파라미터가 없거나 비어있거나, 요청 파라미터의 이름이 메서드 인수의 이름과 일치하지 않습니다"), - INVALID_HTTP_REQUEST_METHOD(HttpStatus.BAD_REQUEST.value(), "E007", "요청 URL 에서 지원하지 않는 HTTP Method 입니다."); + INVALID_HTTP_REQUEST_METHOD(HttpStatus.BAD_REQUEST.value(), "E007", "요청 URL 에서 지원하지 않는 HTTP Method 입니다."), + INVALID_REQUEST_PARAMETER(HttpStatus.BAD_REQUEST.value(), "E008", "요청한 파라미터가 존재하지 않음"); private final int status; private final String code; diff --git a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java index a25d8b25..def82f82 100644 --- a/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java +++ b/module-common/src/main/java/com/kernel360/handler/GlobalExceptionHandler.java @@ -12,6 +12,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MissingRequestHeaderException; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -91,4 +92,12 @@ protected ResponseEntity handleHttpRequestMethodNotSupportedExcep return new ResponseEntity<>(response,HttpStatus.BAD_REQUEST); } + @ExceptionHandler(MissingServletRequestParameterException.class) + protected ResponseEntity handleMissingParameterException(final MissingServletRequestParameterException e) { + log.error("handleMissingParameterException", e); + + final ErrorResponse response = ErrorResponse.of(CommonErrorCode.INVALID_REQUEST_PARAMETER); + + return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); + } } From 4f06edc9eb709296f30850b49435636f3ddcd692 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Sun, 3 Mar 2024 19:38:48 +0900 Subject: [PATCH 51/56] =?UTF-8?q?*=20=EA=B9=83=ED=97=88=EB=B8=8C=20?= =?UTF-8?q?=EC=9E=A5=EC=95=A0=EC=8B=9C(=3F)=20=EB=B0=9C=EC=83=9D=20?= =?UTF-8?q?=EB=90=9C=20merge=20=EC=BD=94=EB=93=9C=20=EB=88=84=EB=9D=BD=20?= =?UTF-8?q?=EC=A1=B0=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kernel360/product/repository/ProductRepository.java | 1 + 1 file changed, 1 insertion(+) diff --git a/module-domain/src/main/java/com/kernel360/product/repository/ProductRepository.java b/module-domain/src/main/java/com/kernel360/product/repository/ProductRepository.java index 36dcf296..c7ec0071 100644 --- a/module-domain/src/main/java/com/kernel360/product/repository/ProductRepository.java +++ b/module-domain/src/main/java/com/kernel360/product/repository/ProductRepository.java @@ -78,5 +78,6 @@ Page findByProductWithKeywordAndSafetyStatus(@Param("keyword") String k @Param("safetyStatus") SafetyStatus safetyStatus, Pageable pageable); + Page findByProductNameContaining(String keyword, Pageable pageable); } From b43762c874d4a1576d6c465089dfe768e6c44ad8 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Sun, 3 Mar 2024 21:20:58 +0900 Subject: [PATCH 52/56] =?UTF-8?q?*=20=ED=94=8C=EB=9E=AB=ED=8F=BC=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EB=A7=8C=20=EC=9D=B4=EC=9A=A9=EC=9D=B4=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=9C=20=EA=B8=B0=EB=8A=A5=EB=93=A4?= =?UTF-8?q?=EC=97=90=20=EB=8C=80=ED=95=B4=20=ED=94=8C=EB=9E=AB=ED=8F=BC=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=98?= =?UTF-8?q?=EC=98=80=EC=8A=B5=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kernel360/member/service/MemberService.java | 10 +++++----- .../kernel360/member/repository/MemberRepository.java | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/module-api/src/main/java/com/kernel360/member/service/MemberService.java b/module-api/src/main/java/com/kernel360/member/service/MemberService.java index 7f2fab56..2b97889e 100644 --- a/module-api/src/main/java/com/kernel360/member/service/MemberService.java +++ b/module-api/src/main/java/com/kernel360/member/service/MemberService.java @@ -92,14 +92,14 @@ private Member newRequestLoginEntity(MemberDto loginDto) { @Transactional(readOnly = true) public boolean idDuplicationCheck(String id) { - Member member = memberRepository.findOneById(id); + Member member = memberRepository.findOneByIdForAccountTypeByPlatform(id); return member != null; } @Transactional(readOnly = true) public boolean emailDuplicationCheck(String email) { - Member member = memberRepository.findOneByEmail(email); + Member member = memberRepository.findOneByEmailForAccountTypeByPlatform(email); return member != null; } @@ -134,7 +134,7 @@ public void deleteMemberByToken(String accessToken) { @Transactional public void changePassword(String password, String token) { String id = JWT.ownerId(token); - Member member = memberRepository.findOneById(id); + Member member = memberRepository.findOneByIdForAccountTypeByPlatform(id); if (!member.getPassword().equals(ConvertSHA256.convertToSHA256(password))) { throw new BusinessException(MemberErrorCode.WRONG_PASSWORD_REQUEST); @@ -239,7 +239,7 @@ public MemberDto findByEmail(String email) { @Transactional(readOnly = true) public MemberDto findByMemberId(String memberId) { - Member member = memberRepository.findOneById(memberId); + Member member = memberRepository.findOneByIdForAccountTypeByPlatform(memberId); if (member == null) { throw new BusinessException(MemberErrorCode.FAILED_FIND_MEMBER_INFO); } @@ -249,7 +249,7 @@ public MemberDto findByMemberId(String memberId) { @Transactional public void resetPasswordByMemberId(String memberId, String newPassword) { - Member member = memberRepository.findOneById(memberId); + Member member = memberRepository.findOneByIdForAccountTypeByPlatform(memberId); if (member == null) { throw new BusinessException(MemberErrorCode.FAILED_FIND_MEMBER_INFO); } diff --git a/module-domain/src/main/java/com/kernel360/member/repository/MemberRepository.java b/module-domain/src/main/java/com/kernel360/member/repository/MemberRepository.java index 956d8a57..b01e4481 100644 --- a/module-domain/src/main/java/com/kernel360/member/repository/MemberRepository.java +++ b/module-domain/src/main/java/com/kernel360/member/repository/MemberRepository.java @@ -3,6 +3,7 @@ import com.kernel360.member.entity.Member; import jakarta.persistence.Id; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface MemberRepository extends JpaRepository { @@ -11,7 +12,12 @@ public interface MemberRepository extends JpaRepository { Member findOneById(String id); + @Query("SELECT m FROM Member m WHERE m.id = :id AND m.accountType = 'PLATFORM'") + Member findOneByIdForAccountTypeByPlatform(String id); + Member findOneByEmail(String email); + @Query("SELECT m FROM Member m WHERE m.email = :email AND m.accountType = 'PLATFORM'") + Member findOneByEmailForAccountTypeByPlatform(String email); } From 66205f48ac2ce8d8fa0db5467f41a12f63bf7e5d Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Sun, 3 Mar 2024 21:33:21 +0900 Subject: [PATCH 53/56] =?UTF-8?q?*=20=ED=94=84=EB=A1=A0=ED=8A=B8=EC=97=94?= =?UTF-8?q?=EB=93=9C=20=EB=B2=84=EC=85=80=EC=84=9C=EB=B2=84=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/kernel360/global/config/WebConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java index 130b114a..472c4daf 100644 --- a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java +++ b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java @@ -26,7 +26,7 @@ public void addCorsMappings(CorsRegistry registry) { .allowedHeaders("*") .allowedMethods("*") .allowCredentials(true) - .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000", "https://f1-wash-pedia-fe-lim-byeong-wooks-projects.vercel.app/") + .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000", "https://washfit.vercel.app/") .maxAge(3600); } } From ff44b50a905a7e45612275e0ba17ef2d7af0f5bf Mon Sep 17 00:00:00 2001 From: Younglong Date: Mon, 4 Mar 2024 10:31:51 +0900 Subject: [PATCH 54/56] =?UTF-8?q?feat:=20=ED=8C=8C=EC=9D=BC=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(~Domain=20->=20~Jpa,=20~Custom=20->=20~ds?= =?UTF-8?q?l)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/kernel360/review/repository/ReviewRepository.java | 2 +- .../{ReviewRepositoryCustom.java => ReviewRepositoryDsl.java} | 2 +- .../com/kernel360/review/repository/ReviewRepositoryImpl.java | 2 +- .../{ReviewRepositoryDomain.java => ReviewRepositoryJpa.java} | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename module-api/src/main/java/com/kernel360/review/repository/{ReviewRepositoryCustom.java => ReviewRepositoryDsl.java} (88%) rename module-domain/src/main/java/com/kernel360/review/repository/{ReviewRepositoryDomain.java => ReviewRepositoryJpa.java} (71%) diff --git a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepository.java b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepository.java index d5008e03..70be6d3d 100644 --- a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepository.java +++ b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepository.java @@ -1,4 +1,4 @@ package com.kernel360.review.repository; -public interface ReviewRepository extends ReviewRepositoryDomain, ReviewRepositoryCustom { +public interface ReviewRepository extends ReviewRepositoryJpa, ReviewRepositoryDsl { } diff --git a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryCustom.java b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryDsl.java similarity index 88% rename from module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryCustom.java rename to module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryDsl.java index cb006c3a..45cbc0dd 100644 --- a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryCustom.java +++ b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryDsl.java @@ -5,6 +5,6 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -public interface ReviewRepositoryCustom { +public interface ReviewRepositoryDsl { Page findAllByCondition(ReviewSearchDto condition, Pageable pageable); } diff --git a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryImpl.java b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryImpl.java index 144943bb..1794fc7f 100644 --- a/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryImpl.java +++ b/module-api/src/main/java/com/kernel360/review/repository/ReviewRepositoryImpl.java @@ -15,7 +15,7 @@ import static com.kernel360.review.entity.QReview.review; @RequiredArgsConstructor -public class ReviewRepositoryImpl implements ReviewRepositoryCustom { +public class ReviewRepositoryImpl implements ReviewRepositoryDsl { private final JPAQueryFactory queryFactory; diff --git a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryDomain.java b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryJpa.java similarity index 71% rename from module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryDomain.java rename to module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryJpa.java index 2a3a48b3..23628bcd 100644 --- a/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryDomain.java +++ b/module-domain/src/main/java/com/kernel360/review/repository/ReviewRepositoryJpa.java @@ -3,6 +3,6 @@ import com.kernel360.review.entity.Review; import org.springframework.data.jpa.repository.JpaRepository; -public interface ReviewRepositoryDomain extends JpaRepository { +public interface ReviewRepositoryJpa extends JpaRepository { Review findByReviewNo(Long reviewNo); } From 71826c7604313056f9006794bd28834ddfa80a6f Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Mon, 4 Mar 2024 11:06:38 +0900 Subject: [PATCH 55/56] =?UTF-8?q?*=20=ED=94=84=EB=A1=A0=ED=8A=B8=EC=97=94?= =?UTF-8?q?=EB=93=9C=20=EB=B2=84=EC=85=80=EC=84=9C=EB=B2=84=EB=AA=85=20/?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/kernel360/global/config/WebConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java index 472c4daf..9f02bd7b 100644 --- a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java +++ b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java @@ -26,7 +26,7 @@ public void addCorsMappings(CorsRegistry registry) { .allowedHeaders("*") .allowedMethods("*") .allowCredentials(true) - .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000", "https://washfit.vercel.app/") + .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000", "https://washfit.vercel.app") .maxAge(3600); } } From 7eeb13f33395b8a2a44cbfe601958942d89b3de8 Mon Sep 17 00:00:00 2001 From: gunsight1 Date: Mon, 4 Mar 2024 11:28:19 +0900 Subject: [PATCH 56/56] =?UTF-8?q?*=20=ED=94=84=EB=A1=A0=ED=8A=B8=EC=97=94?= =?UTF-8?q?=EB=93=9C=20=EB=B2=84=EC=85=80=EC=84=9C=EB=B2=84=20CORS=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(=ED=98=B8=EC=B6=9C=EB=B0=A9=EC=8B=9D?= =?UTF-8?q?=EC=9D=B4=20=EC=9E=98=EB=AA=BB=EB=90=9C=EB=93=AF=ED=95=98?= =?UTF-8?q?=EB=A9=B0=20=ED=94=84=EB=A1=A0=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=ED=95=84=EC=9A=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/kernel360/global/config/WebConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java index 9f02bd7b..14602d0c 100644 --- a/module-api/src/main/java/com/kernel360/global/config/WebConfig.java +++ b/module-api/src/main/java/com/kernel360/global/config/WebConfig.java @@ -26,7 +26,7 @@ public void addCorsMappings(CorsRegistry registry) { .allowedHeaders("*") .allowedMethods("*") .allowCredentials(true) - .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000", "https://washfit.vercel.app") + .allowedOrigins("https://www.washfit.site", "https://dev.washfit.site", "http://localhost:3000", "https://washfit.vercel.app", "https://devapi.washfit.site") .maxAge(3600); } }