Skip to content

Commit

Permalink
Merge pull request #174 from Troth-Cam/feat/transaction
Browse files Browse the repository at this point in the history
feat(#125) : 메인화면 페이징 처리 & 거래하기 api 구현 & 에러코드 수정
  • Loading branch information
yeon015 authored Aug 20, 2023
2 parents cb8eb85 + 82329d8 commit 392b135
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
package trothly.trothcam.controller.web;

import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import trothly.trothcam.domain.member.Member;
import trothly.trothcam.dto.web.HistoryResDto;
import trothly.trothcam.dto.web.TransactionReqDto;
import trothly.trothcam.exception.base.BaseResponse;
import trothly.trothcam.exception.custom.BadRequestException;
import trothly.trothcam.service.web.HistoryService;

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/history")
public class HistoryController {

private final HistoryService historyService;

@PostMapping("/transaction")
public BaseResponse<HistoryResDto> saveHistory(@RequestBody TransactionReqDto req, @AuthenticationPrincipal Member member) {
if(req.getProductId() == null) {
throw new BadRequestException("존재하지 않는 상품 아이디 입니다.");
}

HistoryResDto res = historyService.saveTransaction(req, member);
return BaseResponse.onSuccess(res);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;
import trothly.trothcam.domain.member.Member;
import trothly.trothcam.dto.web.ProductDetailResDto;
import trothly.trothcam.dto.web.ProductRankResDto;
import trothly.trothcam.dto.web.ProductReqDto;
import trothly.trothcam.dto.web.ProductsResDto;
import trothly.trothcam.dto.web.*;
import trothly.trothcam.exception.base.BaseException;
import trothly.trothcam.exception.base.BaseResponse;
import trothly.trothcam.exception.base.ErrorCode;
Expand Down Expand Up @@ -86,6 +83,19 @@ public BaseResponse<List<ProductRankResDto>> findRanking(@PathVariable String ty
return BaseResponse.onSuccess(result);
}

/* 메인 화면 페이징 처리 */
@GetMapping("/product-ranking/{type}/{page}")
public BaseResponse<ProductsPagingListResDto> getProducts(@PathVariable String type, @PathVariable int page) {
if(type.equals("top") && page >= 0) {
return BaseResponse.onSuccess(productService.getProductsTop(page));
} else if (type.equals("latest") && page >= 0) {
return BaseResponse.onSuccess(productService.getProductsLatest(page));
} else {
throw new BaseException(REQUEST_ERROR);
}

}

/* view all */
@GetMapping("/view-all/{type}")
public BaseResponse<List<ProductRankResDto>> findViewAll(@PathVariable String type) {
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/trothly/trothcam/domain/history/History.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,10 @@ public class History {
@Column(name = "sold_at", updatable = false, nullable = false)
private LocalDateTime soldAt;

public History(Product product, Member seller, Member buyer, Long price) {
this.product = product;
this.seller = seller;
this.buyer = buyer;
this.price = price;
}
}
3 changes: 3 additions & 0 deletions src/main/java/trothly/trothcam/domain/product/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ public void updatePublicYn(PublicYn publicYn) {
this.publicYn = publicYn;
}

public void updateOwner(Member owner) {
this.member = owner;
}
public void updateInfo(PublicResDto publicResDto) {
this.price = publicResDto.getPrice();
this.description = publicResDto.getDescription();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package trothly.trothcam.domain.product;

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.stereotype.Repository;
Expand Down Expand Up @@ -39,6 +41,17 @@ public interface ProductRepository extends JpaRepository<Product, Long> {
"from history h join product p on h.product_id = p.product_id order by sold_at desc LIMIT 30", nativeQuery = true)
List<ProductTop> findRankLatestViewAllDto();

//페이징 처리
@Query(value = "select ap.history_id as historyId, ap.product_id as productId, ap.seller_id as sellerId, ap.buyer_id as buyerId, ap.price as price, ap.sold_at as soldAt, p.image_id as imageId, p.title as title, p.tags as tags\n" +
"from (select *, rank() over (partition by h.product_id order by price desc, sold_at asc) as rk from history h) as ap join product p on ap.product_id = p.product_id\n" +
"where ap.rk <= 1\n" +
"order by price desc, sold_at asc", nativeQuery = true, countQuery = "select count(*) from (select *, rank() over (partition by h.product_id order by h.price desc, sold_at asc) as rk from history h) as ap " +
"join product p on ap.product_id = p.product_id where ap.rk <= 1 group by ap.price, sold_at order by ap.price desc, sold_at asc")
Page<ProductTop> findRankPagingDto(Pageable pageable);

@Query(value = "select h.history_id as historyId, h.product_id as productId, h.seller_id as sellerId, h.buyer_id as buyerId, h.price as price, h.sold_at as soldAt, p.image_id as imageId, p.title as title, p.tags as tags \n" +
"from history h join product p on h.product_id = p.product_id order by sold_at desc", nativeQuery = true)
Page<ProductTop> findLatestPagingDto(Pageable pageable);

// 비공개 인증서 리스트 조회
List<Product> findAllByMemberAndPublicYn(Member member, PublicYn publicYn);
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/trothly/trothcam/dto/web/HistoryResDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package trothly.trothcam.dto.web;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class HistoryResDto {
private Long historyId;
private Long productId;
private Long buyerId;
private Long sellerId;
private Long price;
private LocalDateTime soldAt;
private Long newOwnerId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package trothly.trothcam.dto.web;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class ProductsPagingListResDto {
private List<ProductRankResDto> getProductRankResDto;
private int totalPages;
}
14 changes: 14 additions & 0 deletions src/main/java/trothly/trothcam/dto/web/TransactionReqDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package trothly.trothcam.dto.web;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class TransactionReqDto {
private Long productId;
private Long price;
}
3 changes: 3 additions & 0 deletions src/main/java/trothly/trothcam/exception/base/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public enum ErrorCode { // BaseResponseStatus와 같은 역할
NOT_LIKED(2014, "좋아요를 누르지 않은 상품입니다.", BAD_REQUEST),
HISTORIES_NOT_FOUND(2015, "거래 내역이 존재하지 않습니다.", BAD_REQUEST),
PRODUCT_NOT_FOUND(2016, "인증서가 존재하지 않습니다.", BAD_REQUEST),
SAME_MEMBER(2017, "상품의 소유자와 현재 구매하려고 하는 사용자가 같습니다.", BAD_REQUEST),
PRODUCT_IS_NOT_FOUND(2018, "존재하지 않는 상품입니다.", BAD_REQUEST),
IMAGE_NOT_FOUND(2019, "존재하지 않는 이미지입니다.", BAD_REQUEST),

/**
* 3000 : Response 오류
Expand Down
28 changes: 27 additions & 1 deletion src/main/java/trothly/trothcam/service/web/HistoryService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@
import org.springframework.transaction.annotation.Transactional;
import trothly.trothcam.domain.history.History;
import trothly.trothcam.domain.history.HistoryRepository;
import trothly.trothcam.domain.member.Member;
import trothly.trothcam.domain.member.MemberRepository;
import trothly.trothcam.domain.product.Product;
import trothly.trothcam.domain.product.ProductRepository;
import trothly.trothcam.dto.web.HistoryDto;
import trothly.trothcam.dto.web.HistoryResDto;
import trothly.trothcam.dto.web.ProductReqDto;
import trothly.trothcam.dto.web.TransactionReqDto;
import trothly.trothcam.exception.base.BaseException;
import trothly.trothcam.exception.custom.BadRequestException;

import java.util.ArrayList;
import java.util.List;

import static trothly.trothcam.exception.base.ErrorCode.HISTORIES_NOT_FOUND;
import static trothly.trothcam.exception.base.ErrorCode.*;

@Service
@Transactional
Expand All @@ -22,6 +28,7 @@ public class HistoryService {

private final HistoryRepository historyRepository;
private final ProductRepository productRepository;
private final MemberRepository memberRepository;

// 거래 내역 전체 조회
public List<HistoryDto> findAllHistory(ProductReqDto req) {
Expand All @@ -41,4 +48,23 @@ public List<HistoryDto> findAllHistory(ProductReqDto req) {
}

// 거래 내역 저장
public HistoryResDto saveTransaction(TransactionReqDto req, Member member) {
Product product = productRepository.findById(req.getProductId()).orElseThrow(
() -> new BaseException(PRODUCT_IS_NOT_FOUND)
);

Member seller = memberRepository.findById(product.getMember().getId()).orElseThrow(
() -> new BaseException(MEMBER_NOT_FOUND)
);

if(member.getId() == product.getMember().getId()) {
throw new BaseException(SAME_MEMBER);
}

History newHistory = historyRepository.save(new History(product, seller, member, req.getPrice()));

product.updateOwner(member);

return new HistoryResDto(newHistory.getId(), product.getId(), member.getId(), seller.getId(), req.getPrice(), newHistory.getSoldAt(), member.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@

import java.util.Optional;

import static trothly.trothcam.exception.base.ErrorCode.ALREADY_LIKED;
import static trothly.trothcam.exception.base.ErrorCode.NOT_LIKED;
import static trothly.trothcam.exception.base.ErrorCode.*;

@Service
@Transactional
Expand All @@ -35,7 +34,7 @@ public LikeResDto saveLike(ProductReqDto req, Member member) {
}

Product product = productRepository.findById(req.getProductId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 상품입니다.")
() -> new BaseException(PRODUCT_IS_NOT_FOUND)
);

LikeProduct newLike = likeProductRepository.save(new LikeProduct(product, member));
Expand Down
62 changes: 54 additions & 8 deletions src/main/java/trothly/trothcam/service/web/ProductService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import trothly.trothcam.domain.history.History;
Expand Down Expand Up @@ -29,6 +31,8 @@
import java.util.Optional;
import java.util.stream.Collectors;

import static trothly.trothcam.exception.base.ErrorCode.*;

@Slf4j
@Service
@Transactional(readOnly = true)
Expand Down Expand Up @@ -99,19 +103,19 @@ public ProductDetailResDto findProductDetailOn(ProductReqDto req, Member member)
Boolean liked = false;

Product product = productRepository.findById(req.getProductId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 상품입니다.")
() -> new BaseException(PRODUCT_IS_NOT_FOUND)
);

Image image = imageRepository.findById(product.getImage().getId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 이미지입니다.")
() -> new BaseException(IMAGE_NOT_FOUND)
);

Member findOwner = memberRepository.findById(product.getMember().getId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 회원입니다.")
() -> new BaseException(MEMBER_NOT_FOUND)
);

Member findAuthorship = memberRepository.findById(image.getMember().getId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 회원입니다.")
() -> new BaseException(MEMBER_NOT_FOUND)
);

// 조회수 갱신
Expand Down Expand Up @@ -141,19 +145,19 @@ public ProductDetailResDto findProductDetail(ProductReqDto req) {
Boolean liked = false;

Product product = productRepository.findById(req.getProductId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 상품입니다.")
() -> new BaseException(PRODUCT_IS_NOT_FOUND)
);

Image image = imageRepository.findById(product.getImage().getId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 이미지입니다.")
() -> new BaseException(IMAGE_NOT_FOUND)
);

Member findOwner = memberRepository.findById(product.getMember().getId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 회원입니다.")
() -> new BaseException(MEMBER_NOT_FOUND)
);

Member findAuthorship = memberRepository.findById(image.getMember().getId()).orElseThrow(
() -> new BadRequestException("존재하지 않는 회원입니다.")
() -> new BaseException(MEMBER_NOT_FOUND)
);

// 조회수 갱신
Expand Down Expand Up @@ -214,6 +218,48 @@ public List<ProductRankResDto> findProductRankLatest() {
return latestResDtos;
}

/* 메인 페이징 처리 - top */
@Transactional
public ProductsPagingListResDto getProductsTop(int page) {
try {
PageRequest pageRequest = PageRequest.of(page, 8);
Page<ProductRepository.ProductTop> productTops = productRepository.findRankPagingDto(pageRequest);
List<ProductRankResDto> topPagingDto = productTops.stream()
.map(t -> {
Optional<Member> owner = memberRepository.findById(t.getBuyerId());
Optional<Image> image = imageRepository.findById(t.getImageId());

return new ProductRankResDto(t.getHistoryId(), t.getProductId(), owner.get().getWebToken(), owner.get().getName(),
image.get().getMember().getWebToken(), t.getTitle(), t.getTags(), image.get().getImageUrl(),
t.getPrice(), t.getSoldAt());
}).collect(Collectors.toList());
return new ProductsPagingListResDto(topPagingDto, productTops.getTotalPages());
} catch (Exception e) {
throw new BaseException(ErrorCode.DATABASE_ERROR);
}
}

/* 메인 페이징 처리 - top */
@Transactional
public ProductsPagingListResDto getProductsLatest(int page) {
try {
PageRequest pageRequest = PageRequest.of(page, 8);
Page<ProductRepository.ProductTop> productLatests = productRepository.findLatestPagingDto(pageRequest);
List<ProductRankResDto> latestPagingDto = productLatests.stream()
.map(t -> {
Optional<Member> owner = memberRepository.findById(t.getBuyerId());
Optional<Image> image = imageRepository.findById(t.getImageId());

return new ProductRankResDto(t.getHistoryId(), t.getProductId(), owner.get().getWebToken(), owner.get().getName(),
image.get().getMember().getWebToken(), t.getTitle(), t.getTags(), image.get().getImageUrl(),
t.getPrice(), t.getSoldAt());
}).collect(Collectors.toList());
return new ProductsPagingListResDto(latestPagingDto, productLatests.getTotalPages());
} catch (Exception e) {
throw new BaseException(ErrorCode.DATABASE_ERROR);
}
}

/* view all top 조회 */
@Transactional
public List<ProductRankResDto> findRankViewAllTop() {
Expand Down

0 comments on commit 392b135

Please sign in to comment.