From e36a9c6735fa341f7e8b1dba414d5e103b9ac3b9 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 03:55:06 +0900 Subject: [PATCH 01/42] =?UTF-8?q?#27=20add:=20JpaAuditing=EC=9D=84=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9=ED=95=9C=20BaseTimeEntity=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/helpmeCookies/Step3Application.java | 2 ++ .../global/entity/BaseTimeEntity.java | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/global/entity/BaseTimeEntity.java diff --git a/src/main/java/com/helpmeCookies/Step3Application.java b/src/main/java/com/helpmeCookies/Step3Application.java index c6bad29..a594415 100644 --- a/src/main/java/com/helpmeCookies/Step3Application.java +++ b/src/main/java/com/helpmeCookies/Step3Application.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication +@EnableJpaAuditing public class Step3Application { public static void main(String[] args) { diff --git a/src/main/java/com/helpmeCookies/global/entity/BaseTimeEntity.java b/src/main/java/com/helpmeCookies/global/entity/BaseTimeEntity.java new file mode 100644 index 0000000..9279fc3 --- /dev/null +++ b/src/main/java/com/helpmeCookies/global/entity/BaseTimeEntity.java @@ -0,0 +1,21 @@ +package com.helpmeCookies.global.entity; + +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@Getter +public abstract class BaseTimeEntity { + + @CreatedDate + private LocalDateTime createdDate; + + @LastModifiedDate + private LocalDateTime modifiedDate; +} From 05c59068ae52819226879e16124cb714d10a9017 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:24:49 +0900 Subject: [PATCH 02/42] =?UTF-8?q?#27=20fix,=20add:=20ArtistInfo=20Id=20Gen?= =?UTF-8?q?erator=20=EC=88=98=EC=A0=95,=20name=20column=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/helpmeCookies/user/entity/ArtistInfo.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/helpmeCookies/user/entity/ArtistInfo.java b/src/main/java/com/helpmeCookies/user/entity/ArtistInfo.java index 83d86e7..4d74c5e 100644 --- a/src/main/java/com/helpmeCookies/user/entity/ArtistInfo.java +++ b/src/main/java/com/helpmeCookies/user/entity/ArtistInfo.java @@ -5,18 +5,23 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; @Entity public class ArtistInfo { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @NotNull + private String name; + @Column(nullable = false) private Long totalFollowers; @Column(nullable = false) private Long totalLikes; + private String about; } From 3a3751b5b1d8f3d824dd23739af2b02dffa266b9 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:25:27 +0900 Subject: [PATCH 03/42] =?UTF-8?q?#27=20add:=20Product=20BaseTimeEntity=20?= =?UTF-8?q?=EC=83=81=EC=86=8D,=20ArtistInfo=20JoinColumn=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/helpmeCookies/product/entity/Product.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/helpmeCookies/product/entity/Product.java b/src/main/java/com/helpmeCookies/product/entity/Product.java index d44b972..584b32a 100644 --- a/src/main/java/com/helpmeCookies/product/entity/Product.java +++ b/src/main/java/com/helpmeCookies/product/entity/Product.java @@ -1,5 +1,7 @@ package com.helpmeCookies.product.entity; +import com.helpmeCookies.global.entity.BaseTimeEntity; +import jakarta.persistence.JoinColumn; import java.util.List; import com.helpmeCookies.user.entity.ArtistInfo; @@ -17,7 +19,7 @@ import lombok.Builder; @Entity -public class Product { +public class Product extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -48,6 +50,7 @@ public class Product { private List hashTags; @ManyToOne + @JoinColumn(name = "artist_info_id") private ArtistInfo artistInfo; public Product() {} From 2c9e4999b88899a0c79874268e80e334e544a85e Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:26:55 +0900 Subject: [PATCH 04/42] =?UTF-8?q?#27=20feat(persistence):=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1(imageUrl=20=EC=B6=94=EA=B0=80=20=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/repository/ProductRepository.java | 19 +++++++++++++++++++ .../product/repository/dto/ProductSearch.java | 9 +++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java diff --git a/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java b/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java index d8b05f3..aca10a1 100644 --- a/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java +++ b/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java @@ -1,9 +1,28 @@ package com.helpmeCookies.product.repository; import com.helpmeCookies.product.entity.Product; +import com.helpmeCookies.product.repository.dto.ProductSearch; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface ProductRepository extends JpaRepository { + + @Query("SELECT p.id AS id, p.name AS name, a.name AS artist, p.price AS price " + + "FROM Product p JOIN p.artistInfo a " + + "WHERE p.name LIKE %:query%") // Index 미사용 + Page findByName(@Param("query") String query, Pageable pageable); + + @Query(value = "SELECT p.id, p.name, a.name AS artist, p.price " + + "FROM product p JOIN artist_info a ON p.artist_info_id = a.id " + + "WHERE MATCH(p.name) AGAINST (:query IN BOOLEAN MODE)", + countQuery = "SELECT COUNT(*) " + + "FROM product p JOIN artist_info a ON p.artist_info_id = a.id " + + "WHERE MATCH(p.name) AGAINST (:query IN BOOLEAN MODE)", + nativeQuery = true) // Index 사용 + Page findByNameWithIdx(@Param("query") String query, Pageable pageable); } diff --git a/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java b/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java new file mode 100644 index 0000000..3c5fcee --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java @@ -0,0 +1,9 @@ +package com.helpmeCookies.product.repository.dto; + + +public interface ProductSearch { + Long getId(); + String getName(); + String getArtist(); + Long getPrice(); +} From e5c750e646c28556721c50b260b281c1869ba92e Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:27:10 +0900 Subject: [PATCH 05/42] =?UTF-8?q?#27=20feat(service):=20=EC=83=81=ED=92=88?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?(imageUrl=20=EC=B6=94=EA=B0=80=20=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/service/ProductService.java | 11 ++++- .../product/service/dto/ProductPage.java | 44 +++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java diff --git a/src/main/java/com/helpmeCookies/product/service/ProductService.java b/src/main/java/com/helpmeCookies/product/service/ProductService.java index 1a16699..6b3c443 100644 --- a/src/main/java/com/helpmeCookies/product/service/ProductService.java +++ b/src/main/java/com/helpmeCookies/product/service/ProductService.java @@ -4,15 +4,22 @@ import com.helpmeCookies.product.entity.Category; import com.helpmeCookies.product.entity.Product; import com.helpmeCookies.product.repository.ProductRepository; +import com.helpmeCookies.product.service.dto.ProductPage; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service +@RequiredArgsConstructor public class ProductService { + private final ProductRepository productRepository; - public ProductService(ProductRepository productRepository) { - this.productRepository = productRepository; + @Transactional(readOnly = true) + public ProductPage.Paging getProductsByPage(String query, Pageable pageable) { + var productPage = productRepository.findByNameWithIdx(query, pageable); + return ProductPage.Paging.from(productPage); } public Product save(ProductRequest productSaveRequest) { diff --git a/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java b/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java new file mode 100644 index 0000000..0b2b920 --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java @@ -0,0 +1,44 @@ +package com.helpmeCookies.product.service.dto; + +import com.helpmeCookies.product.repository.dto.ProductSearch; +import java.util.List; +import org.springframework.data.domain.Page; + +public class ProductPage { + + public record Info( + Long id, + String name, + String artist, + Long price + ) { + public static Info from(ProductSearch productSearch) { + return new Info( + productSearch.getId(), + productSearch.getName(), + productSearch.getArtist(), + productSearch.getPrice() + ); + } + + public static List of(List content) { + return content.stream() + .map(Info::from) + .toList(); + } + } + + public record Paging ( + boolean hasNext, + List products + ) { + + public static Paging from(Page productPage) { + return new Paging( + productPage.hasNext(), + Info.of(productPage.getContent()) + ); + } + } + +} From fd66d6d279cd72e41345a260e7ee65fcbe9a8e36 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:27:18 +0900 Subject: [PATCH 06/42] =?UTF-8?q?#27=20feat(presentation):=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1(imageUrl=20=EC=B6=94=EA=B0=80=20=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/controller/ProductController.java | 36 +++++++++++++++---- .../product/util/ProductSort.java | 5 +++ .../helpmeCookies/product/util/SortUtil.java | 14 ++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/helpmeCookies/product/util/ProductSort.java create mode 100644 src/main/java/com/helpmeCookies/product/util/SortUtil.java diff --git a/src/main/java/com/helpmeCookies/product/controller/ProductController.java b/src/main/java/com/helpmeCookies/product/controller/ProductController.java index c87732e..884a774 100644 --- a/src/main/java/com/helpmeCookies/product/controller/ProductController.java +++ b/src/main/java/com/helpmeCookies/product/controller/ProductController.java @@ -1,22 +1,33 @@ package com.helpmeCookies.product.controller; +import static com.helpmeCookies.product.util.SortUtil.convertProductSort; + import com.helpmeCookies.product.dto.ProductRequest; import com.helpmeCookies.product.dto.ProductResponse; import com.helpmeCookies.product.entity.Product; import com.helpmeCookies.product.service.ProductService; +import com.helpmeCookies.product.service.dto.ProductPage; +import com.helpmeCookies.product.util.ProductSort; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +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.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; @RestController -@RequestMapping("/api/v1/products") +@RequestMapping("/v1/products") +@RequiredArgsConstructor public class ProductController { private final ProductService productService; - public ProductController(ProductService productService) { - this.productService = productService; - } - @PostMapping public ResponseEntity saveProduct(@RequestBody ProductRequest productRequest) { Product product = productService.save(productRequest); @@ -41,4 +52,17 @@ public ResponseEntity deleteProduct(@PathVariable("productId") Long produc productService.delete(productId); return ResponseEntity.noContent().build(); } + + @GetMapping + public ResponseEntity getProductsByPage( + @RequestParam("query") String query, + @RequestParam(name = "size", required = false, defaultValue = "20") int size, + @RequestParam("page") int page, + @RequestParam("sort") ProductSort productSort + ) { + var sort = convertProductSort(productSort); + var pageable = PageRequest.of(page, size, sort); + + return ResponseEntity.ok(productService.getProductsByPage(query, pageable)); + } } diff --git a/src/main/java/com/helpmeCookies/product/util/ProductSort.java b/src/main/java/com/helpmeCookies/product/util/ProductSort.java new file mode 100644 index 0000000..1a37cec --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/util/ProductSort.java @@ -0,0 +1,5 @@ +package com.helpmeCookies.product.util; + +public enum ProductSort { + RELEVANCE, LATEST +} diff --git a/src/main/java/com/helpmeCookies/product/util/SortUtil.java b/src/main/java/com/helpmeCookies/product/util/SortUtil.java new file mode 100644 index 0000000..3186acf --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/util/SortUtil.java @@ -0,0 +1,14 @@ +package com.helpmeCookies.product.util; + +import org.springframework.data.domain.Sort; + +public class SortUtil { + + public static Sort convertProductSort(ProductSort productSort) { + return switch (productSort) { + case LATEST -> Sort.by(Sort.Order.desc("createdDate")); + default -> Sort.unsorted(); + }; + } + +} From 2c63651e3652f71e0259aa66c48b553965753027 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Sat, 19 Oct 2024 19:58:49 +0900 Subject: [PATCH 07/42] refactor:[#54]- refact userDomain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UserInfo에 대한 정보를 변경한다. --- .../com/helpmeCookies/user/dto/UserDto.java | 4 ++++ .../helpmeCookies/user/dto/UserInfoDto.java | 6 ------ .../user/dto/response/UserCommonInfoRes.java | 9 +++++---- .../user/dto/response/UserDetailsInfoRes.java | 19 ++++++++++--------- .../com/helpmeCookies/user/entity/User.java | 4 ++++ .../helpmeCookies/user/entity/UserInfo.java | 4 ---- .../user/service/ArtistService.java | 6 ++++-- 7 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/dto/UserDto.java b/src/main/java/com/helpmeCookies/user/dto/UserDto.java index d5544d5..b3c46e2 100644 --- a/src/main/java/com/helpmeCookies/user/dto/UserDto.java +++ b/src/main/java/com/helpmeCookies/user/dto/UserDto.java @@ -9,12 +9,16 @@ public record UserDto( Long id, UserInfoDto userInfo, + String userImageUrl, + String nickname, LocalDateTime createdAt ) { public static UserDto fromEntity(User user) { return new UserDto( user.getId(), UserInfoDto.fromEntity(user.getUserInfo()), + user.getUserImageUrl(), + user.getNickname(), user.getCreatedAt() ); } diff --git a/src/main/java/com/helpmeCookies/user/dto/UserInfoDto.java b/src/main/java/com/helpmeCookies/user/dto/UserInfoDto.java index 28099ff..ef1bedd 100644 --- a/src/main/java/com/helpmeCookies/user/dto/UserInfoDto.java +++ b/src/main/java/com/helpmeCookies/user/dto/UserInfoDto.java @@ -8,8 +8,6 @@ public record UserInfoDto( String name, - String userImageUrl, - String nickname, String email, String birthdate, String phone, @@ -19,8 +17,6 @@ public record UserInfoDto( public static UserInfoDto fromEntity(UserInfo userInfo) { return new UserInfoDto( userInfo.getName(), - userInfo.getUserImageUrl(), - userInfo.getNickname(), userInfo.getEmail(), userInfo.getBirthdate(), userInfo.getPhone(), @@ -32,8 +28,6 @@ public static UserInfoDto fromEntity(UserInfo userInfo) { public UserInfo toEntity() { return new UserInfo( name, - userImageUrl, - nickname, email, birthdate, phone, diff --git a/src/main/java/com/helpmeCookies/user/dto/response/UserCommonInfoRes.java b/src/main/java/com/helpmeCookies/user/dto/response/UserCommonInfoRes.java index 5cc9ce4..0f270df 100644 --- a/src/main/java/com/helpmeCookies/user/dto/response/UserCommonInfoRes.java +++ b/src/main/java/com/helpmeCookies/user/dto/response/UserCommonInfoRes.java @@ -3,6 +3,7 @@ import java.util.List; import com.helpmeCookies.product.entity.HashTag; +import com.helpmeCookies.user.dto.UserDto; import com.helpmeCookies.user.dto.UserInfoDto; public record UserCommonInfoRes( @@ -10,11 +11,11 @@ public record UserCommonInfoRes( List hashTags, String userImageUrl ) { - public static UserCommonInfoRes fromDto(UserInfoDto userInfoDto) { + public static UserCommonInfoRes fromDto(UserDto userDto) { return new UserCommonInfoRes( - userInfoDto.nickname(), - userInfoDto.hashTags(), - userInfoDto.userImageUrl() + userDto.userInfo().name(), + userDto.userInfo().hashTags(), + userDto.userImageUrl() ); } diff --git a/src/main/java/com/helpmeCookies/user/dto/response/UserDetailsInfoRes.java b/src/main/java/com/helpmeCookies/user/dto/response/UserDetailsInfoRes.java index 67fface..579e250 100644 --- a/src/main/java/com/helpmeCookies/user/dto/response/UserDetailsInfoRes.java +++ b/src/main/java/com/helpmeCookies/user/dto/response/UserDetailsInfoRes.java @@ -3,6 +3,7 @@ import java.util.List; import com.helpmeCookies.product.entity.HashTag; +import com.helpmeCookies.user.dto.UserDto; import com.helpmeCookies.user.dto.UserInfoDto; import lombok.Builder; @@ -18,16 +19,16 @@ public record UserDetailsInfoRes( String address, List hashTags ) { - public static UserDetailsInfoRes fromDto(UserInfoDto userInfoDto) { + public static UserDetailsInfoRes fromDto(UserDto userDto) { return UserDetailsInfoRes.builder() - .name(userInfoDto.name()) - .userImageUrl(userInfoDto.userImageUrl()) - .nickname(userInfoDto.nickname()) - .email(userInfoDto.email()) - .birthdate(userInfoDto.birthdate()) - .phone(userInfoDto.phone()) - .address(userInfoDto.address()) - .hashTags(userInfoDto.hashTags()) + .name(userDto.userInfo().name()) + .userImageUrl(userDto.userImageUrl()) + .nickname(userDto.nickname()) + .email(userDto.userInfo().email()) + .birthdate(userDto.userInfo().birthdate()) + .phone(userDto.userInfo().phone()) + .address(userDto.userInfo().address()) + .hashTags(userDto.userInfo().hashTags()) .build(); } } diff --git a/src/main/java/com/helpmeCookies/user/entity/User.java b/src/main/java/com/helpmeCookies/user/entity/User.java index 4fee3a0..1e26b75 100644 --- a/src/main/java/com/helpmeCookies/user/entity/User.java +++ b/src/main/java/com/helpmeCookies/user/entity/User.java @@ -41,6 +41,10 @@ public class User { @Column(nullable = false) private Long id; + private String nickname; + + private String userImageUrl; + @Embedded private UserInfo userInfo; diff --git a/src/main/java/com/helpmeCookies/user/entity/UserInfo.java b/src/main/java/com/helpmeCookies/user/entity/UserInfo.java index e70ac05..8b5453b 100644 --- a/src/main/java/com/helpmeCookies/user/entity/UserInfo.java +++ b/src/main/java/com/helpmeCookies/user/entity/UserInfo.java @@ -25,10 +25,6 @@ public class UserInfo { private String name; - private String nickname; - - private String userImageUrl; - private String email; private String birthdate; diff --git a/src/main/java/com/helpmeCookies/user/service/ArtistService.java b/src/main/java/com/helpmeCookies/user/service/ArtistService.java index 015f319..3f63d32 100644 --- a/src/main/java/com/helpmeCookies/user/service/ArtistService.java +++ b/src/main/java/com/helpmeCookies/user/service/ArtistService.java @@ -45,7 +45,8 @@ public void registerStudentsArtist(StudentArtistReq studentArtistReq, Long userI ArtistInfo artistInfo = ArtistInfo.builder() .userId(userId) .artistType(ArtistType.STUDENT) - .nickname(user.getUserInfo().getNickname()) + .artistImageUrl(user.getUserImageUrl()) + .nickname(user.getNickname()) .totalFollowers(0L) .totalLikes(0L) .about(studentArtistReq.about()) @@ -74,8 +75,9 @@ public void registerBusinessArtist(BusinessArtistReq businessArtistReq, Long use // BusinessArtist 생성 ArtistInfo artistInfo = ArtistInfo.builder() .userId(userId) + .artistImageUrl(user.getUserImageUrl()) .artistType(ArtistType.BUSINESS) - .nickname(user.getUserInfo().getNickname()) + .nickname(user.getNickname()) .totalFollowers(0L) .totalLikes(0L) .about(businessArtistReq.about()) From 17b78fdadebf3bcb09fd51bee634b1dc055f64a4 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Sat, 19 Oct 2024 19:59:46 +0900 Subject: [PATCH 08/42] refactor:[#54]- refact Swagger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 스웨거 관리 인터페이스를 추가하고 변경한다. --- .../user/controller/ArtistController.java | 5 +- .../user/controller/LoginController.java | 4 +- .../user/controller/UserController.java | 41 +++++-------- .../controller/apiDocs/ArtistApiDocs.java | 47 +++++++++++++++ .../user/controller/apiDocs/UserApiDocs.java | 57 +++++++++++++++++++ .../querydsl/UserCustomRepositoryImpl.java | 3 +- .../user/service/UserService.java | 9 ++- 7 files changed, 128 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java create mode 100644 src/main/java/com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java diff --git a/src/main/java/com/helpmeCookies/user/controller/ArtistController.java b/src/main/java/com/helpmeCookies/user/controller/ArtistController.java index 607f425..32a71f7 100644 --- a/src/main/java/com/helpmeCookies/user/controller/ArtistController.java +++ b/src/main/java/com/helpmeCookies/user/controller/ArtistController.java @@ -10,6 +10,7 @@ import com.helpmeCookies.global.jwt.JwtProvider; import com.helpmeCookies.global.jwt.JwtUser; +import com.helpmeCookies.user.controller.apiDocs.ArtistApiDocs; import com.helpmeCookies.user.dto.request.BusinessArtistReq; import com.helpmeCookies.user.dto.request.StudentArtistReq; import com.helpmeCookies.user.dto.response.ArtistDetailsRes; @@ -22,10 +23,8 @@ @RestController @RequiredArgsConstructor @Tag(name = "작가 관련 기능", description = "작가 관련 API") -public class ArtistController { +public class ArtistController implements ArtistApiDocs { private final ArtistService artistService; - private final JwtProvider jwtProvider; - @Operation(summary = "학생 작가 등록", description = "학생 작가 등록") @PostMapping("/v1/artists/students") diff --git a/src/main/java/com/helpmeCookies/user/controller/LoginController.java b/src/main/java/com/helpmeCookies/user/controller/LoginController.java index 319af2a..35e74ac 100644 --- a/src/main/java/com/helpmeCookies/user/controller/LoginController.java +++ b/src/main/java/com/helpmeCookies/user/controller/LoginController.java @@ -29,18 +29,18 @@ public class LoginController { @GetMapping("/test/signup") public JwtToken signup() { UserInfo userInfo = UserInfo.builder() - .userImageUrl("https://www.naver.com") .email("test@test") .birthdate("1995-01-01") .phone("010-1234-5678") .hashTags(List.of(HashTag.DREAMLIKE)) .name("test") - .nickname("test") .address("서울시 강남구") .build(); User user = User.builder() .userInfo(userInfo) + .nickname("test") + .userImageUrl("test") .build(); userRepository.save(user); diff --git a/src/main/java/com/helpmeCookies/user/controller/UserController.java b/src/main/java/com/helpmeCookies/user/controller/UserController.java index dbbe184..058fccb 100644 --- a/src/main/java/com/helpmeCookies/user/controller/UserController.java +++ b/src/main/java/com/helpmeCookies/user/controller/UserController.java @@ -4,6 +4,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; +import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.DeleteMapping; @@ -15,6 +16,7 @@ import org.springframework.web.bind.annotation.RestController; import com.helpmeCookies.global.jwt.JwtUser; +import com.helpmeCookies.user.controller.apiDocs.UserApiDocs; import com.helpmeCookies.user.dto.UserFollowingDto; import com.helpmeCookies.user.dto.response.UserCommonInfoRes; import com.helpmeCookies.user.dto.request.UserInfoReq; @@ -29,39 +31,31 @@ @RestController @RequiredArgsConstructor -@Tag(name = "유저 및 팔로우 기능", description = "유저 및 팔로우 기능과 관련된 API") -public class UserController { +public class UserController implements UserApiDocs { private final UserService userService; - @Operation(summary = "유저 일반 정보 조회", description = "로그인한 유저의 username, imageUrl, hashtag를 조회한다.") @GetMapping("/v1/users") - public UserCommonInfoRes getUsers( + public ResponseEntity getUsers( @AuthenticationPrincipal JwtUser jwtUser ) { - return UserCommonInfoRes.fromDto(userService.getUserInfo(jwtUser.getId())); + return ResponseEntity.ok(UserCommonInfoRes.fromDto(userService.getUserInfo(jwtUser.getId()))); } - // 유저 상세 정보 조회 - @Operation(summary = "유저 상세 정보 조회", description = "로그인한 유저의 이름, 주소를 비롯한 개인정보를 함께 조회한다.") @GetMapping("/v1/users/details") - public UserDetailsInfoRes getUserDetails( + public ResponseEntity getUserDetails( @AuthenticationPrincipal JwtUser jwtUser ) { - return UserDetailsInfoRes.fromDto(userService.getUserInfo(jwtUser.getId())); + return ResponseEntity.ok(UserDetailsInfoRes.fromDto(userService.getUserInfo(jwtUser.getId()))); } - // 유저 타입 조회 - @Operation(summary = "유저 타입 조회", description = "로그인한 유저의 타입과 권한을 조회한다.") @GetMapping("/v1/users/type") - public UserTypeDto getUserType( + public ResponseEntity getUserType( @AuthenticationPrincipal JwtUser jwtUser ) { - return userService.getUserType(jwtUser.getId()); + return ResponseEntity.ok(userService.getUserType(jwtUser.getId())); } - // 유저 정보 수정 - @Operation(summary = "유저 정보 수정", description = "로그인한 유저의 개인정보를 수정한다.") @PutMapping("/v1/users") public String updateUserInfo( @AuthenticationPrincipal JwtUser jwtUser, @@ -72,37 +66,32 @@ public String updateUserInfo( return "ok"; } - @Operation(summary = "아티스트 팔로우하기", description = "로그인한 유저가 특정 아티스트를 팔로우한다.") @PostMapping("/v1/users/following/{artistId}") - public String followArtist( + public ResponseEntity followArtist( @AuthenticationPrincipal JwtUser jwtUser, @PathVariable Long artistId ) { userService.followArtist(jwtUser.getId(), artistId); - return "ok"; + return ResponseEntity.ok().build(); } - @Operation(summary = "아티스트 팔로우 취소하기", description = "로그인한 유저가 특정 아티스트를 팔로우 취소한다.") @DeleteMapping("/v1/users/following/{artistId}") - public String unfollowArtist( + public ResponseEntity unfollowArtist( @AuthenticationPrincipal JwtUser jwtUser, @PathVariable Long artistId ) { userService.unfollowArtist(jwtUser.getId(), artistId); - return "ok"; + return ResponseEntity.ok().build(); } - @Operation(summary = "팔로잉 목록 조회", description = "로그인한 유저의 팔로우한 아티스트 목록을 조회한다.") @GetMapping("/v1/users/following") - public Page getFollowingList( + public ResponseEntity> getFollowingList( @AuthenticationPrincipal JwtUser jwtUser, @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable ) { - return userService.getFollowingWithPaging(jwtUser.getId(),pageable); + return ResponseEntity.ok(userService.getFollowingWithPaging(jwtUser.getId(), pageable)); } - // 유저 탈퇴 - @Operation(summary = "유저 탈퇴", description = "로그인한 유저의 정보를 삭제한다.") @DeleteMapping("/v1/users") public String deleteUser( @AuthenticationPrincipal JwtUser jwtUser diff --git a/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java b/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java new file mode 100644 index 0000000..3f77c43 --- /dev/null +++ b/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java @@ -0,0 +1,47 @@ +package com.helpmeCookies.user.controller.apiDocs; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +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 com.helpmeCookies.global.jwt.JwtUser; +import com.helpmeCookies.user.dto.request.BusinessArtistReq; +import com.helpmeCookies.user.dto.request.StudentArtistReq; +import com.helpmeCookies.user.dto.response.ArtistDetailsRes; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +@Tag(name = "작가 관련 기능", description = "작가 관련 API") +public interface ArtistApiDocs { + + @Operation(summary = "학생 작가 등록", description = "학생 작가 등록") + @PostMapping("/v1/artists/students") + ResponseEntity registerStudents( + @RequestBody StudentArtistReq artistDetailsReq, + @AuthenticationPrincipal JwtUser jwtUser + ); + + @Operation(summary = "사업자 작가 등록", description = "사업자 작가 등록") + @PostMapping("/v1/artists/bussinesses") + ResponseEntity registerbussinsess( + @RequestBody BusinessArtistReq businessArtistReq, + @AuthenticationPrincipal JwtUser jwtUser + ); + + @Operation(summary = "작가 프로필 조회", description = "작가 프로필 조회") + @GetMapping("/v1/artists/{userId}") + ArtistDetailsRes getArtist( + @AuthenticationPrincipal JwtUser jwtUser, + @PathVariable Long userId + ); + + @Operation(summary = "작가 프로필 조회", description = "자신의 작가 프로필 조회") + @GetMapping("/v1/artist") + ArtistDetailsRes getArtist( + @AuthenticationPrincipal JwtUser jwtUser + ); +} diff --git a/src/main/java/com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java b/src/main/java/com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java new file mode 100644 index 0000000..bfbdde4 --- /dev/null +++ b/src/main/java/com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java @@ -0,0 +1,57 @@ +package com.helpmeCookies.user.controller.apiDocs; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; + +import com.helpmeCookies.global.jwt.JwtUser; +import com.helpmeCookies.user.dto.UserTypeDto; +import com.helpmeCookies.user.dto.response.UserCommonInfoRes; +import com.helpmeCookies.user.dto.response.UserDetailsInfoRes; +import com.helpmeCookies.user.dto.response.UserFollowingRes; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; + +@Tag(name = "유저 및 팔로우 기능", description = "유저 및 팔로우 기능과 관련된 API") +public interface UserApiDocs { + + @Operation(summary = "유저 일반 정보 조회", description = "로그인한 유저의 username, imageUrl, hashtag를 조회한다.") + @GetMapping("/v1/users") + ResponseEntity getUsers(@AuthenticationPrincipal JwtUser jwtUser); + + @Operation(summary = "유저 상세 정보 조회", description = "로그인한 유저의 상세 정보를 조회한다.") + @GetMapping("/v1/users/details") + ResponseEntity getUserDetails(@AuthenticationPrincipal JwtUser jwtUser); + + @Operation(summary = "유저 타입 조회", description = "로그인한 유저의 타입과 권한을 조회한다.") + @GetMapping("/v1/users/type") + public ResponseEntity getUserType(@AuthenticationPrincipal JwtUser jwtUser); + + @Operation(summary = "아티스트 팔로우하기", description = "로그인한 유저가 특정 아티스트를 팔로우한다.") + @PostMapping("/v1/users/following/{artistId}") + public ResponseEntity followArtist( + @AuthenticationPrincipal JwtUser jwtUser, @PathVariable Long artistId + ); + + @Operation(summary = "아티스트 팔로우 취소하기", description = "로그인한 유저가 특정 아티스트를 팔로우 취소한다.") + @DeleteMapping("/v1/users/following/{artistId}") + public ResponseEntity unfollowArtist( + @AuthenticationPrincipal JwtUser jwtUser, + @PathVariable Long artistId + ); + + @Operation(summary = "팔로잉 목록 조회", description = "로그인한 유저의 팔로우한 아티스트 목록을 조회한다.") + @GetMapping("/v1/users/following") + public ResponseEntity> getFollowingList( + @AuthenticationPrincipal JwtUser jwtUser, + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable + ); +} diff --git a/src/main/java/com/helpmeCookies/user/repository/querydsl/UserCustomRepositoryImpl.java b/src/main/java/com/helpmeCookies/user/repository/querydsl/UserCustomRepositoryImpl.java index ca3164e..bd31f40 100644 --- a/src/main/java/com/helpmeCookies/user/repository/querydsl/UserCustomRepositoryImpl.java +++ b/src/main/java/com/helpmeCookies/user/repository/querydsl/UserCustomRepositoryImpl.java @@ -27,9 +27,8 @@ public class UserCustomRepositoryImpl implements UserCustomRepository { public Page findFollowingUsers(Long userId, Pageable pageable) { QUser user = QUser.user; QArtistInfo artistInfo = QArtistInfo.artistInfo; - QSocial social = QSocial.social; // Social 테이블 추가 + QSocial social = QSocial.social; - // JPQLQuery query = queryFactory .select(Projections.constructor( UserFollowingDto.class, diff --git a/src/main/java/com/helpmeCookies/user/service/UserService.java b/src/main/java/com/helpmeCookies/user/service/UserService.java index 139405b..8bbf410 100644 --- a/src/main/java/com/helpmeCookies/user/service/UserService.java +++ b/src/main/java/com/helpmeCookies/user/service/UserService.java @@ -30,12 +30,11 @@ public class UserService { @Transactional - public UserInfoDto getUserInfo(Long userId) { - UserInfo userInfo = userRepository.findById(userId) - .orElseThrow(() -> new ResourceNotFoundException("존재하지 않는 유저입니다.")) - .getUserInfo(); + public UserDto getUserInfo(Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new ResourceNotFoundException("존재하지 않는 유저입니다.")); - return UserInfoDto.fromEntity(userInfo); + return UserDto.fromEntity(user); } @Transactional From 677d27af7d974f088ff48424d31f6016c2c07c65 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Sat, 19 Oct 2024 20:07:09 +0900 Subject: [PATCH 09/42] refactor:[#54]- refact userDto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit userDto를 수정한다 --- .../java/com/helpmeCookies/user/dto/request/UserInfoReq.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/dto/request/UserInfoReq.java b/src/main/java/com/helpmeCookies/user/dto/request/UserInfoReq.java index d5c44a1..eee632c 100644 --- a/src/main/java/com/helpmeCookies/user/dto/request/UserInfoReq.java +++ b/src/main/java/com/helpmeCookies/user/dto/request/UserInfoReq.java @@ -22,8 +22,6 @@ public UserInfoDto toDto() { nickname, email, birthdate, - phone, - address, hashTags ); } From 73f68e5339696e090ca9a195040e8c05cbdec1c6 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 03:55:06 +0900 Subject: [PATCH 10/42] =?UTF-8?q?#27=20add:=20JpaAuditing=EC=9D=84=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9=ED=95=9C=20BaseTimeEntity=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/helpmeCookies/Step3Application.java | 2 ++ .../global/entity/BaseTimeEntity.java | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/global/entity/BaseTimeEntity.java diff --git a/src/main/java/com/helpmeCookies/Step3Application.java b/src/main/java/com/helpmeCookies/Step3Application.java index c6bad29..a594415 100644 --- a/src/main/java/com/helpmeCookies/Step3Application.java +++ b/src/main/java/com/helpmeCookies/Step3Application.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication +@EnableJpaAuditing public class Step3Application { public static void main(String[] args) { diff --git a/src/main/java/com/helpmeCookies/global/entity/BaseTimeEntity.java b/src/main/java/com/helpmeCookies/global/entity/BaseTimeEntity.java new file mode 100644 index 0000000..9279fc3 --- /dev/null +++ b/src/main/java/com/helpmeCookies/global/entity/BaseTimeEntity.java @@ -0,0 +1,21 @@ +package com.helpmeCookies.global.entity; + +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import lombok.Getter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@Getter +public abstract class BaseTimeEntity { + + @CreatedDate + private LocalDateTime createdDate; + + @LastModifiedDate + private LocalDateTime modifiedDate; +} From b753e67e8a9fe3d96371fd7892c11e68a1a1d620 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:25:27 +0900 Subject: [PATCH 11/42] =?UTF-8?q?#27=20add:=20Product=20BaseTimeEntity=20?= =?UTF-8?q?=EC=83=81=EC=86=8D,=20ArtistInfo=20JoinColumn=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/helpmeCookies/product/entity/Product.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/helpmeCookies/product/entity/Product.java b/src/main/java/com/helpmeCookies/product/entity/Product.java index d44b972..584b32a 100644 --- a/src/main/java/com/helpmeCookies/product/entity/Product.java +++ b/src/main/java/com/helpmeCookies/product/entity/Product.java @@ -1,5 +1,7 @@ package com.helpmeCookies.product.entity; +import com.helpmeCookies.global.entity.BaseTimeEntity; +import jakarta.persistence.JoinColumn; import java.util.List; import com.helpmeCookies.user.entity.ArtistInfo; @@ -17,7 +19,7 @@ import lombok.Builder; @Entity -public class Product { +public class Product extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -48,6 +50,7 @@ public class Product { private List hashTags; @ManyToOne + @JoinColumn(name = "artist_info_id") private ArtistInfo artistInfo; public Product() {} From 2c29a01bbb1c5cc5e5ea143623aa929549f5e3c4 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:26:55 +0900 Subject: [PATCH 12/42] =?UTF-8?q?#27=20feat(persistence):=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1(imageUrl=20=EC=B6=94=EA=B0=80=20=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/repository/ProductRepository.java | 19 +++++++++++++++++++ .../product/repository/dto/ProductSearch.java | 9 +++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java diff --git a/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java b/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java index d8b05f3..aca10a1 100644 --- a/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java +++ b/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java @@ -1,9 +1,28 @@ package com.helpmeCookies.product.repository; import com.helpmeCookies.product.entity.Product; +import com.helpmeCookies.product.repository.dto.ProductSearch; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface ProductRepository extends JpaRepository { + + @Query("SELECT p.id AS id, p.name AS name, a.name AS artist, p.price AS price " + + "FROM Product p JOIN p.artistInfo a " + + "WHERE p.name LIKE %:query%") // Index 미사용 + Page findByName(@Param("query") String query, Pageable pageable); + + @Query(value = "SELECT p.id, p.name, a.name AS artist, p.price " + + "FROM product p JOIN artist_info a ON p.artist_info_id = a.id " + + "WHERE MATCH(p.name) AGAINST (:query IN BOOLEAN MODE)", + countQuery = "SELECT COUNT(*) " + + "FROM product p JOIN artist_info a ON p.artist_info_id = a.id " + + "WHERE MATCH(p.name) AGAINST (:query IN BOOLEAN MODE)", + nativeQuery = true) // Index 사용 + Page findByNameWithIdx(@Param("query") String query, Pageable pageable); } diff --git a/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java b/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java new file mode 100644 index 0000000..3c5fcee --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java @@ -0,0 +1,9 @@ +package com.helpmeCookies.product.repository.dto; + + +public interface ProductSearch { + Long getId(); + String getName(); + String getArtist(); + Long getPrice(); +} From 1d2d527c91d46d197ed72895ec0aade02c99f06e Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:27:10 +0900 Subject: [PATCH 13/42] =?UTF-8?q?#27=20feat(product.service):=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/service/ProductService.java | 8 ++++ .../product/service/dto/ProductPage.java | 44 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java diff --git a/src/main/java/com/helpmeCookies/product/service/ProductService.java b/src/main/java/com/helpmeCookies/product/service/ProductService.java index c9b22d4..b0b156d 100644 --- a/src/main/java/com/helpmeCookies/product/service/ProductService.java +++ b/src/main/java/com/helpmeCookies/product/service/ProductService.java @@ -5,7 +5,9 @@ import com.helpmeCookies.product.entity.Product; import com.helpmeCookies.product.repository.ProductImageRepository; import com.helpmeCookies.product.repository.ProductRepository; +import com.helpmeCookies.product.dto.ProductPage; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -15,6 +17,12 @@ public class ProductService { private final ProductRepository productRepository; private final ProductImageRepository productImageRepository; + @Transactional(readOnly = true) + public ProductPage.Paging getProductsByPage(String query, Pageable pageable) { + var productPage = productRepository.findByNameWithIdx(query, pageable); + return ProductPage.Paging.from(productPage); + } + public Product save(ProductRequest productSaveRequest) { //TODO ArtistInfo 코드 병합시 수정 예정 Product product = productSaveRequest.toEntity(null); diff --git a/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java b/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java new file mode 100644 index 0000000..0b2b920 --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java @@ -0,0 +1,44 @@ +package com.helpmeCookies.product.service.dto; + +import com.helpmeCookies.product.repository.dto.ProductSearch; +import java.util.List; +import org.springframework.data.domain.Page; + +public class ProductPage { + + public record Info( + Long id, + String name, + String artist, + Long price + ) { + public static Info from(ProductSearch productSearch) { + return new Info( + productSearch.getId(), + productSearch.getName(), + productSearch.getArtist(), + productSearch.getPrice() + ); + } + + public static List of(List content) { + return content.stream() + .map(Info::from) + .toList(); + } + } + + public record Paging ( + boolean hasNext, + List products + ) { + + public static Paging from(Page productPage) { + return new Paging( + productPage.hasNext(), + Info.of(productPage.getContent()) + ); + } + } + +} From e4e393ae1b922e8a1b482974efed075ce78728a3 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Thu, 3 Oct 2024 04:27:18 +0900 Subject: [PATCH 14/42] =?UTF-8?q?#27=20feat(product.controller):=20?= =?UTF-8?q?=EC=83=81=ED=92=88=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/controller/ProductController.java | 18 ++++++++++++++++++ .../product/util/ProductSort.java | 5 +++++ .../helpmeCookies/product/util/SortUtil.java | 14 ++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/product/util/ProductSort.java create mode 100644 src/main/java/com/helpmeCookies/product/util/SortUtil.java diff --git a/src/main/java/com/helpmeCookies/product/controller/ProductController.java b/src/main/java/com/helpmeCookies/product/controller/ProductController.java index c655ee7..e3b03c9 100644 --- a/src/main/java/com/helpmeCookies/product/controller/ProductController.java +++ b/src/main/java/com/helpmeCookies/product/controller/ProductController.java @@ -2,12 +2,17 @@ import com.helpmeCookies.product.dto.FileUploadResponse; import com.helpmeCookies.product.dto.ProductImageResponse; +import static com.helpmeCookies.product.util.SortUtil.convertProductSort; + import com.helpmeCookies.product.dto.ProductRequest; import com.helpmeCookies.product.dto.ProductResponse; import com.helpmeCookies.product.entity.Product; import com.helpmeCookies.product.service.ProductImageService; import com.helpmeCookies.product.service.ProductService; import lombok.RequiredArgsConstructor; +import com.helpmeCookies.product.dto.ProductPage; +import com.helpmeCookies.product.util.ProductSort; +import org.springframework.data.domain.PageRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -59,4 +64,17 @@ public ResponseEntity deleteProduct(@PathVariable("productId") Long produc productService.delete(productId); return ResponseEntity.noContent().build(); } + + @GetMapping + public ResponseEntity getProductsByPage( + @RequestParam("query") String query, + @RequestParam(name = "size", required = false, defaultValue = "20") int size, + @RequestParam("page") int page, + @RequestParam("sort") ProductSort productSort + ) { + var sort = convertProductSort(productSort); + var pageable = PageRequest.of(page, size, sort); + + return ResponseEntity.ok(productService.getProductsByPage(query, pageable)); + } } diff --git a/src/main/java/com/helpmeCookies/product/util/ProductSort.java b/src/main/java/com/helpmeCookies/product/util/ProductSort.java new file mode 100644 index 0000000..1a37cec --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/util/ProductSort.java @@ -0,0 +1,5 @@ +package com.helpmeCookies.product.util; + +public enum ProductSort { + RELEVANCE, LATEST +} diff --git a/src/main/java/com/helpmeCookies/product/util/SortUtil.java b/src/main/java/com/helpmeCookies/product/util/SortUtil.java new file mode 100644 index 0000000..3186acf --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/util/SortUtil.java @@ -0,0 +1,14 @@ +package com.helpmeCookies.product.util; + +import org.springframework.data.domain.Sort; + +public class SortUtil { + + public static Sort convertProductSort(ProductSort productSort) { + return switch (productSort) { + case LATEST -> Sort.by(Sort.Order.desc("createdDate")); + default -> Sort.unsorted(); + }; + } + +} From e2456f8b01f7d55fea5dac9cd20d518fbcbc585c Mon Sep 17 00:00:00 2001 From: sim-mer Date: Fri, 25 Oct 2024 04:16:51 +0900 Subject: [PATCH 15/42] =?UTF-8?q?#27=20chore(build.gradle):=20testcontaine?= =?UTF-8?q?rs=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build.gradle b/build.gradle index 2000e5e..615d23c 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,14 @@ dependencies { //S3 implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' + + //Test + testImplementation 'org.testcontainers:testcontainers:1.20.2' + testImplementation 'org.testcontainers:junit-jupiter:1.20.2' + testImplementation 'org.testcontainers:mysql:1.20.2' + } + tasks.named('test') { useJUnitPlatform() } From 46e885e9fb8e33afa6a4c860f726d53750a7a8e9 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Fri, 25 Oct 2024 04:19:44 +0900 Subject: [PATCH 16/42] =?UTF-8?q?#27=20refactor(ProductPage.java):=20Produ?= =?UTF-8?q?ctPage=20=ED=8C=A8=ED=82=A4=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 --- .../product/controller/ProductController.java | 3 +- .../product/service/dto/ProductPage.java | 44 ------------------- 2 files changed, 2 insertions(+), 45 deletions(-) delete mode 100644 src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java diff --git a/src/main/java/com/helpmeCookies/product/controller/ProductController.java b/src/main/java/com/helpmeCookies/product/controller/ProductController.java index e3b03c9..f87b105 100644 --- a/src/main/java/com/helpmeCookies/product/controller/ProductController.java +++ b/src/main/java/com/helpmeCookies/product/controller/ProductController.java @@ -4,14 +4,15 @@ import com.helpmeCookies.product.dto.ProductImageResponse; import static com.helpmeCookies.product.util.SortUtil.convertProductSort; +import com.helpmeCookies.product.dto.ProductPage; import com.helpmeCookies.product.dto.ProductRequest; import com.helpmeCookies.product.dto.ProductResponse; import com.helpmeCookies.product.entity.Product; import com.helpmeCookies.product.service.ProductImageService; import com.helpmeCookies.product.service.ProductService; +import com.helpmeCookies.product.util.ProductSort; import lombok.RequiredArgsConstructor; import com.helpmeCookies.product.dto.ProductPage; -import com.helpmeCookies.product.util.ProductSort; import org.springframework.data.domain.PageRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java b/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java deleted file mode 100644 index 0b2b920..0000000 --- a/src/main/java/com/helpmeCookies/product/service/dto/ProductPage.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.helpmeCookies.product.service.dto; - -import com.helpmeCookies.product.repository.dto.ProductSearch; -import java.util.List; -import org.springframework.data.domain.Page; - -public class ProductPage { - - public record Info( - Long id, - String name, - String artist, - Long price - ) { - public static Info from(ProductSearch productSearch) { - return new Info( - productSearch.getId(), - productSearch.getName(), - productSearch.getArtist(), - productSearch.getPrice() - ); - } - - public static List of(List content) { - return content.stream() - .map(Info::from) - .toList(); - } - } - - public record Paging ( - boolean hasNext, - List products - ) { - - public static Paging from(Page productPage) { - return new Paging( - productPage.hasNext(), - Info.of(productPage.getContent()) - ); - } - } - -} From be44e0fa2211c205418e3fedd019baa959134b1f Mon Sep 17 00:00:00 2001 From: sim-mer Date: Fri, 25 Oct 2024 04:21:08 +0900 Subject: [PATCH 17/42] =?UTF-8?q?#27=20fix(SortUtil.java):=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EC=A0=95=EB=A0=AC=20=EB=B3=80=ED=99=98=20=EC=9C=A0?= =?UTF-8?q?=ED=8B=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=8A=A4=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=ED=81=AC=20=EC=BC=80=EC=9D=B4=EC=8A=A4=EB=A1=9C=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/helpmeCookies/product/util/SortUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/helpmeCookies/product/util/SortUtil.java b/src/main/java/com/helpmeCookies/product/util/SortUtil.java index 3186acf..e85e068 100644 --- a/src/main/java/com/helpmeCookies/product/util/SortUtil.java +++ b/src/main/java/com/helpmeCookies/product/util/SortUtil.java @@ -6,7 +6,7 @@ public class SortUtil { public static Sort convertProductSort(ProductSort productSort) { return switch (productSort) { - case LATEST -> Sort.by(Sort.Order.desc("createdDate")); + case LATEST -> Sort.by(Sort.Order.desc("created_date")); default -> Sort.unsorted(); }; } From 8f56e6a6f85bb824ee095625a2fe4bb4e44e8a16 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Fri, 25 Oct 2024 04:32:47 +0900 Subject: [PATCH 18/42] =?UTF-8?q?#27=20feat(product):=20=EC=83=81=ED=92=88?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=95=20DTO=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/dto/ProductPage.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/product/dto/ProductPage.java diff --git a/src/main/java/com/helpmeCookies/product/dto/ProductPage.java b/src/main/java/com/helpmeCookies/product/dto/ProductPage.java new file mode 100644 index 0000000..1648c19 --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/dto/ProductPage.java @@ -0,0 +1,44 @@ +package com.helpmeCookies.product.dto; + +import com.helpmeCookies.product.repository.dto.ProductSearch; +import java.util.List; +import org.springframework.data.domain.Page; + +public class ProductPage { + + public record Info( + Long id, + String name, + String artist, + Long price + ) { + public static Info from(ProductSearch productSearch) { + return new Info( + productSearch.getId(), + productSearch.getName(), + productSearch.getArtist(), + productSearch.getPrice() + ); + } + + public static List of(List content) { + return content.stream() + .map(Info::from) + .toList(); + } + } + + public record Paging ( + boolean hasNext, + List products + ) { + + public static Paging from(Page productPage) { + return new Paging( + productPage.hasNext(), + Info.of(productPage.getContent()) + ); + } + } + +} From 36bd84f82e8906af013e264eb91889983c2f1e90 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Sun, 27 Oct 2024 10:20:08 +0900 Subject: [PATCH 19/42] =?UTF-8?q?#27=20docs(product):=20=EC=83=81=ED=92=88?= =?UTF-8?q?=20api=20=EB=AC=B8=EC=84=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?url=20mapping=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/controller/ProductController.java | 10 ++++----- .../controller/docs/ProductApiDocs.java | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/helpmeCookies/product/controller/docs/ProductApiDocs.java diff --git a/src/main/java/com/helpmeCookies/product/controller/ProductController.java b/src/main/java/com/helpmeCookies/product/controller/ProductController.java index f87b105..e575c09 100644 --- a/src/main/java/com/helpmeCookies/product/controller/ProductController.java +++ b/src/main/java/com/helpmeCookies/product/controller/ProductController.java @@ -1,9 +1,10 @@ package com.helpmeCookies.product.controller; -import com.helpmeCookies.product.dto.FileUploadResponse; -import com.helpmeCookies.product.dto.ProductImageResponse; import static com.helpmeCookies.product.util.SortUtil.convertProductSort; +import com.helpmeCookies.product.controller.docs.ProductApiDocs; +import com.helpmeCookies.product.dto.FileUploadResponse; +import com.helpmeCookies.product.dto.ProductImageResponse; import com.helpmeCookies.product.dto.ProductPage; import com.helpmeCookies.product.dto.ProductRequest; import com.helpmeCookies.product.dto.ProductResponse; @@ -12,7 +13,6 @@ import com.helpmeCookies.product.service.ProductService; import com.helpmeCookies.product.util.ProductSort; import lombok.RequiredArgsConstructor; -import com.helpmeCookies.product.dto.ProductPage; import org.springframework.data.domain.PageRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -22,9 +22,9 @@ import java.util.List; @RestController -@RequestMapping("/api/v1/products") +@RequestMapping("/v1/products") @RequiredArgsConstructor -public class ProductController { +public class ProductController implements ProductApiDocs { private final ProductService productService; private final ProductImageService productImageService; diff --git a/src/main/java/com/helpmeCookies/product/controller/docs/ProductApiDocs.java b/src/main/java/com/helpmeCookies/product/controller/docs/ProductApiDocs.java new file mode 100644 index 0000000..e0097b5 --- /dev/null +++ b/src/main/java/com/helpmeCookies/product/controller/docs/ProductApiDocs.java @@ -0,0 +1,21 @@ +package com.helpmeCookies.product.controller.docs; + +import com.helpmeCookies.product.dto.ProductPage.Paging; +import com.helpmeCookies.product.util.ProductSort; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; + +@Tag(name = "상품 관련 기능", description = "상품 관련 API") +public interface ProductApiDocs { + + @Operation(summary = "상품 검색") + ResponseEntity getProductsByPage( + String query, + @Parameter(description = "default value 20") int size, + int page, + ProductSort productSort + ); + +} From 30769a7bae59e862cc0d219b72604cc543922270 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Sun, 27 Oct 2024 10:20:54 +0900 Subject: [PATCH 20/42] =?UTF-8?q?#27=20fix(product):=20ArtistInfo=20entity?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../helpmeCookies/product/repository/ProductRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java b/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java index aca10a1..512722d 100644 --- a/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java +++ b/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java @@ -12,12 +12,12 @@ @Repository public interface ProductRepository extends JpaRepository { - @Query("SELECT p.id AS id, p.name AS name, a.name AS artist, p.price AS price " + + @Query("SELECT p.id AS id, p.name AS name, a.nickname AS artist, p.price AS price " + "FROM Product p JOIN p.artistInfo a " + "WHERE p.name LIKE %:query%") // Index 미사용 Page findByName(@Param("query") String query, Pageable pageable); - @Query(value = "SELECT p.id, p.name, a.name AS artist, p.price " + + @Query(value = "SELECT p.id, p.name, a.nickname AS artist, p.price " + "FROM product p JOIN artist_info a ON p.artist_info_id = a.id " + "WHERE MATCH(p.name) AGAINST (:query IN BOOLEAN MODE)", countQuery = "SELECT COUNT(*) " + From 803d9dfb773b5a07b1abc0d23fdd297161a202e7 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Sun, 27 Oct 2024 10:22:37 +0900 Subject: [PATCH 21/42] =?UTF-8?q?#27=20test(product):=20=EC=83=81=ED=92=88?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/search/SearchControllerTest.java | 76 +++++++++++++++++++ .../product/search/SearchRepositoryTest.java | 54 +++++++++++++ .../product/search/SearchServiceTest.java | 63 +++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java create mode 100644 src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java create mode 100644 src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java diff --git a/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java b/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java new file mode 100644 index 0000000..be84884 --- /dev/null +++ b/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java @@ -0,0 +1,76 @@ +package com.helpmeCookies.product.search; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.helpmeCookies.global.jwt.JwtProvider; +import com.helpmeCookies.product.controller.ProductController; +import com.helpmeCookies.product.dto.ProductPage; +import com.helpmeCookies.product.repository.dto.ProductSearch; +import com.helpmeCookies.product.service.ProductImageService; +import com.helpmeCookies.product.service.ProductService; +import com.helpmeCookies.product.util.ProductSort; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.test.web.servlet.MockMvc; + +@WebMvcTest(ProductController.class) +@AutoConfigureMockMvc(addFilters = false) +@Import(JwtProvider.class) +public class SearchControllerTest { + + @Autowired + private MockMvc mvc; + + @MockBean + private ProductService productService; + + @MockBean + private ProductImageService productImageService; + + + @Test + @DisplayName("상품 검색 컨트롤러") + void 상품_검색() throws Exception { + // given + String query = "product"; + int size = 10; + int page = 0; + ProductSort productSort = ProductSort.LATEST; + + var productSearch = mock(ProductSearch.class); + given(productSearch.getId()).willReturn(1L); + given(productSearch.getName()).willReturn("product1"); + given(productSearch.getArtist()).willReturn("artist"); + given(productSearch.getPrice()).willReturn(10000L); + var paging = ProductPage.Paging.from(new PageImpl<>(List.of(productSearch))); + given(productService.getProductsByPage(eq(query), any(Pageable.class))) + .willReturn(paging); + + // when & then + mvc.perform(get("/test/v1/products") + .param("query", query) + .param("size", String.valueOf(size)) + .param("page", String.valueOf(page)) + .param("sort", productSort.name())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.hasNext").value(false)) + .andExpect(jsonPath("$.products[0].name").value("product1")) + .andExpect(jsonPath("$.products[0].artist").value("artist")) + .andExpect(jsonPath("$.products[0].price").value(10000L)); + } + +} diff --git a/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java b/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java new file mode 100644 index 0000000..b5f2ad0 --- /dev/null +++ b/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java @@ -0,0 +1,54 @@ +package com.helpmeCookies.product.search; + +import static com.helpmeCookies.product.util.SortUtil.convertProductSort; +import static org.assertj.core.api.Assertions.assertThat; + +import com.helpmeCookies.global.config.QueryDSLConfig; +import com.helpmeCookies.product.repository.ProductRepository; +import com.helpmeCookies.product.util.ProductSort; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.context.annotation.Import; +import org.springframework.data.domain.PageRequest; + +@DataJpaTest +@ExtendWith(OutputCaptureExtension.class) +@Import(QueryDSLConfig.class) +public class SearchRepositoryTest { + + @Autowired + private ProductRepository productRepository; + + + @Test + @DisplayName("상품 검색 쿼리 확인") + void 상품_검색(CapturedOutput out) { + // given + var sort = convertProductSort(ProductSort.LATEST); + var pageRequest = PageRequest.of(0, 10, sort); + + // when + try{ + productRepository.findByNameWithIdx("product", pageRequest); + } catch (Exception ignored) { + } + + // then + assertThat(out.getOut()) + .contains("SELECT") + .contains("p.id,") + .contains("p.name,") + .contains("a.nickname AS artist,") + .contains("p.price") + .contains("FROM product p") + .contains("JOIN artist_info a ON p.artist_info_id = a.id") + .contains("WHERE MATCH(p.name) AGAINST (? IN BOOLEAN MODE)") + .contains("order by p.created_date desc"); + //.contains("limit ?") 테스트 dbh2 db에서는 limit이 없어서 제외 + } +} diff --git a/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java b/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java new file mode 100644 index 0000000..65c1edb --- /dev/null +++ b/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java @@ -0,0 +1,63 @@ +package com.helpmeCookies.product.search; + +import static com.helpmeCookies.product.util.SortUtil.convertProductSort; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +import com.helpmeCookies.product.repository.ProductRepository; +import com.helpmeCookies.product.repository.dto.ProductSearch; +import com.helpmeCookies.product.service.ProductService; +import com.helpmeCookies.product.util.ProductSort; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.test.context.TestComponent; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; + +@TestComponent +@ExtendWith(MockitoExtension.class) +public class SearchServiceTest { + + @Mock + private ProductRepository productRepository; + + @InjectMocks + private ProductService productService; + + @Test + @DisplayName("상품 검색 서비스") + void 상품_검색() { + // given + var sort = convertProductSort(ProductSort.LATEST); + var pageRequest = PageRequest.of(0, 10, sort); + var productSearch = mock(ProductSearch.class); + given(productSearch.getId()).willReturn(1L); + given(productSearch.getName()).willReturn("product1"); + given(productSearch.getArtist()).willReturn("artist"); + given(productSearch.getPrice()).willReturn(10000L); + + var productPage = new PageImpl<>(List.of(productSearch)); + given(productRepository.findByNameWithIdx("roduct", pageRequest)) + .willReturn(productPage); + + // when + var result = productService.getProductsByPage("roduct", pageRequest); + + // then + assertAll( + () -> assertThat(result.hasNext()).isFalse(), + () -> assertThat(result.products().size()).isEqualTo(1L), + () -> assertThat(result.products().get(0).name()).isEqualTo("product1"), + () -> assertThat(result.products().get(0).artist()).isEqualTo("artist"), + () -> assertThat(result.products().get(0).price()).isEqualTo(10000L) + ); + } + +} From daaf61eb2bd9c2b848a8fdcd0e0bde19b432f05c Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 12:03:32 +0900 Subject: [PATCH 22/42] =?UTF-8?q?#27=20feat(product):=20Product=20thumbnai?= =?UTF-8?q?lUrl=20=EC=82=BD=EC=9E=85=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/helpmeCookies/product/entity/Product.java | 6 ++++++ .../helpmeCookies/product/service/ProductImageService.java | 6 ++++++ .../product/service/ProductImageServiceTest.java | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/helpmeCookies/product/entity/Product.java b/src/main/java/com/helpmeCookies/product/entity/Product.java index 584b32a..7f07fa3 100644 --- a/src/main/java/com/helpmeCookies/product/entity/Product.java +++ b/src/main/java/com/helpmeCookies/product/entity/Product.java @@ -44,6 +44,8 @@ public class Product extends BaseTimeEntity { @Column(nullable = false) private String preferredLocation; + private String thumbnailUrl; + @ElementCollection(targetClass = HashTag.class) @CollectionTable(name = "product_hashtags") @Enumerated(EnumType.STRING) @@ -113,4 +115,8 @@ public void update(String name, Category category, String size, Long price, Stri this.hashTags = hashTags; this.artistInfo = artistInfo; } + + public void updateThumbnail(String thumbnailUrl) { + this.thumbnailUrl = thumbnailUrl; + } } diff --git a/src/main/java/com/helpmeCookies/product/service/ProductImageService.java b/src/main/java/com/helpmeCookies/product/service/ProductImageService.java index 25215c5..0e34e78 100644 --- a/src/main/java/com/helpmeCookies/product/service/ProductImageService.java +++ b/src/main/java/com/helpmeCookies/product/service/ProductImageService.java @@ -3,6 +3,7 @@ import com.helpmeCookies.global.utils.AwsS3FileUtils; import com.helpmeCookies.product.dto.FileUploadResponse; import com.helpmeCookies.product.repository.ProductImageRepository; +import com.helpmeCookies.product.repository.ProductRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,12 +17,17 @@ public class ProductImageService { private final AwsS3FileUtils awsS3FileUtils; private final ProductImageRepository productImageRepository; + private final ProductRepository productRepository; @Transactional public List uploadMultiFiles(Long productId, List files) throws IOException { List uploadResponses = awsS3FileUtils.uploadMultiImages(files); uploadResponses.forEach(response -> productImageRepository.save(response.toEntity(productId))); + + var product = productRepository.findById(productId).orElseThrow(() -> new IllegalArgumentException("유효하지 않은 id입니다")); + product.updateThumbnail(uploadResponses.getFirst().photoUrl()); + return uploadResponses; } diff --git a/src/test/java/com/helpmeCookies/product/service/ProductImageServiceTest.java b/src/test/java/com/helpmeCookies/product/service/ProductImageServiceTest.java index b0b3653..23cc74d 100644 --- a/src/test/java/com/helpmeCookies/product/service/ProductImageServiceTest.java +++ b/src/test/java/com/helpmeCookies/product/service/ProductImageServiceTest.java @@ -41,7 +41,7 @@ class ProductImageServiceTest { @BeforeEach void setUp() { - productImageService = new ProductImageService(awsS3FileUtils, productImageRepository); + productImageService = new ProductImageService(awsS3FileUtils, productImageRepository, productRepository); } @AfterEach From 58dad0c9e991cd015b978106b39552bd9f219414 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 12:07:50 +0900 Subject: [PATCH 23/42] =?UTF-8?q?#27=20feat(product):=20=EC=83=81=ED=92=88?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=20=EC=8B=9C=20Product=20thumbnailUrl=20?= =?UTF-8?q?=ED=8F=AC=ED=95=A8=EB=90=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/helpmeCookies/product/dto/ProductPage.java | 6 ++++-- .../product/repository/ProductRepository.java | 7 +------ .../product/repository/dto/ProductSearch.java | 1 + 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/helpmeCookies/product/dto/ProductPage.java b/src/main/java/com/helpmeCookies/product/dto/ProductPage.java index 1648c19..9778e2f 100644 --- a/src/main/java/com/helpmeCookies/product/dto/ProductPage.java +++ b/src/main/java/com/helpmeCookies/product/dto/ProductPage.java @@ -10,14 +10,16 @@ public record Info( Long id, String name, String artist, - Long price + Long price, + String thumbnailUrl ) { public static Info from(ProductSearch productSearch) { return new Info( productSearch.getId(), productSearch.getName(), productSearch.getArtist(), - productSearch.getPrice() + productSearch.getPrice(), + productSearch.getThumbnailUrl() ); } diff --git a/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java b/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java index 512722d..4b23b79 100644 --- a/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java +++ b/src/main/java/com/helpmeCookies/product/repository/ProductRepository.java @@ -12,12 +12,7 @@ @Repository public interface ProductRepository extends JpaRepository { - @Query("SELECT p.id AS id, p.name AS name, a.nickname AS artist, p.price AS price " + - "FROM Product p JOIN p.artistInfo a " + - "WHERE p.name LIKE %:query%") // Index 미사용 - Page findByName(@Param("query") String query, Pageable pageable); - - @Query(value = "SELECT p.id, p.name, a.nickname AS artist, p.price " + + @Query(value = "SELECT p.id, p.name, p.thumbnail_url, a.nickname AS artist, p.price " + "FROM product p JOIN artist_info a ON p.artist_info_id = a.id " + "WHERE MATCH(p.name) AGAINST (:query IN BOOLEAN MODE)", countQuery = "SELECT COUNT(*) " + diff --git a/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java b/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java index 3c5fcee..c997acd 100644 --- a/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java +++ b/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java @@ -6,4 +6,5 @@ public interface ProductSearch { String getName(); String getArtist(); Long getPrice(); + String getThumbnailUrl(); } From 2be345745c1f41308d0f8d271bb3ec6e3293328f Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 12:23:19 +0900 Subject: [PATCH 24/42] =?UTF-8?q?#27=20test(product):=20=EC=83=81=ED=92=88?= =?UTF-8?q?=20=EA=B2=80=EC=83=89=20thumbnailUrl=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../helpmeCookies/product/repository/dto/ProductSearch.java | 2 +- .../helpmeCookies/product/search/SearchControllerTest.java | 6 ++++-- .../helpmeCookies/product/search/SearchRepositoryTest.java | 1 + .../com/helpmeCookies/product/search/SearchServiceTest.java | 4 +++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java b/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java index c997acd..60ca2e0 100644 --- a/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java +++ b/src/main/java/com/helpmeCookies/product/repository/dto/ProductSearch.java @@ -4,7 +4,7 @@ public interface ProductSearch { Long getId(); String getName(); + String getThumbnailUrl(); String getArtist(); Long getPrice(); - String getThumbnailUrl(); } diff --git a/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java b/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java index be84884..4566fe1 100644 --- a/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java +++ b/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java @@ -56,12 +56,13 @@ public class SearchControllerTest { given(productSearch.getName()).willReturn("product1"); given(productSearch.getArtist()).willReturn("artist"); given(productSearch.getPrice()).willReturn(10000L); + given(productSearch.getThumbnailUrl()).willReturn("thumbnailUrl"); var paging = ProductPage.Paging.from(new PageImpl<>(List.of(productSearch))); given(productService.getProductsByPage(eq(query), any(Pageable.class))) .willReturn(paging); // when & then - mvc.perform(get("/test/v1/products") + mvc.perform(get("/v1/products") .param("query", query) .param("size", String.valueOf(size)) .param("page", String.valueOf(page)) @@ -70,7 +71,8 @@ public class SearchControllerTest { .andExpect(jsonPath("$.hasNext").value(false)) .andExpect(jsonPath("$.products[0].name").value("product1")) .andExpect(jsonPath("$.products[0].artist").value("artist")) - .andExpect(jsonPath("$.products[0].price").value(10000L)); + .andExpect(jsonPath("$.products[0].price").value(10000L)) + .andExpect(jsonPath("$.products[0].thumbnailUrl").value("thumbnailUrl")); } } diff --git a/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java b/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java index b5f2ad0..e914d94 100644 --- a/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java +++ b/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java @@ -43,6 +43,7 @@ public class SearchRepositoryTest { .contains("SELECT") .contains("p.id,") .contains("p.name,") + .contains("p.thumbnail_url,") .contains("a.nickname AS artist,") .contains("p.price") .contains("FROM product p") diff --git a/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java b/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java index 65c1edb..a13d83d 100644 --- a/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java +++ b/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java @@ -42,6 +42,7 @@ public class SearchServiceTest { given(productSearch.getName()).willReturn("product1"); given(productSearch.getArtist()).willReturn("artist"); given(productSearch.getPrice()).willReturn(10000L); + given(productSearch.getThumbnailUrl()).willReturn("thumbnailUrl"); var productPage = new PageImpl<>(List.of(productSearch)); given(productRepository.findByNameWithIdx("roduct", pageRequest)) @@ -56,7 +57,8 @@ public class SearchServiceTest { () -> assertThat(result.products().size()).isEqualTo(1L), () -> assertThat(result.products().get(0).name()).isEqualTo("product1"), () -> assertThat(result.products().get(0).artist()).isEqualTo("artist"), - () -> assertThat(result.products().get(0).price()).isEqualTo(10000L) + () -> assertThat(result.products().get(0).price()).isEqualTo(10000L), + () -> assertThat(result.products().get(0).thumbnailUrl()).isEqualTo("thumbnailUrl") ); } From b9ac98aca46a3f31a42adcd7c53a048184f18b72 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 13:21:16 +0900 Subject: [PATCH 25/42] =?UTF-8?q?#27=20feat(user.repository):=20=EC=9E=91?= =?UTF-8?q?=EA=B0=80=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/repository/ArtistInfoRepository.java | 18 +++++++++++++++--- .../user/repository/dto/ArtistSearch.java | 9 +++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/helpmeCookies/user/repository/dto/ArtistSearch.java diff --git a/src/main/java/com/helpmeCookies/user/repository/ArtistInfoRepository.java b/src/main/java/com/helpmeCookies/user/repository/ArtistInfoRepository.java index 49847d2..86da115 100644 --- a/src/main/java/com/helpmeCookies/user/repository/ArtistInfoRepository.java +++ b/src/main/java/com/helpmeCookies/user/repository/ArtistInfoRepository.java @@ -1,12 +1,24 @@ package com.helpmeCookies.user.repository; +import com.helpmeCookies.user.entity.ArtistInfo; +import com.helpmeCookies.user.repository.dto.ArtistSearch; import java.util.Optional; - +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; - -import com.helpmeCookies.user.entity.ArtistInfo; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface ArtistInfoRepository extends JpaRepository { Optional findByUserId(Long userId); boolean existsByUserId(Long userId); + + @Query(value = "SELECT a.id, a.nickname, a.artist_image_url, a.total_followers, a.total_likes " + + "FROM artist_info a " + + "WHERE MATCH(a.nickname) AGAINST (:query IN BOOLEAN MODE)", + countQuery = "SELECT COUNT(*) " + + "FROM artist_info a " + + "WHERE MATCH(a.nickname) AGAINST (:query IN BOOLEAN MODE)", + nativeQuery = true) // Index 사용 + Page findByNicknameWithIdx(@Param("query") String query, Pageable pageable); } diff --git a/src/main/java/com/helpmeCookies/user/repository/dto/ArtistSearch.java b/src/main/java/com/helpmeCookies/user/repository/dto/ArtistSearch.java new file mode 100644 index 0000000..777ed6a --- /dev/null +++ b/src/main/java/com/helpmeCookies/user/repository/dto/ArtistSearch.java @@ -0,0 +1,9 @@ +package com.helpmeCookies.user.repository.dto; + +public interface ArtistSearch { + Long getId(); + String getNickname(); + String getArtistImageUrl(); + Long getTotalFollowers(); + Long getTotalLikes(); +} From 135135b01d3c11063b2380725d10cf05c36e8f6f Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 13:22:29 +0900 Subject: [PATCH 26/42] =?UTF-8?q?#27=20feat(user.service):=20=EC=9E=91?= =?UTF-8?q?=EA=B0=80=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../helpmeCookies/user/service/ArtistService.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/service/ArtistService.java b/src/main/java/com/helpmeCookies/user/service/ArtistService.java index 3f63d32..c36475e 100644 --- a/src/main/java/com/helpmeCookies/user/service/ArtistService.java +++ b/src/main/java/com/helpmeCookies/user/service/ArtistService.java @@ -1,10 +1,8 @@ package com.helpmeCookies.user.service; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import com.helpmeCookies.global.exception.user.ResourceNotFoundException; import com.helpmeCookies.user.dto.ArtistInfoDto; +import com.helpmeCookies.user.dto.ArtistInfoPage; import com.helpmeCookies.user.dto.BusinessArtistDto; import com.helpmeCookies.user.dto.StudentArtistDto; import com.helpmeCookies.user.dto.request.BusinessArtistReq; @@ -20,8 +18,10 @@ import com.helpmeCookies.user.repository.StudentArtistRepository; import com.helpmeCookies.user.repository.UserRepository; import com.sun.jdi.request.DuplicateRequestException; - import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @RequiredArgsConstructor @Service @@ -115,4 +115,10 @@ public ArtistDetailsRes getArtistDetails(Long userId) { throw new ResourceNotFoundException("존재하지 않는 아티스트입니다."); } } + + @Transactional(readOnly = true) + public ArtistInfoPage.Paging getArtistsByPage(String query, Pageable pageable) { + var artistInfoPage = artistInfoRepository.findByNicknameWithIdx(query, pageable); + return ArtistInfoPage.Paging.from(artistInfoPage); + } } From 3e94711e67cf550b469f38f4eeebe5ee262877a0 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 13:22:35 +0900 Subject: [PATCH 27/42] =?UTF-8?q?#27=20feat(user.controller):=20=EC=9E=91?= =?UTF-8?q?=EA=B0=80=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/ArtistController.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/controller/ArtistController.java b/src/main/java/com/helpmeCookies/user/controller/ArtistController.java index 32a71f7..6e94168 100644 --- a/src/main/java/com/helpmeCookies/user/controller/ArtistController.java +++ b/src/main/java/com/helpmeCookies/user/controller/ArtistController.java @@ -1,24 +1,24 @@ package com.helpmeCookies.user.controller; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -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.RestController; - -import com.helpmeCookies.global.jwt.JwtProvider; import com.helpmeCookies.global.jwt.JwtUser; import com.helpmeCookies.user.controller.apiDocs.ArtistApiDocs; +import com.helpmeCookies.user.dto.ArtistInfoPage; import com.helpmeCookies.user.dto.request.BusinessArtistReq; import com.helpmeCookies.user.dto.request.StudentArtistReq; import com.helpmeCookies.user.dto.response.ArtistDetailsRes; import com.helpmeCookies.user.service.ArtistService; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor @@ -62,4 +62,14 @@ public ArtistDetailsRes getArtist( ) { return artistService.getArtistDetails(jwtUser.getId()); } + + @GetMapping("/v1/artists") + public ResponseEntity getArtistsByPage( + @RequestParam("query") String query, + @RequestParam(name = "size", required = false, defaultValue = "20") int size, + @RequestParam("page") int page + ) { + var pageable = PageRequest.of(page, size); + return ResponseEntity.ok(artistService.getArtistsByPage(query, pageable)); + } } From aff8acfc266f2811dc13e7e871f261b36687fa04 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 13:22:50 +0900 Subject: [PATCH 28/42] =?UTF-8?q?#27=20feat(user.dto):=20=EC=9E=91?= =?UTF-8?q?=EA=B0=80=20=EA=B2=80=EC=83=89=20=ED=8E=98=EC=9D=B4=EC=A7=95=20?= =?UTF-8?q?DTO=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/dto/ArtistInfoPage.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/user/dto/ArtistInfoPage.java diff --git a/src/main/java/com/helpmeCookies/user/dto/ArtistInfoPage.java b/src/main/java/com/helpmeCookies/user/dto/ArtistInfoPage.java new file mode 100644 index 0000000..725fb2e --- /dev/null +++ b/src/main/java/com/helpmeCookies/user/dto/ArtistInfoPage.java @@ -0,0 +1,46 @@ +package com.helpmeCookies.user.dto; + +import com.helpmeCookies.user.repository.dto.ArtistSearch; +import java.util.List; +import org.springframework.data.domain.Page; + +public class ArtistInfoPage { + + public record Info( + Long id, + String nickname, + String artistImageUrl, + Long totalFollowers, + Long totalLikes + ) { + + private static Info from(ArtistSearch artistSearch) { + return new Info( + artistSearch.getId(), + artistSearch.getNickname(), + artistSearch.getArtistImageUrl(), + artistSearch.getTotalFollowers(), + artistSearch.getTotalLikes() + ); + } + + public static List of(List content) { + return content.stream() + .map(Info::from) + .toList(); + } + } + + public record Paging ( + boolean hasNext, + List artists + ) { + public static Paging from(Page artistPage) { + return new Paging( + artistPage.hasNext(), + Info.of(artistPage.getContent()) + ); + } + } + +} From 285c4ce4130b4185681e3a15f36203c8edc8a1a3 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 13:23:07 +0900 Subject: [PATCH 29/42] =?UTF-8?q?#27=20docs(user):=20=EC=9E=91=EA=B0=80=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20API=20=EB=AC=B8=EC=84=9C=EC=97=90=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 --- .../controller/apiDocs/ArtistApiDocs.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java b/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java index 3f77c43..254c5b7 100644 --- a/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java +++ b/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java @@ -1,19 +1,19 @@ package com.helpmeCookies.user.controller.apiDocs; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -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 com.helpmeCookies.global.jwt.JwtUser; +import com.helpmeCookies.user.dto.ArtistInfoPage.Paging; import com.helpmeCookies.user.dto.request.BusinessArtistReq; import com.helpmeCookies.user.dto.request.StudentArtistReq; import com.helpmeCookies.user.dto.response.ArtistDetailsRes; - import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +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; @Tag(name = "작가 관련 기능", description = "작가 관련 API") public interface ArtistApiDocs { @@ -44,4 +44,11 @@ ArtistDetailsRes getArtist( ArtistDetailsRes getArtist( @AuthenticationPrincipal JwtUser jwtUser ); + + @Operation(summary = "작가 검색") + ResponseEntity getArtistsByPage( + String query, + @Parameter(description = "default value 20") int size, + int page + ); } From 425881a950b1eda7e25e86aa2f70ac6ee5ba242c Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 13:37:01 +0900 Subject: [PATCH 30/42] =?UTF-8?q?#27=20test(user):=20=EC=9E=91=EA=B0=80=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../search/SearchControllerTest.java | 42 +++++++++++++++- .../search/SearchRepositoryTest.java | 31 +++++++++++- .../search/SearchServiceTest.java | 49 +++++++++++++++++-- 3 files changed, 114 insertions(+), 8 deletions(-) rename src/test/java/com/helpmeCookies/{product => }/search/SearchControllerTest.java (64%) rename src/test/java/com/helpmeCookies/{product => }/search/SearchRepositoryTest.java (68%) rename src/test/java/com/helpmeCookies/{product => }/search/SearchServiceTest.java (51%) diff --git a/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java b/src/test/java/com/helpmeCookies/search/SearchControllerTest.java similarity index 64% rename from src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java rename to src/test/java/com/helpmeCookies/search/SearchControllerTest.java index 4566fe1..f212587 100644 --- a/src/test/java/com/helpmeCookies/product/search/SearchControllerTest.java +++ b/src/test/java/com/helpmeCookies/search/SearchControllerTest.java @@ -1,4 +1,4 @@ -package com.helpmeCookies.product.search; +package com.helpmeCookies.search; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -15,6 +15,10 @@ import com.helpmeCookies.product.service.ProductImageService; import com.helpmeCookies.product.service.ProductService; import com.helpmeCookies.product.util.ProductSort; +import com.helpmeCookies.user.controller.ArtistController; +import com.helpmeCookies.user.dto.ArtistInfoPage; +import com.helpmeCookies.user.repository.dto.ArtistSearch; +import com.helpmeCookies.user.service.ArtistService; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -27,7 +31,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.test.web.servlet.MockMvc; -@WebMvcTest(ProductController.class) +@WebMvcTest({ProductController.class, ArtistController.class}) @AutoConfigureMockMvc(addFilters = false) @Import(JwtProvider.class) public class SearchControllerTest { @@ -41,6 +45,9 @@ public class SearchControllerTest { @MockBean private ProductImageService productImageService; + @MockBean + private ArtistService artistService; + @Test @DisplayName("상품 검색 컨트롤러") @@ -75,4 +82,35 @@ public class SearchControllerTest { .andExpect(jsonPath("$.products[0].thumbnailUrl").value("thumbnailUrl")); } + @Test + @DisplayName("작가 검색 컨트롤러") + void 작가_검색() throws Exception { + // given + String query = "nickname"; + int size = 10; + int page = 0; + + var artistSearch = mock(ArtistSearch.class); + given(artistSearch.getId()).willReturn(1L); + given(artistSearch.getNickname()).willReturn("nickname"); + given(artistSearch.getArtistImageUrl()).willReturn("artistImageUrl"); + given(artistSearch.getTotalFollowers()).willReturn(10000L); + given(artistSearch.getTotalLikes()).willReturn(10000L); + var paging = ArtistInfoPage.Paging.from(new PageImpl<>(List.of(artistSearch))); + given(artistService.getArtistsByPage(eq(query), any(Pageable.class))) + .willReturn(paging); + + // when & then + mvc.perform(get("/v1/artists") + .param("query", query) + .param("size", String.valueOf(size)) + .param("page", String.valueOf(page))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.hasNext").value(false)) + .andExpect(jsonPath("$.artists[0].nickname").value("nickname")) + .andExpect(jsonPath("$.artists[0].artistImageUrl").value("artistImageUrl")) + .andExpect(jsonPath("$.artists[0].totalFollowers").value(10000L)) + .andExpect(jsonPath("$.artists[0].totalLikes").value(10000L)); + } + } diff --git a/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java b/src/test/java/com/helpmeCookies/search/SearchRepositoryTest.java similarity index 68% rename from src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java rename to src/test/java/com/helpmeCookies/search/SearchRepositoryTest.java index e914d94..9b00725 100644 --- a/src/test/java/com/helpmeCookies/product/search/SearchRepositoryTest.java +++ b/src/test/java/com/helpmeCookies/search/SearchRepositoryTest.java @@ -1,4 +1,4 @@ -package com.helpmeCookies.product.search; +package com.helpmeCookies.search; import static com.helpmeCookies.product.util.SortUtil.convertProductSort; import static org.assertj.core.api.Assertions.assertThat; @@ -6,6 +6,7 @@ import com.helpmeCookies.global.config.QueryDSLConfig; import com.helpmeCookies.product.repository.ProductRepository; import com.helpmeCookies.product.util.ProductSort; +import com.helpmeCookies.user.repository.ArtistInfoRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -24,6 +25,9 @@ public class SearchRepositoryTest { @Autowired private ProductRepository productRepository; + @Autowired + private ArtistInfoRepository artistInfoRepository; + @Test @DisplayName("상품 검색 쿼리 확인") @@ -52,4 +56,29 @@ public class SearchRepositoryTest { .contains("order by p.created_date desc"); //.contains("limit ?") 테스트 dbh2 db에서는 limit이 없어서 제외 } + + @Test + @DisplayName("작가 검색 쿼리 확인") + void 작가_검색(CapturedOutput out) { + // given + var pageRequest = PageRequest.of(0, 10); + + // when + try{ + artistInfoRepository.findByNicknameWithIdx("nickname", pageRequest); + } catch (Exception ignored) { + } + + // then + assertThat(out.getOut()) + .contains("SELECT") + .contains("a.id,") + .contains("a.nickname,") + .contains("a.artist_image_url,") + .contains("a.total_followers,") + .contains("a.total_likes") + .contains("FROM artist_info a") + .contains("WHERE MATCH(a.nickname) AGAINST (? IN BOOLEAN MODE)"); + } + } diff --git a/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java b/src/test/java/com/helpmeCookies/search/SearchServiceTest.java similarity index 51% rename from src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java rename to src/test/java/com/helpmeCookies/search/SearchServiceTest.java index a13d83d..4a9b738 100644 --- a/src/test/java/com/helpmeCookies/product/search/SearchServiceTest.java +++ b/src/test/java/com/helpmeCookies/search/SearchServiceTest.java @@ -1,4 +1,4 @@ -package com.helpmeCookies.product.search; +package com.helpmeCookies.search; import static com.helpmeCookies.product.util.SortUtil.convertProductSort; import static org.assertj.core.api.Assertions.assertThat; @@ -10,6 +10,9 @@ import com.helpmeCookies.product.repository.dto.ProductSearch; import com.helpmeCookies.product.service.ProductService; import com.helpmeCookies.product.util.ProductSort; +import com.helpmeCookies.user.repository.ArtistInfoRepository; +import com.helpmeCookies.user.repository.dto.ArtistSearch; +import com.helpmeCookies.user.service.ArtistService; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,6 +34,12 @@ public class SearchServiceTest { @InjectMocks private ProductService productService; + @Mock + private ArtistInfoRepository artistInfoRepository; + + @InjectMocks + private ArtistService artistService; + @Test @DisplayName("상품 검색 서비스") void 상품_검색() { @@ -55,10 +64,40 @@ public class SearchServiceTest { assertAll( () -> assertThat(result.hasNext()).isFalse(), () -> assertThat(result.products().size()).isEqualTo(1L), - () -> assertThat(result.products().get(0).name()).isEqualTo("product1"), - () -> assertThat(result.products().get(0).artist()).isEqualTo("artist"), - () -> assertThat(result.products().get(0).price()).isEqualTo(10000L), - () -> assertThat(result.products().get(0).thumbnailUrl()).isEqualTo("thumbnailUrl") + () -> assertThat(result.products().getFirst().name()).isEqualTo("product1"), + () -> assertThat(result.products().getFirst().artist()).isEqualTo("artist"), + () -> assertThat(result.products().getFirst().price()).isEqualTo(10000L), + () -> assertThat(result.products().getFirst().thumbnailUrl()).isEqualTo("thumbnailUrl") + ); + } + + @Test + @DisplayName("작가 검색 서비스") + void 작가_검색() { + // given + var pageRequest = PageRequest.of(0, 10); + var artistSearch = mock(ArtistSearch.class); + given(artistSearch.getId()).willReturn(1L); + given(artistSearch.getNickname()).willReturn("nickname"); + given(artistSearch.getArtistImageUrl()).willReturn("artistImageUrl"); + given(artistSearch.getTotalFollowers()).willReturn(10000L); + given(artistSearch.getTotalLikes()).willReturn(10000L); + + var artistPage = new PageImpl<>(List.of(artistSearch)); + given(artistInfoRepository.findByNicknameWithIdx("nickname", pageRequest)) + .willReturn(artistPage); + + // when + var result = artistService.getArtistsByPage("nickname", pageRequest); + + // then + assertAll( + () -> assertThat(result.hasNext()).isFalse(), + () -> assertThat(result.artists().size()).isEqualTo(1L), + () -> assertThat(result.artists().getFirst().nickname()).isEqualTo("nickname"), + () -> assertThat(result.artists().getFirst().artistImageUrl()).isEqualTo("artistImageUrl"), + () -> assertThat(result.artists().getFirst().totalFollowers()).isEqualTo(10000L), + () -> assertThat(result.artists().getFirst().totalLikes()).isEqualTo(10000L) ); } From 8478defed061f516220aada72d2840893ff8a7f5 Mon Sep 17 00:00:00 2001 From: sim-mer Date: Tue, 29 Oct 2024 13:37:32 +0900 Subject: [PATCH 31/42] =?UTF-8?q?#27=20test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/repository/querydsl/UserCustomRepositoryImpl.java | 4 ++-- src/test/java/com/helpmeCookies/e2e/ArtistE2Etest.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/repository/querydsl/UserCustomRepositoryImpl.java b/src/main/java/com/helpmeCookies/user/repository/querydsl/UserCustomRepositoryImpl.java index bd31f40..2b176f0 100644 --- a/src/main/java/com/helpmeCookies/user/repository/querydsl/UserCustomRepositoryImpl.java +++ b/src/main/java/com/helpmeCookies/user/repository/querydsl/UserCustomRepositoryImpl.java @@ -33,8 +33,8 @@ public Page findFollowingUsers(Long userId, Pageable pageable) .select(Projections.constructor( UserFollowingDto.class, user.id, - user.userInfo.userImageUrl, - user.userInfo.nickname, + user.userImageUrl, + user.nickname, artistInfo.totalFollowers, artistInfo.totalLikes )) diff --git a/src/test/java/com/helpmeCookies/e2e/ArtistE2Etest.java b/src/test/java/com/helpmeCookies/e2e/ArtistE2Etest.java index 6d76c7b..3522fdc 100644 --- a/src/test/java/com/helpmeCookies/e2e/ArtistE2Etest.java +++ b/src/test/java/com/helpmeCookies/e2e/ArtistE2Etest.java @@ -45,7 +45,8 @@ public void testRegisterStudents_withValidToken() throws Exception { StudentArtistReq request = new StudentArtistReq( "student@example.com", "Example University", - "Computer Science" + "Computer Science", + "" ); String requestJson = objectMapper.writeValueAsString(request); From 447a2d4f78cdf1115f5d15cd13b2c84d17677294 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:04:39 +0900 Subject: [PATCH 32/42] chore:[#65]- add Oauth2 Lib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 카카오 로그인을 위한 Oauth2 라이브러리 추가 --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 615d23c..a8dbafa 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.security:spring-security-oauth2-client' // Lombok compileOnly 'org.projectlombok:lombok' From ac75818f06d91860c2cc403764bb8c464f004ab8 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:05:30 +0900 Subject: [PATCH 33/42] feat:[#65]- add Oauth2 login logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 카카오로그인을 위한 로직 추가. /oauth2의 경우 별도의 보안 로직을 가짐 --- .../global/security/WebSecurityConfig.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/helpmeCookies/global/security/WebSecurityConfig.java b/src/main/java/com/helpmeCookies/global/security/WebSecurityConfig.java index c91beed..20b7f52 100644 --- a/src/main/java/com/helpmeCookies/global/security/WebSecurityConfig.java +++ b/src/main/java/com/helpmeCookies/global/security/WebSecurityConfig.java @@ -19,8 +19,6 @@ @Configuration @EnableWebSecurity @RequiredArgsConstructor - - @Controller public class WebSecurityConfig { private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; @@ -29,9 +27,30 @@ public class WebSecurityConfig { @Bean public WebSecurityCustomizer configure() { - return (web) -> web.ignoring() - .requestMatchers("/static/**") - .requestMatchers("/test/**"); + return (web) -> web.ignoring(); + } + + @Bean + public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception { + http + .securityMatcher("/oauth2/**") + .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests((authorize) -> authorize + .requestMatchers("/oauth2/authorization/**", + "/oauth2/code/kakao/**" + ).permitAll() + .anyRequest().authenticated() + ) + .oauth2Login((oauth2) -> oauth2 + .redirectionEndpoint(redirection -> redirection + .baseUri("/oauth2/code/*")) + .userInfoEndpoint((userInfo) -> userInfo + .userService(new Oauth2CustomUserService()) + ) + .defaultSuccessUrl("/oauth2/login/kakao") + ); + + return http.build(); } @Bean @@ -43,7 +62,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((authorize) -> authorize .requestMatchers( - "/login", "/signup", "/", "/user", + "/login", "/signup", "/ttt/*", "/user", "/api/auth/**", "/swagger-ui/**", "/actuator/**", @@ -51,9 +70,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "swagger-ui/**" ).permitAll() .anyRequest().authenticated() - ); - - http.exceptionHandling((exception) -> exception + ).exceptionHandling((exception) -> exception .authenticationEntryPoint(jwtAuthenticationEntryPoint) .accessDeniedHandler(jwtAccessDeniedHandler) ); From 238adf17870a42ae3f8a95fc77ee4d56fa8ee373 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:06:53 +0900 Subject: [PATCH 34/42] refact:[#65]- refact jwt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 전체적인 주석과 간단한 띄어쓰기 변경 --- .../helpmeCookies/global/jwt/JwtProvider.java | 29 ++++++++----------- .../security/JwtAccessDeniedHandler.java | 2 -- .../security/JwtAuthenticationEntryPoint.java | 1 - .../security/JwtAuthenticationFilter.java | 1 - 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/helpmeCookies/global/jwt/JwtProvider.java b/src/main/java/com/helpmeCookies/global/jwt/JwtProvider.java index 7a1e9c2..3fa9c37 100644 --- a/src/main/java/com/helpmeCookies/global/jwt/JwtProvider.java +++ b/src/main/java/com/helpmeCookies/global/jwt/JwtProvider.java @@ -47,15 +47,16 @@ public JwtToken createToken(JwtUser jwtUser) { .build(); } - // 유요한 토큰인지 확인 + /* + 토큰 검증시 rawToken을 Claims로 변환하고, 해당 토큰이 accessToken이면서 만료되어있지 않다면 True를 반환한다. + */ + public boolean validateToken(String rawToken, boolean isAccessToken) { try { - // 엑세스 토큰인지 확인 Claims claims = extractClaims(rawToken); if (claims.get(IS_ACCESS_TOKEN, Boolean.class) != isAccessToken) { return false; } - // 만료시간 확인 return !claims.getExpiration().before(new Date()); } catch (Exception e) { return false; @@ -65,22 +66,24 @@ public boolean validateToken(String rawToken, boolean isAccessToken) { /** * refreshToken을 통해, accessToken을 재발급하는 메서드. * refreshToken의 유효성을 검사하고, isAccessToken이 true일때만 accessToken을 재발급한다. - * TODO: refreshToken을 저장하고, 저장된 refreshToken과 비교하는 로직 필요 + * TODO: refreshToken을 저장하고, 저장된 refreshToken과 비교하는 로직 필요 redis 추가 후 구현 */ public String reissueAccessToken(String refreshToken) { Claims claims = extractClaims(refreshToken); if (claims.get(IS_ACCESS_TOKEN, Boolean.class)) { throw new IllegalArgumentException("리프레시 토큰이 아닙니다."); } + + Date expiration = claims.getExpiration(); + if (expiration.before(new Date())) { + throw new IllegalArgumentException("리프레시 토큰이 만료되었습니다."); + } + JwtUser jwtUser = claimsToJwtUser(claims); return generateToken(jwtUser, true); } - /** - * [validateToken] 이후 호출하는 메서드. - * rawToken을 통해 JwtUser를 추출한다. - * [jwtUser]는 userId와 role을 가지고 있다. 즉 JWT에 저장된 정보를 추출한다. - */ + public JwtUser getJwtUser(String rawToken) { Claims claims = extractClaims(rawToken); return claimsToJwtUser(claims); @@ -91,10 +94,6 @@ private JwtUser claimsToJwtUser(Claims claims) { return JwtUser.of(Long.parseLong(userId)); } - /** - * Jwt 토큰생성 - * accessToken과 refreshToken의 다른점은 만료시간과, isAccessToken이다. - */ private String generateToken(JwtUser jwtUser, boolean isAccessToken) { long expireTime = isAccessToken ? accessTokenExpireTime : refreshTokenExpireTime; Date expireDate = new Date(System.currentTimeMillis() + expireTime); @@ -106,7 +105,6 @@ private String generateToken(JwtUser jwtUser, boolean isAccessToken) { .compact(); } - private Claims extractClaims(String rawToken) { return Jwts.parserBuilder() .setSigningKey(secretKey) @@ -115,9 +113,6 @@ private Claims extractClaims(String rawToken) { .getBody(); } - /** - * HS256방식의 키를 생성한다. - */ @Override public void afterPropertiesSet() { secretKey = new SecretKeySpec(secret.getBytes(), SignatureAlgorithm.HS256.getJcaName()); diff --git a/src/main/java/com/helpmeCookies/global/security/JwtAccessDeniedHandler.java b/src/main/java/com/helpmeCookies/global/security/JwtAccessDeniedHandler.java index f6dde1c..f11567c 100644 --- a/src/main/java/com/helpmeCookies/global/security/JwtAccessDeniedHandler.java +++ b/src/main/java/com/helpmeCookies/global/security/JwtAccessDeniedHandler.java @@ -26,7 +26,5 @@ public class JwtAccessDeniedHandler implements AccessDeniedHandler { public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) { log.error("Token : {}", request.getHeader("Authorization")); - // TODO: 에러코드 추가 - response.setStatus(403); } } \ No newline at end of file diff --git a/src/main/java/com/helpmeCookies/global/security/JwtAuthenticationEntryPoint.java b/src/main/java/com/helpmeCookies/global/security/JwtAuthenticationEntryPoint.java index 2072bb2..2f9a5a8 100644 --- a/src/main/java/com/helpmeCookies/global/security/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/helpmeCookies/global/security/JwtAuthenticationEntryPoint.java @@ -24,6 +24,5 @@ public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { log.debug("Token : {}", request.getHeader("Authorization")); - response.setStatus(401); } } diff --git a/src/main/java/com/helpmeCookies/global/security/JwtAuthenticationFilter.java b/src/main/java/com/helpmeCookies/global/security/JwtAuthenticationFilter.java index 1e70986..4570b65 100644 --- a/src/main/java/com/helpmeCookies/global/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/helpmeCookies/global/security/JwtAuthenticationFilter.java @@ -41,7 +41,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse return; } - // TODO: UserDetailsService를 통해 사용자 정보를 가져와 인증을 진행한다. if (jwtProvider.validateToken(rawToken, true)) { JwtUser jwtUser = jwtProvider.getJwtUser(rawToken); Authentication authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, From 43931c81cde4bfad60b9bc4133c8e90e073743dc Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:07:35 +0900 Subject: [PATCH 35/42] refact:[#65]- refact userupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put 메서드에 맞게 모든 유저 정보를 수정 할 수 있도록 변경 --- .../helpmeCookies/user/dto/UserInfoDto.java | 2 ++ .../{UserInfoReq.java => UserReq.java} | 22 ++++++------------- .../com/helpmeCookies/user/entity/User.java | 8 +++++-- .../user/service/UserService.java | 14 ++++++++++-- 4 files changed, 27 insertions(+), 19 deletions(-) rename src/main/java/com/helpmeCookies/user/dto/request/{UserInfoReq.java => UserReq.java} (56%) diff --git a/src/main/java/com/helpmeCookies/user/dto/UserInfoDto.java b/src/main/java/com/helpmeCookies/user/dto/UserInfoDto.java index ef1bedd..618903a 100644 --- a/src/main/java/com/helpmeCookies/user/dto/UserInfoDto.java +++ b/src/main/java/com/helpmeCookies/user/dto/UserInfoDto.java @@ -6,6 +6,8 @@ import com.helpmeCookies.product.entity.HashTag; import com.helpmeCookies.user.entity.UserInfo; +import lombok.Builder; + public record UserInfoDto( String name, String email, diff --git a/src/main/java/com/helpmeCookies/user/dto/request/UserInfoReq.java b/src/main/java/com/helpmeCookies/user/dto/request/UserReq.java similarity index 56% rename from src/main/java/com/helpmeCookies/user/dto/request/UserInfoReq.java rename to src/main/java/com/helpmeCookies/user/dto/request/UserReq.java index eee632c..ff9055b 100644 --- a/src/main/java/com/helpmeCookies/user/dto/request/UserInfoReq.java +++ b/src/main/java/com/helpmeCookies/user/dto/request/UserReq.java @@ -3,26 +3,18 @@ import java.util.List; import com.helpmeCookies.product.entity.HashTag; +import com.helpmeCookies.user.dto.UserDto; import com.helpmeCookies.user.dto.UserInfoDto; -public record UserInfoReq( +public record UserReq( String name, - String userImageUrl, - String nickname, String email, String birthdate, String phone, String address, - List hashTags + List hashTags, + String userImageUrl, + String nickname ) { - public UserInfoDto toDto() { - return new UserInfoDto( - name, - userImageUrl, - nickname, - email, - birthdate, - hashTags - ); - } -} + +} \ No newline at end of file diff --git a/src/main/java/com/helpmeCookies/user/entity/User.java b/src/main/java/com/helpmeCookies/user/entity/User.java index 1e26b75..2ca3903 100644 --- a/src/main/java/com/helpmeCookies/user/entity/User.java +++ b/src/main/java/com/helpmeCookies/user/entity/User.java @@ -53,9 +53,13 @@ public class User { @Column(nullable = false, updatable = false) protected LocalDateTime createdAt; + public void updateUserCommonInfo(String nickname, String userImageUrl) { + this.nickname = nickname; + this.userImageUrl = userImageUrl; + } + public void updateUserInfo(UserInfo userInfo) { - // TODO: 유저 정보 업데이트시 유효성 검사 - setUserInfo(userInfo); + this.userInfo = userInfo; } private User setUserInfo(UserInfo userInfo) { diff --git a/src/main/java/com/helpmeCookies/user/service/UserService.java b/src/main/java/com/helpmeCookies/user/service/UserService.java index 8bbf410..39abc2a 100644 --- a/src/main/java/com/helpmeCookies/user/service/UserService.java +++ b/src/main/java/com/helpmeCookies/user/service/UserService.java @@ -9,6 +9,7 @@ import com.helpmeCookies.user.dto.UserDto; import com.helpmeCookies.user.dto.UserInfoDto; import com.helpmeCookies.user.dto.UserTypeDto; +import com.helpmeCookies.user.dto.request.UserReq; import com.helpmeCookies.user.dto.response.UserFollowingRes; import com.helpmeCookies.user.entity.ArtistInfo; import com.helpmeCookies.user.entity.Social; @@ -38,12 +39,21 @@ public UserDto getUserInfo(Long userId) { } @Transactional - public UserDto updateUserInfo(UserInfoDto userInfoDto, Long userId) { + public UserDto updateUser(UserReq userReq, Long userId) { User existingUser = userRepository.findById(userId) .orElseThrow(() -> new ResourceNotFoundException("존재하지 않는 유저입니다.")); - existingUser.updateUserInfo(userInfoDto.toEntity()); + existingUser.updateUserCommonInfo(userReq.nickname(), userReq.userImageUrl()); + UserInfo userInfo = UserInfo.builder().name(userReq.name()) + .email(userReq.email()) + .birthdate(userReq.birthdate()) + .phone(userReq.phone()) + .address(userReq.address()) + .hashTags(userReq.hashTags()) + .build(); + + existingUser.updateUserInfo(userInfo); return UserDto.fromEntity(userRepository.save(existingUser)); } From fcbce1572ef1307df997d1127e9689b78637ed19 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:07:51 +0900 Subject: [PATCH 36/42] refact:[#65]- refact userupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Put 메서드에 맞게 모든 유저 정보를 수정 할 수 있도록 변경 --- .../user/controller/UserController.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/controller/UserController.java b/src/main/java/com/helpmeCookies/user/controller/UserController.java index 058fccb..945471d 100644 --- a/src/main/java/com/helpmeCookies/user/controller/UserController.java +++ b/src/main/java/com/helpmeCookies/user/controller/UserController.java @@ -6,7 +6,6 @@ import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -17,16 +16,13 @@ import com.helpmeCookies.global.jwt.JwtUser; import com.helpmeCookies.user.controller.apiDocs.UserApiDocs; -import com.helpmeCookies.user.dto.UserFollowingDto; import com.helpmeCookies.user.dto.response.UserCommonInfoRes; -import com.helpmeCookies.user.dto.request.UserInfoReq; +import com.helpmeCookies.user.dto.request.UserReq; import com.helpmeCookies.user.dto.response.UserDetailsInfoRes; import com.helpmeCookies.user.dto.UserTypeDto; import com.helpmeCookies.user.dto.response.UserFollowingRes; import com.helpmeCookies.user.service.UserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @RestController @@ -57,12 +53,12 @@ public ResponseEntity getUserType( } @PutMapping("/v1/users") - public String updateUserInfo( + public String updateUser( @AuthenticationPrincipal JwtUser jwtUser, - @RequestBody UserInfoReq userInfoReq + @RequestBody UserReq userReq ) { // UserInfoDto를 통해서 유저 정보를 수정한다. - userService.updateUserInfo(userInfoReq.toDto(), jwtUser.getId()); + userService.updateUser(userReq, jwtUser.getId()); return "ok"; } From d9eee4b3722825f3c538dfcd7c0abf96d0aca6aa Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:08:29 +0900 Subject: [PATCH 37/42] feat:[#65]- add kakao login MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 카카오 로그인을 수행하는 로직 추가 --- .../user/controller/LoginController.java | 16 +++++++++++----- .../user/repository/UserRepository.java | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/controller/LoginController.java b/src/main/java/com/helpmeCookies/user/controller/LoginController.java index 35e74ac..69e2d36 100644 --- a/src/main/java/com/helpmeCookies/user/controller/LoginController.java +++ b/src/main/java/com/helpmeCookies/user/controller/LoginController.java @@ -1,9 +1,12 @@ package com.helpmeCookies.user.controller; import java.util.List; +import java.util.Map; +import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -11,10 +14,12 @@ import com.helpmeCookies.global.jwt.JwtProvider; import com.helpmeCookies.global.jwt.JwtToken; import com.helpmeCookies.global.jwt.JwtUser; +import com.helpmeCookies.global.security.UserDetailService; import com.helpmeCookies.product.entity.HashTag; import com.helpmeCookies.user.entity.User; import com.helpmeCookies.user.entity.UserInfo; import com.helpmeCookies.user.repository.UserRepository; +import com.helpmeCookies.user.service.UserService; import lombok.RequiredArgsConstructor; @@ -23,6 +28,7 @@ //Todo: Swagger 추가 public class LoginController { private final UserRepository userRepository; + private final UserDetailService userDetailsService; private final JwtProvider jwtProvider; // 임시 회원가입 url. 유저를 생성하고 jwt 토큰을 반환한다. @@ -47,10 +53,10 @@ public JwtToken signup() { return jwtProvider.createToken(JwtUser.of(user.getId())); } - // 임시 로그인 url. 로그인한 유저의 정보의 일부를 반환한다. - @GetMapping("/login") - public String login(@AuthenticationPrincipal JwtUser jwtUser) { - User user = userRepository.findById(jwtUser.getId()).orElseThrow(); - return user.getUserInfo().getEmail(); + @GetMapping("/oauth2/login/kakao") + public JwtToken ttt(@AuthenticationPrincipal OAuth2User oAuth2User) { + Map attributes = oAuth2User.getAttributes(); + String email = (String) attributes.get("email"); + return jwtProvider.createToken(userDetailsService.loadUserByEmail(email)); } } diff --git a/src/main/java/com/helpmeCookies/user/repository/UserRepository.java b/src/main/java/com/helpmeCookies/user/repository/UserRepository.java index 7aa80d0..b6ce04c 100644 --- a/src/main/java/com/helpmeCookies/user/repository/UserRepository.java +++ b/src/main/java/com/helpmeCookies/user/repository/UserRepository.java @@ -11,4 +11,5 @@ @Repository public interface UserRepository extends JpaRepository, UserCustomRepository { Optional findById(Long id); + Optional findByUserInfoEmail(String email); } From 63e0215a9de77f873496f7a4fca413c1247b4ec5 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:08:51 +0900 Subject: [PATCH 38/42] feat:[#65]- add kakao login MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 카카오 로그인을 수행하는 로직 추가 --- .../security/Oauth2CustomUserService.java | 22 ++++++++++++++ .../global/security/UserDetailService.java | 30 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/main/java/com/helpmeCookies/global/security/Oauth2CustomUserService.java create mode 100644 src/main/java/com/helpmeCookies/global/security/UserDetailService.java diff --git a/src/main/java/com/helpmeCookies/global/security/Oauth2CustomUserService.java b/src/main/java/com/helpmeCookies/global/security/Oauth2CustomUserService.java new file mode 100644 index 0000000..6041900 --- /dev/null +++ b/src/main/java/com/helpmeCookies/global/security/Oauth2CustomUserService.java @@ -0,0 +1,22 @@ +package com.helpmeCookies.global.security; + +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.user.OAuth2User; + +import com.helpmeCookies.user.service.UserService; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class Oauth2CustomUserService implements OAuth2UserService { + + @Override + public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { + final DefaultOAuth2UserService delegate = new DefaultOAuth2UserService(); + OAuth2User oAuth2User = delegate.loadUser(userRequest); + return oAuth2User; + } +} diff --git a/src/main/java/com/helpmeCookies/global/security/UserDetailService.java b/src/main/java/com/helpmeCookies/global/security/UserDetailService.java new file mode 100644 index 0000000..73976a7 --- /dev/null +++ b/src/main/java/com/helpmeCookies/global/security/UserDetailService.java @@ -0,0 +1,30 @@ +package com.helpmeCookies.global.security; + +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import com.helpmeCookies.global.jwt.JwtUser; +import com.helpmeCookies.user.entity.User; +import com.helpmeCookies.user.entity.UserInfo; +import com.helpmeCookies.user.repository.UserRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class UserDetailService { + private final UserRepository userRepository; + + public JwtUser loadUserByEmail(String email) throws UsernameNotFoundException { + // 만약 유저가 존재하지 않는다면 저장 + User user = userRepository.findByUserInfoEmail(email) + .orElseGet(() -> { + User newUser = User.builder() + .userInfo(UserInfo.builder().email(email).build()) + .build(); + return userRepository.save(newUser); + }); + return JwtUser.of(user.getId()); + } +} From 4cbd3a81321625958b210cdebc21b24bcf26b76f Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:35:17 +0900 Subject: [PATCH 39/42] refactor:[#65]- refact swagger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 스웨거 문서 변경 --- .../com/helpmeCookies/user/controller/ArtistController.java | 6 ------ .../user/controller/apiDocs/ArtistApiDocs.java | 5 ++--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/helpmeCookies/user/controller/ArtistController.java b/src/main/java/com/helpmeCookies/user/controller/ArtistController.java index 6e94168..4b00d3b 100644 --- a/src/main/java/com/helpmeCookies/user/controller/ArtistController.java +++ b/src/main/java/com/helpmeCookies/user/controller/ArtistController.java @@ -22,11 +22,9 @@ @RestController @RequiredArgsConstructor -@Tag(name = "작가 관련 기능", description = "작가 관련 API") public class ArtistController implements ArtistApiDocs { private final ArtistService artistService; - @Operation(summary = "학생 작가 등록", description = "학생 작가 등록") @PostMapping("/v1/artists/students") public ResponseEntity registerStudents( @RequestBody StudentArtistReq artistDetailsReq, @@ -36,7 +34,6 @@ public ResponseEntity registerStudents( return ResponseEntity.ok().build(); } - @Operation(summary = "사업자 작가 등록", description = "사업자 작가 등록") @PostMapping("/v1/artists/bussinesses") public ResponseEntity registerbussinsess( @RequestBody BusinessArtistReq businessArtistReq, @@ -46,16 +43,13 @@ public ResponseEntity registerbussinsess( return ResponseEntity.ok().build(); } - @Operation(summary = "작가 프로필 조회", description = "작가 프로필 조회") @GetMapping("/v1/artists/{userId}") public ArtistDetailsRes getArtist( - @AuthenticationPrincipal JwtUser jwtUser, @PathVariable Long userId ) { return artistService.getArtistDetails(userId); } - @Operation(summary = "작가 프로필 조회", description = "자신의 작가 프로필 조회") @GetMapping("/v1/artist") public ArtistDetailsRes getArtist( @AuthenticationPrincipal JwtUser jwtUser diff --git a/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java b/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java index 254c5b7..4df8e2d 100644 --- a/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java +++ b/src/main/java/com/helpmeCookies/user/controller/apiDocs/ArtistApiDocs.java @@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -@Tag(name = "작가 관련 기능", description = "작가 관련 API") +@Tag(name = "작가 관련 기능", description = "작가 관련 API, 작가 프로필 조회 API를 제외한 모든 API는 인증 이후 사용할 수 있습니다.(Authorization: Bearer {token}이 필요합니다.)") public interface ArtistApiDocs { @Operation(summary = "학생 작가 등록", description = "학생 작가 등록") @@ -35,11 +35,10 @@ ResponseEntity registerbussinsess( @Operation(summary = "작가 프로필 조회", description = "작가 프로필 조회") @GetMapping("/v1/artists/{userId}") ArtistDetailsRes getArtist( - @AuthenticationPrincipal JwtUser jwtUser, @PathVariable Long userId ); - @Operation(summary = "작가 프로필 조회", description = "자신의 작가 프로필 조회") + @Operation(summary = "작가 자신의 프로필 조회", description = "작가 자신의 프로필 조회") @GetMapping("/v1/artist") ArtistDetailsRes getArtist( @AuthenticationPrincipal JwtUser jwtUser From b4cc6f48f5753564a91323c55de98990d72ece78 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Fri, 1 Nov 2024 17:35:23 +0900 Subject: [PATCH 40/42] refactor:[#65]- refact swagger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 스웨거 문서 변경 --- .../com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java b/src/main/java/com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java index bfbdde4..1eaff9c 100644 --- a/src/main/java/com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java +++ b/src/main/java/com/helpmeCookies/user/controller/apiDocs/UserApiDocs.java @@ -27,7 +27,7 @@ public interface UserApiDocs { @GetMapping("/v1/users") ResponseEntity getUsers(@AuthenticationPrincipal JwtUser jwtUser); - @Operation(summary = "유저 상세 정보 조회", description = "로그인한 유저의 상세 정보를 조회한다.") + @Operation(summary = "유저 상세 정보 조회", description = "로그인한 유저의 상세 정보를 조회한다. 유저의 모든 정보를 조회 할 수 있다.") @GetMapping("/v1/users/details") ResponseEntity getUserDetails(@AuthenticationPrincipal JwtUser jwtUser); From 88427c8ab80e0b6cc3286af80bdaacf3c9ba45c7 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Sat, 2 Nov 2024 10:04:25 +0900 Subject: [PATCH 41/42] refactor:[#65]- refact jpaAuditing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit config로 이동 --- src/main/java/com/helpmeCookies/Step3Application.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/helpmeCookies/Step3Application.java b/src/main/java/com/helpmeCookies/Step3Application.java index a594415..bc273eb 100644 --- a/src/main/java/com/helpmeCookies/Step3Application.java +++ b/src/main/java/com/helpmeCookies/Step3Application.java @@ -2,10 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication -@EnableJpaAuditing public class Step3Application { public static void main(String[] args) { From 3e7b7661e1cb213fa16bca997e36b984884fb756 Mon Sep 17 00:00:00 2001 From: yooonwodyd Date: Sat, 2 Nov 2024 10:05:37 +0900 Subject: [PATCH 42/42] refactor:[#65]- add ignoring url MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit swagger-ui ignoring 추가 --- .../com/helpmeCookies/global/security/WebSecurityConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/helpmeCookies/global/security/WebSecurityConfig.java b/src/main/java/com/helpmeCookies/global/security/WebSecurityConfig.java index 20b7f52..9ef964e 100644 --- a/src/main/java/com/helpmeCookies/global/security/WebSecurityConfig.java +++ b/src/main/java/com/helpmeCookies/global/security/WebSecurityConfig.java @@ -27,7 +27,9 @@ public class WebSecurityConfig { @Bean public WebSecurityCustomizer configure() { - return (web) -> web.ignoring(); + return (web) -> web.ignoring() + .requestMatchers("/swagger-ui") + .requestMatchers("/static/**"); } @Bean