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

알림 기능 구현 & 키워드 검색 기능 구현 #14

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.trade_ham.domain.auth.controller;

import com.trade_ham.domain.auth.dto.CustomOAuth2User;
import com.trade_ham.domain.auth.dto.UserUpdateDTO;
import com.trade_ham.domain.auth.service.UserService;
import com.trade_ham.global.common.response.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

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

private final UserService userService;

@PostMapping("/user")
public ApiResponse<UserUpdateDTO> updateUser(@RequestBody UserUpdateDTO userUpdateDTO, @AuthenticationPrincipal CustomOAuth2User oAuth2User) {
Long sellerId = oAuth2User.getId();
// ID가 제대로 나오는지 확인
log.info("OAuth2 User ID: {}", oAuth2User.getId());

UserUpdateDTO userResponse = userService.updateUser(sellerId, userUpdateDTO);

return ApiResponse.success(userResponse);
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/trade_ham/domain/auth/dto/UserUpdateDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.trade_ham.domain.auth.dto;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class UserUpdateDTO {
private String account; // 계좌번호
private String realname;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ public class UserEntity {
private List<ProductEntity> purchasedProductEntities = new ArrayList<>();

// 추후 따로 받는다.
private String acount; // 계좌번호
private String account; // 계좌번호
private String realname; // 실제이름

public void updateNickname(String nickname) {
public void updateAccountAndNickname(String account, String nickname) {
this.account = account;
this.nickname = nickname;
}

Expand Down
30 changes: 30 additions & 0 deletions src/main/java/com/trade_ham/domain/auth/service/UserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.trade_ham.domain.auth.service;

import com.trade_ham.domain.auth.dto.UserUpdateDTO;
import com.trade_ham.domain.auth.entity.UserEntity;
import com.trade_ham.domain.auth.repository.UserRepository;
import com.trade_ham.global.common.exception.ErrorCode;
import com.trade_ham.global.common.exception.ResourceNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@RequiredArgsConstructor
public class UserService {

private final UserRepository userRepository;

public UserUpdateDTO updateUser(Long sellerId, UserUpdateDTO userUpdateDTO) {
UserEntity userEntity = userRepository.findById(sellerId)
.orElseThrow(() -> new ResourceNotFoundException(ErrorCode.USER_NOT_FOUND));

userEntity.setAccount(userUpdateDTO.getAccount());
userEntity.setNickname(userUpdateDTO.getRealname());

userRepository.save(userEntity);

return userUpdateDTO;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.trade_ham.domain.locker.controller;

import com.trade_ham.domain.auth.dto.CustomOAuth2User;
import com.trade_ham.domain.locker.entity.NotificationEntity;
import com.trade_ham.domain.locker.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.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()
public ApiResponse<List<NotificationEntity>> allNotification(@AuthenticationPrincipal CustomOAuth2User oAuth2User) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드 네이밍은 보통 동사나 전치사가 앞에 오도록 하면 좋을 것 같아요!
저도 자바 메서드 명명 규칙을 참고하였습니다.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드 네이밍은 보통 동사나 전치사가 앞에 오도록 하면 좋을 것 같아요! 저도 자바 메서드 명명 규칙을 참고하였습니다.

넵 앞으로는 메서드를 작성할 때 메서드 네이밍을 생각하면서 코드를 작성해야겠네요!

Long userId = oAuth2User.getId();

List<NotificationEntity> notifications = notificationService.allNotification(userId);
return ApiResponse.success(notifications);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.trade_ham.domain.locker.dto;

import com.trade_ham.domain.auth.entity.UserEntity;
import jakarta.persistence.Column;
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class NotificationBuyerDTO {
private String message;
private String sellerAccount;
private String sellerRealname;
private boolean isRead;
private UserEntity userId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.trade_ham.domain.locker.dto;

import com.trade_ham.domain.auth.entity.UserEntity;
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class NotificationLockerDTO {
private String message;
private Long lockerId;
private String lockerPassword;
private boolean isRead;
private UserEntity userId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.trade_ham.domain.locker.entity;

import com.trade_ham.domain.auth.entity.UserEntity;
import com.trade_ham.domain.locker.dto.NotificationBuyerDTO;
import com.trade_ham.domain.locker.dto.NotificationLockerDTO;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
public class NotificationEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "notification_id")
private Long id;

//seller
@Column(name = "locker_id")
private Long lockerId;

@Column(name = "locker_password")
private String lockerPassword;

//buyer
@Column(name = "seller_account")
private String sellerAccount;

@Column(name = "seller_realname")
private String sellerRealname;
Comment on lines +27 to +31
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거,, 제 플로우가 잘못되었던건데
밀로랑 얘기를 나눈걸로는 계좌번호랑 실명 구매 페이지시 페이지에서 노출되어 그 자리에서 입금 절차를 거친다고 들었습니다!
그래서 알림으로 보내지 않아도 될 것 같습니다!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거에 맞게 다른 부분도 수정되면 좋을 것 같네요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거에 맞게 다른 부분도 수정되면 좋을 것 같네요!

참고하겠습니다!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞습니다~


// common
private String message;

@Setter
private boolean isRead;

@ManyToOne
@Column(name = "user_id")
private UserEntity userId;

// 판매자 전용 알림
public NotificationEntity(NotificationLockerDTO notificationLockerDTO) {
this.message = notificationLockerDTO.getMessage();
this.lockerId = notificationLockerDTO.getLockerId();
this.lockerPassword = notificationLockerDTO.getLockerPassword();
this.isRead = notificationLockerDTO.isRead();
this.userId = notificationLockerDTO.getUserId();
}

// 구매자 전용 알림
public NotificationEntity(NotificationBuyerDTO NotificationBuyerDTO) {
this.message = NotificationBuyerDTO.getMessage();
this.sellerAccount = NotificationBuyerDTO.getSellerAccount();
this.sellerRealname = NotificationBuyerDTO.getSellerRealname();
this.isRead = NotificationBuyerDTO.isRead();
this.userId = NotificationBuyerDTO.getUserId();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

판매자 전용 알림, 구매자 전용 알림보다 더 좋은 구성이 있을 것 같습니다!

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.trade_ham.domain.locker.repository;

import com.trade_ham.domain.auth.entity.UserEntity;
import com.trade_ham.domain.locker.dto.NotificationResponseDTO;
import com.trade_ham.domain.locker.entity.NotificationEntity;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface NotificationRepository extends JpaRepository<NotificationEntity, Long> {
List<NotificationEntity> findByUserIdAndIsReadTrue(Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.trade_ham.domain.locker.service;

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

import java.util.List;

@Service
@RequiredArgsConstructor
public class NotificationService {

private final NotificationRepository notificationRepository;

@Transactional
public List<NotificationEntity> allNotification(Long userId) {
List<NotificationEntity> notifications = notificationRepository.findByUserIdAndIsReadTrue(userId);

for(NotificationEntity notificationEntity : notifications) {
notificationEntity.setRead(false);
}
Comment on lines +19 to +24
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

알림을 읽지 않은 것(false)을 읽었다(true)로 바꾸는 게 좋을 것 같아요!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

알림을 읽지 않은 것(false)을 읽었다(true)로 바꾸는 게 좋을 것 같아요!

넵!


return notificationRepository.saveAll(notifications);
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
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.*;


Expand All @@ -17,15 +19,16 @@ public class PurchaseProductController {
private final PurchaseProductService productService;

@GetMapping("/product/purchase-page/{productId}")
public ApiResponse<String> accessPurchasePage(@PathVariable Long productId) {
public ApiResponse<String> accessPurchasePage(@PathVariable Long productId, @AuthenticationPrincipal CustomOAuth2User oAuth2User) {
Long buyerId = oAuth2User.getId();
ProductEntity productEntity = productService.findProductById(productId);

// 상태가 SELL이 아니라면 예외 발생
if (!productEntity.getStatus().equals(ProductStatus.SELL)) {
throw new AccessDeniedException(ErrorCode.ACCESS_DENIED);
}
Comment on lines 24 to 29
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비지니스 로직 부분은 service단으로 넘겨도 좋을 거 같아요!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findProductById의 경우 purchaseProduct 에서 비관적 락으로 Id를 찾더라구요 없어도 될 것 같아요

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findProductById의 경우 purchaseProduct 에서 비관적 락으로 Id를 찾더라구요 없어도 될 것 같아요

코드가 중복되는군요 좋은 코멘트 감사합니다!


productService.purchaseProduct(productId);
productService.purchaseProduct(productId, buyerId);

// 상태가 SELL이면 구매 페이지에 접근 가능
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
@RequiredArgsConstructor
@RequestMapping("/api/v1")
public class SearchProductController {

private final SearchProductService searchProductService;

@GetMapping("/search")
public ApiResponse<List<ProductEntity>> searchSellProduct(@RequestParam String keyword) {
List<ProductEntity> productEntities = searchProductService.searchSellProduct(keyword);

return ApiResponse.success(productEntities);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ public class AlbumEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long albumId;

@ManyToOne
@JoinColumn(name = "product_id")
private ProductEntity productEntity;

private String imageUrl;
private Double fileSize;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.trade_ham.domain.auth.entity.UserEntity;
import com.trade_ham.domain.locker.entity.LockerEntity;
import com.trade_ham.global.common.BaseEntity;
import jakarta.persistence.*;
import lombok.*;

Expand All @@ -10,10 +11,11 @@
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProductEntity {
public class ProductEntity extends BaseEntity {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿굿

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

@ManyToOne
@JoinColumn(name = "seller_id")
private UserEntity seller;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public interface ProductRepository extends JpaRepository<ProductEntity, Long> {
List<ProductEntity> findBySeller(UserEntity seller);
List<ProductEntity> findByBuyer(UserEntity buyer);
List<ProductEntity> findByStatusOrderByCreatedAtDesc(ProductStatus status);
@Query("SELECT p FROM ProductEntity p WHERE p.status = ProductStatus.SELL AND p.name LIKE %:keyword%")
List<ProductEntity> findByKeywordContainingAndStatusIsSell(@Param("keyword") String keyword);

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT p FROM ProductEntity p WHERE p.productId = :productId")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
import com.trade_ham.domain.product.entity.TradeEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TradeRepository extends JpaRepository<TradeEntity, Long> {}
import java.util.Optional;

public interface TradeRepository extends JpaRepository<TradeEntity, Long> {
Optional<TradeEntity> findByProductEntityId(Long productId);
}
Loading