Skip to content

Commit

Permalink
Merge pull request #55 from saessagMarket/feat/#52-count-view-like
Browse files Browse the repository at this point in the history
상품 조회수, 좋아요
  • Loading branch information
JunBe authored Jan 30, 2025
2 parents 89b7c09 + dc7e7d8 commit 8c8d680
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 78 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.market.saessag.domain.photo.controller;

import com.market.saessag.domain.photo.service.S3Service;
import com.market.saessag.global.response.ApiResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
Expand All @@ -21,22 +22,31 @@ public PhotoController(S3Service s3Service) {
}

@PostMapping("/upload")
public ResponseEntity<List<String>> uploadPhotos(@RequestParam MultipartFile[] files) {
public ApiResponse<List<String>> uploadPhotos(@RequestParam MultipartFile[] files) {
List<String> fileUrls = new ArrayList<>();
try {
for (MultipartFile file : files) {
String fileUrl = s3Service.uploadFile(file);
fileUrls.add(fileUrl);
}
return ResponseEntity.ok(fileUrls); //ApiResponse 사용하기
return ApiResponse.<List<String>>builder()
.status("200")
.data(fileUrls)
.build();
} catch (IOException e) {
return ResponseEntity.internalServerError().body(Collections.singletonList("파일 업로드에 실패했습니다." + e.getMessage()));
return ApiResponse.<List<String>>builder()
.status("500")
.data(Collections.singletonList("파일 업로드에 실패했습니다." + e.getMessage()))
.build();
}
}

@GetMapping()
public ResponseEntity<Map<String, String>> getPresignedUrl(@RequestParam List<String> keys) {
public ApiResponse<Map<String, String>> getPresignedUrl(@RequestParam List<String> keys) {
Map<String, String> urls = s3Service.getPresignedUrl(keys);
return ResponseEntity.ok(urls);
return ApiResponse.<Map<String, String>>builder()
.status("200")
.data(urls)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.market.saessag.domain.product.dto.ProductRequest;
import com.market.saessag.domain.product.dto.ProductResponse;
import com.market.saessag.domain.product.service.ProductService;
import com.market.saessag.domain.user.dto.SignInResponse;
import com.market.saessag.global.response.ApiResponse;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
Expand All @@ -18,77 +20,82 @@ public class ProductController {

//통합 조회 (제목, 닉네임, 정렬기준)
@GetMapping()
public ResponseEntity<ApiResponse<Page<ProductResponse>>> searchProducts(
public ApiResponse<Page<ProductResponse>> searchProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String title,
@RequestParam(required = false) String nickname,
@RequestParam(required = false) String sort, //정렬 기준 (price, addedDate 등)
@RequestParam(defaultValue = "desc") String direction) {
Page<ProductResponse> product = productService.searchProducts(page, size, title, nickname, sort, direction);
ApiResponse<Page<ProductResponse>> response = ApiResponse.<Page<ProductResponse>>builder()
return ApiResponse.<Page<ProductResponse>>builder()
.status("200")
.data(product)
.build();

return ResponseEntity.status(HttpStatus.OK).body(response);
}

//상세 조회
@GetMapping("/{productId}")
public ResponseEntity<ApiResponse<ProductResponse>> getProductDetail(@PathVariable Long productId) {
public ApiResponse<ProductResponse> getProductDetail(@PathVariable Long productId,
@SessionAttribute(name = "user", required = false) SignInResponse user) {

ProductResponse productDetail = productService.getProductDetail(productId);
ApiResponse<ProductResponse> response = ApiResponse.<ProductResponse>builder()
if (user != null) {
productService.incrementView(productId, user.getId());
}

return ApiResponse.<ProductResponse>builder()
.status("200")
.data(productDetail)
.build();

return ResponseEntity.status(HttpStatus.OK).body(response);
}

//상품 생성
@PostMapping
public ResponseEntity<ApiResponse<ProductResponse>> createProduct(@RequestBody ProductRequest productRequest) {
public ApiResponse<ProductResponse> createProduct(@RequestBody ProductRequest productRequest) {
ProductResponse createdProduct = productService.createProduct(productRequest);
ApiResponse<ProductResponse> response = ApiResponse.<ProductResponse>builder()
return ApiResponse.<ProductResponse>builder()
.status("201")
.data(createdProduct)
.build();

return ResponseEntity.status(HttpStatus.CREATED).body(response);
}

//상품 수정
@PutMapping("/{productId}")
public ResponseEntity<ApiResponse<ProductResponse>> updateProduct(@PathVariable Long productId,
public ApiResponse<ProductResponse> updateProduct(@PathVariable Long productId,
@RequestBody ProductRequest productRequest) {
ProductResponse updatedProduct = productService.updateProduct(productId, productRequest);
ApiResponse<ProductResponse> response = ApiResponse.<ProductResponse>builder()
return ApiResponse.<ProductResponse>builder()
.status("200")
.data(updatedProduct)
.build();

return ResponseEntity.status(HttpStatus.OK).body(response);
}

//상품 삭제
@DeleteMapping("/{productId}")
public ResponseEntity<ApiResponse> deleteProduct(@PathVariable Long productId) {
public ApiResponse<Void> deleteProduct(@PathVariable Long productId) {
boolean isDeleted = productService.deleteProduct(productId);
if (!isDeleted) {
ApiResponse<Void> response = ApiResponse.<Void>builder()
return ApiResponse.<Void>builder()
.status("404")
.data(null)
.build();

return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
}

ApiResponse<Void> response = ApiResponse.<Void>builder()
return ApiResponse.<Void>builder()
.status("204")
.data(null)
.build();
}

// 상품 좋아요
@PostMapping("/{productId}/like")
public ApiResponse<Void> likeProduct(@PathVariable Long productId, @SessionAttribute(name = "user") SignInResponse user) {
productService.likeProduct(productId, user.getId());

return ResponseEntity.status(HttpStatus.NO_CONTENT).body(response);
return ApiResponse.<Void>builder()
.status("200")
.data(null)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ public class ProductResponse {
private String detailedAddress;
private final String addedDate;
private String status;
private Long like;
private Long view;
private final UserResponse user;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@

import com.market.saessag.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.*;

import java.time.LocalDateTime;
import java.util.List;

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Product {

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

@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
Expand Down Expand Up @@ -50,8 +51,41 @@ public enum ProductStatus {
FOR_SALE, HIDDEN, SOLD_OUT
}

@Column(nullable = false)
private Long views;

@Column(nullable = false)
private Long likes;

@PrePersist
public void prePersist() {
this.addedDate = LocalDateTime.now(); // 현재 시간 자동 설정
this.views = 0L;
this.likes = 0L;
}

public void updateProduct(String title, Long price, String description, List<String> photo,
Double latitude, Double longitude, String basicAddress, String detailedAddress, ProductStatus status) {
this.title = title;
this.price = price;
this.description = description;
this.photo = photo;
this.latitude = latitude;
this.longitude = longitude;
this.basicAddress = basicAddress;
this.detailedAddress = detailedAddress;
this.status = status;
}

public void incrementViews() {
this.views++;
}

public void incrementLikes(){
this.likes++;
}

public void decrementLikes(){
this.likes--;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.market.saessag.domain.product.entity;

import com.market.saessag.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"product_id", "user_id"})})
public class ProductLike {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "product_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE) // 상품 삭제 시 좋아요도 삭제
private Product product;

@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.market.saessag.domain.product.entity;

import com.market.saessag.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

import java.time.LocalDateTime;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"product_id", "user_id"})})
public class ProductView {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "product_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private Product product;

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

private LocalDateTime viewTime;

@PrePersist
public void prePersist() {
this.viewTime = LocalDateTime.now();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.market.saessag.domain.product.repository;

import com.market.saessag.domain.product.entity.Product;
import com.market.saessag.domain.product.entity.ProductLike;
import com.market.saessag.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;


public interface ProductLikeRepository extends JpaRepository<ProductLike, Long> {
ProductLike findByProductAndUser(Product product, User user);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.market.saessag.domain.product.repository;

import com.market.saessag.domain.product.entity.Product;
import com.market.saessag.domain.product.entity.ProductView;
import com.market.saessag.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductViewRepository extends JpaRepository<ProductView, Long> {
boolean existsByProductAndUser(Product product, User user);
}
Loading

0 comments on commit 8c8d680

Please sign in to comment.