Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

소셜 기능 (찜하기, 조회수) 구현 #19

Open
wants to merge 8 commits into
base: roki/social
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class LockerEntity {
@Column(name = "locker_number", nullable = false, length = 50)
private String lockerNumber;

@Setter
@Column(name = "locker_password", length = 50)
private String lockerPassword;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,13 @@ public ApiResponse<List<ProductEntity>> findProductsByBuyer(@AuthenticationPrinc

return ApiResponse.success(productEntities);
}

// 내가 좋아요한 상품 조회
@GetMapping("likes")
public ApiResponse<List<ProductResponseDTO>> findLikedProducts(@AuthenticationPrincipal CustomOAuth2User oAuth2User) {
Long userId = oAuth2User.getId();
List<ProductResponseDTO> likedProducts = myPageService.findLikedProducts(userId);

return ApiResponse.success(likedProducts);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@

import com.trade_ham.domain.auth.entity.UserEntity;
import com.trade_ham.domain.auth.repository.UserRepository;
import com.trade_ham.domain.product.entity.LikeEntity;
import com.trade_ham.domain.product.entity.ProductEntity;
import com.trade_ham.domain.product.dto.ProductResponseDTO;
import com.trade_ham.domain.product.repository.LikeRepository;
import com.trade_ham.domain.product.repository.ProductRepository;
import com.trade_ham.global.common.exception.ErrorCode;
import com.trade_ham.global.common.exception.ResourceNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -20,6 +23,7 @@ public class MyPageService {

private final UserRepository userRepository;
private final ProductRepository productRepository;
private final LikeRepository likeRepository;

// 구매자 구매 내역 관리
public List<ProductEntity> findProductsByBuyer(Long buyerId) {
Expand All @@ -38,4 +42,16 @@ public List<ProductResponseDTO> findProductsBySeller(Long sellerId) {
.map(ProductResponseDTO::new)
.collect(Collectors.toList());
}

/**
* 사용자가 좋아요한 상품 목록 조회
*/
@Transactional(readOnly = true)
public List<ProductResponseDTO> findLikedProducts(Long userId) {
// 좋아요 정보를 통해 상품 목록 조회
List<LikeEntity> likes = likeRepository.findByUserId(userId);
return likes.stream()
.map(like -> new ProductResponseDTO(like.getProduct()))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.trade_ham.domain.notifiaction.controller;

import com.trade_ham.domain.auth.dto.CustomOAuth2User;
import com.trade_ham.domain.notifiaction.dto.LockerNotificationDTO;
import com.trade_ham.domain.notifiaction.service.NotificationService;
import com.trade_ham.global.common.response.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/notification")
public class NotificationController {

private final NotificationService notificationService;

@GetMapping("/all")
ApiResponse<List<LockerNotificationDTO>> getMyNotifications(@AuthenticationPrincipal CustomOAuth2User oAuth2User) {
return ApiResponse.success(notificationService.getMyNotifications(oAuth2User.getId()));
}

@PostMapping("/readCheck")
ApiResponse<String> checkReadNotification(@AuthenticationPrincipal CustomOAuth2User oAuth2User) {
notificationService.checkReadNotification(oAuth2User.getId());
return ApiResponse.success("알림을 확인 후 닫습니다.");
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.trade_ham.domain.notifiaction.dto;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class LockerNotificationDTO {
private final String lockerId;
private final String lockerPassword;
private final boolean isRead;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.trade_ham.domain.notifiaction.entity;

import com.trade_ham.domain.auth.entity.UserEntity;
import jakarta.persistence.*;
import lombok.Setter;

@Entity
public class NotificationEntity {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
private UserEntity user;

private String message;
private String lockerId;
private String lockerPassword;

@Setter
private boolean isRead;

private NotificationEntity(UserEntity user, String message, String lockerId, String lockerPassword) {
this.user = user;
this.message = message;
this.lockerId = lockerId;
this.lockerPassword = lockerPassword;
this.isRead = true;
}

public NotificationEntity() {

}

public static NotificationEntity createNotification(UserEntity user, String message, String lockerId, String lockerPassword) {
return new NotificationEntity(user, message, lockerId, lockerPassword);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.trade_ham.domain.notifiaction.repository;

import com.trade_ham.domain.notifiaction.dto.LockerNotificationDTO;
import com.trade_ham.domain.notifiaction.entity.NotificationEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface NotificationRepository extends JpaRepository<NotificationEntity, Long> {
List<LockerNotificationDTO> findByUserId(Long userId);
List<NotificationEntity> findByUserIdAndIsReadFalse(Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.trade_ham.domain.notifiaction.service;

import com.trade_ham.domain.notifiaction.dto.LockerNotificationDTO;
import com.trade_ham.domain.notifiaction.entity.NotificationEntity;
import com.trade_ham.domain.notifiaction.repository.NotificationRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;

@Service
@RequiredArgsConstructor
public class NotificationService {

private final NotificationRepository notificationRepository;

public List<LockerNotificationDTO> getMyNotifications(Long userId) {
List<LockerNotificationDTO> notifications = notificationRepository.findByUserId(userId);
if (notifications == null || notifications.isEmpty()) {
return Collections.emptyList();
}
return notifications;
}

@Transactional
public List<NotificationEntity> checkReadNotification(Long userId) {
List<NotificationEntity> notifications = notificationRepository.findByUserIdAndIsReadFalse(userId);
if (notifications == null || notifications.isEmpty()) {
return Collections.emptyList();
}
notifications.forEach(notification -> notification.setRead(true));
return notificationRepository.saveAll(notifications);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.trade_ham.domain.product.controller;

import com.trade_ham.domain.auth.dto.CustomOAuth2User;
import com.trade_ham.domain.product.service.LikeProductService;
import com.trade_ham.global.common.response.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1/products/{productId}/like")
@RequiredArgsConstructor
public class LikeProductController {

private final LikeProductService likeProductService;

@PostMapping("")
public ApiResponse<String> likeProduct(@PathVariable Long productId, @AuthenticationPrincipal CustomOAuth2User oAuth2User) {
likeProductService.likeProduct(productId, oAuth2User.getId());
return ApiResponse.success("좋아요가 추가되었습니다.");
}

@DeleteMapping("")
public ApiResponse<String> unlikeProduct(@PathVariable Long productId, @AuthenticationPrincipal CustomOAuth2User oAuth2User) {
likeProductService.unlikeProduct(productId, oAuth2User.getId());
return ApiResponse.success("좋아요가 삭제되었습니다.");
}

@GetMapping("/count")
public ApiResponse<Integer> getLikeCount(@PathVariable Long productId) {
int likeCount = likeProductService.getLikeCount(productId);
return ApiResponse.success(likeCount);
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,46 @@
package com.trade_ham.domain.product.controller;

import com.trade_ham.domain.auth.dto.CustomOAuth2User;
import com.trade_ham.domain.product.entity.ProductEntity;
import com.trade_ham.domain.product.entity.ProductStatus;
import com.trade_ham.domain.product.service.PurchaseProductService;
import com.trade_ham.global.common.exception.AccessDeniedException;
import com.trade_ham.global.common.exception.ErrorCode;
import com.trade_ham.global.common.response.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;


@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
@RequestMapping("/api/v1/product")
public class PurchaseProductController {
private final PurchaseProductService productService;

@GetMapping("/product/purchase-page/{productId}")
@GetMapping("/purchase-page/{productId}")
public ApiResponse<String> accessPurchasePage(@PathVariable Long productId) {
ProductEntity productEntity = productService.findProductById(productId);
productService.purchaseProduct(productId);
return ApiResponse.success("구매 페이지에 접근 가능합니다.");
}

// 상태가 SELL이 아니라면 예외 발생
if (!productEntity.getStatus().equals(ProductStatus.SELL)) {
throw new AccessDeniedException(ErrorCode.ACCESS_DENIED);
}
@PostMapping("/purchase/{product_id}")
public ApiResponse<String> completePurchase(@PathVariable Long product_id, @AuthenticationPrincipal CustomOAuth2User oAuth2User) {
Long buyerId = oAuth2User.getId();
productService.completePurchase(product_id, buyerId);
return ApiResponse.success("구매를 완료하였습니다.");
}

productService.purchaseProduct(productId);
@PostMapping("/locker-in/{product_id}")
public ApiResponse<String> storeInLocker(@PathVariable Long product_id) {
productService.storeInLocker(product_id);
return ApiResponse.success("물건을 사물함에 넣었습니다.");
}

// 상태가 SELL이면 구매 페이지에 접근 가능
return ApiResponse.success("구매 페이지에 접근 가능합니다.");
@PostMapping("/take-out/{product_id}")
public ApiResponse<String> markAsReceived(@PathVariable Long product_id) {
productService.markAsReceived(product_id);
return ApiResponse.success("물건을 수령하였습니다.");
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.trade_ham.domain.product.controller;


import com.trade_ham.domain.product.entity.ProductEntity;
import com.trade_ham.domain.product.service.SearchProductService;
import com.trade_ham.global.common.response.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/v1")
@RequiredArgsConstructor
public class SearchProductController {

private final SearchProductService searchProductService;

@GetMapping("/products/search")
public ApiResponse<List<ProductEntity>> searchProducts(@RequestParam String keyword) {
List<ProductEntity> products = searchProductService.searchProducts(keyword);
return ApiResponse.success(products);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.trade_ham.domain.product.controller;

import com.trade_ham.domain.auth.dto.CustomOAuth2User;
import com.trade_ham.domain.product.service.ViewProductService;
import com.trade_ham.global.common.response.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/products/{productId}/views")
public class ViewProductController {

private final ViewProductService viewProductService;

@PostMapping
public ApiResponse<String> incrementViewCount(@PathVariable Long productId, @AuthenticationPrincipal CustomOAuth2User oAuth2User) {
viewProductService.incrementViewCount(productId, oAuth2User.getId());
return ApiResponse.success("조회수가 증가했습니다.");
}

@GetMapping
public ApiResponse<Integer> getViewCount(@PathVariable Long productId) {
int viewCount = viewProductService.getViewCount(productId);
return ApiResponse.success(viewCount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ public ProductResponseDTO(ProductEntity productEntity) {
this.price = productEntity.getPrice();
this.status = productEntity.getStatus();
}

}
36 changes: 36 additions & 0 deletions src/main/java/com/trade_ham/domain/product/entity/LikeEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.trade_ham.domain.product.entity;

import com.trade_ham.domain.auth.entity.UserEntity;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@Table(
name = "likes",
uniqueConstraints = @UniqueConstraint(columnNames = {"user_id", "product_id"})
)
public class LikeEntity {

@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private UserEntity user;

@ManyToOne
@JoinColumn(name = "product_id", nullable = false)
private ProductEntity product;

private LikeEntity(UserEntity user, ProductEntity product) {
this.user = user;
this.product = product;
}

public static LikeEntity of (UserEntity user, ProductEntity product) {
return new LikeEntity(user, product);
}
}
Loading