add content api

This commit is contained in:
박서은 2025-06-17 15:08:46 +09:00
parent b34277c9bd
commit d77f6843ff
12 changed files with 38 additions and 143 deletions

View File

@ -60,18 +60,16 @@ public class ContentQueryService implements ContentQueryUseCase {
/** /**
* 콘텐츠 목록 조회 * 콘텐츠 목록 조회
* *
* @param contentType 콘텐츠 타입 * @param storeId 가게 ID
* @param platform 플랫폼 * @param platform 플랫폼
* @param period 기간
* @param sortBy 정렬 기준
* @return 콘텐츠 목록 * @return 콘텐츠 목록
*/ */
@Override @Override
public List<ContentResponse> getContents(String contentType, String platform, String period, String sortBy) { public List<ContentResponse> getContents(Long storeId, String platform) {
ContentType type = contentType != null ? ContentType.fromString(contentType) : null;
Platform platformEnum = platform != null ? Platform.fromString(platform) : null; Platform platformEnum = platform != null ? Platform.fromString(platform) : null;
List<Content> contents = contentRepository.findByFilters(type, platformEnum, period, sortBy); List<Content> contents = contentRepository.findByFilters(storeId, platformEnum);
return contents.stream() return contents.stream()
.map(this::toContentResponse) .map(this::toContentResponse)

View File

@ -74,6 +74,7 @@ public class SnsContentService implements SnsContentUseCase {
.platform(Platform.fromString(request.getPlatform())) .platform(Platform.fromString(request.getPlatform()))
.title(request.getTitle()) .title(request.getTitle())
.content(request.getContent()) .content(request.getContent())
.contentType(request.getContentType())
.hashtags(request.getHashtags()) .hashtags(request.getHashtags())
.images(request.getImages()) .images(request.getImages())
.status(ContentStatus.PUBLISHED) .status(ContentStatus.PUBLISHED)

View File

@ -22,13 +22,12 @@ public interface ContentQueryUseCase {
/** /**
* 콘텐츠 목록 조회 * 콘텐츠 목록 조회
* *
* @param contentType 콘텐츠 타입 * @param storeId 콘텐츠 타입
* @param platform 플랫폼 * @param platform 플랫폼
* @param period 기간
* @param sortBy 정렬 기준
* @return 콘텐츠 목록 * @return 콘텐츠 목록
*/ */
List<ContentResponse> getContents(String contentType, String platform, String period, String sortBy); List<ContentResponse> getContents(Long storeId, String platform);
/** /**
* 진행 중인 콘텐츠 목록 조회 * 진행 중인 콘텐츠 목록 조회

View File

@ -31,13 +31,12 @@ public interface ContentRepository {
/** /**
* 필터 조건으로 콘텐츠 목록 조회 * 필터 조건으로 콘텐츠 목록 조회
* @param contentType 콘텐츠 타입 * @param storeId 콘텐츠 타입
* @param platform 플랫폼 * @param platform 플랫폼
* @param period 기간
* @param sortBy 정렬 기준
* @return 콘텐츠 목록 * @return 콘텐츠 목록
*/ */
List<Content> findByFilters(ContentType contentType, Platform platform, String period, String sortBy); List<Content> findByFilters(Long storeId, Platform platform);
/** /**
* 진행 중인 콘텐츠 목록 조회 * 진행 중인 콘텐츠 목록 조회

View File

@ -1,38 +0,0 @@
package com.won.smarketing.content.domain.repository;
import com.won.smarketing.content.infrastructure.entity.ContentEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* Spring Data JPA ContentRepository
* JPA 기반 콘텐츠 데이터 접근
*/
@Repository
public interface SpringDataContentRepository extends JpaRepository<ContentEntity, Long> {
/**
* 매장별 콘텐츠 조회
*
* @param storeId 매장 ID
* @return 콘텐츠 목록
*/
List<ContentEntity> findByStoreId(Long storeId);
/**
* 콘텐츠 타입별 조회
*
* @param contentType 콘텐츠 타입
* @return 콘텐츠 목록
*/
List<ContentEntity> findByContentType(String contentType);
/**
* 플랫폼별 조회
*
* @param platform 플랫폼
* @return 콘텐츠 목록
*/
List<ContentEntity> findByPlatform(String platform);
}

View File

@ -1,60 +0,0 @@
package com.won.smarketing.content.infrastructure.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
/**
* 콘텐츠 엔티티
* 콘텐츠 정보를 데이터베이스에 저장하기 위한 JPA 엔티티
*/
@Entity
@Table(name = "contents")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class ContentEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "content_type", nullable = false)
private String contentType;
@Column(name = "platform", nullable = false)
private String platform;
@Column(name = "title", nullable = false)
private String title;
@Column(name = "content", columnDefinition = "TEXT")
private String content;
@Column(name = "hashtags")
private String hashtags;
@Column(name = "images", columnDefinition = "TEXT")
private String images;
@Column(name = "status", nullable = false)
private String status;
@Column(name = "store_id", nullable = false)
private Long storeId;
@CreatedDate
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
@Column(name = "updated_at")
private LocalDateTime updatedAt;
}

View File

@ -23,6 +23,7 @@ import java.util.Date;
public class ContentJpaEntity { public class ContentJpaEntity {
@Id @Id
@Column(name = "content_id")
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;

View File

@ -41,9 +41,9 @@ public class ContentMapper {
ContentJpaEntity entity = new ContentJpaEntity(); ContentJpaEntity entity = new ContentJpaEntity();
// 기본 필드 매핑 // 기본 필드 매핑
if (content.getId() != null) { // if (content.getId() != null) {
entity.setId(content.getId()); // entity.setId(content.getId());
} // }
entity.setStoreId(content.getStoreId()); entity.setStoreId(content.getStoreId());
entity.setContentType(content.getContentType() != null ? content.getContentType().name() : null); entity.setContentType(content.getContentType() != null ? content.getContentType().name() : null);
entity.setPlatform(content.getPlatform() != null ? content.getPlatform().name() : null); entity.setPlatform(content.getPlatform() != null ? content.getPlatform().name() : null);

View File

@ -66,20 +66,18 @@ public class JpaContentRepository implements ContentRepository {
/** /**
* 필터 조건으로 콘텐츠 목록 조회 * 필터 조건으로 콘텐츠 목록 조회
* @param contentType 콘텐츠 타입 * @param storeId 콘텐츠 타입
* @param platform 플랫폼 * @param platform 플랫폼
* @param period 기간 (현재는 사용하지 않음) *
* @param sortBy 정렬 기준 (현재는 사용하지 않음)
* @return 도메인 콘텐츠 목록 * @return 도메인 콘텐츠 목록
*/ */
@Override @Override
public List<Content> findByFilters(ContentType contentType, Platform platform, String period, String sortBy) { public List<Content> findByFilters(Long storeId, Platform platform) {
log.debug("Finding contents with filters - contentType: {}, platform: {}", contentType, platform); log.debug("Finding contents with filters - platform: {}", platform);
String contentTypeStr = contentType != null ? contentType.name() : null;
String platformStr = platform != null ? platform.name() : null; String platformStr = platform != null ? platform.name() : null;
List<ContentJpaEntity> entities = jpaRepository.findByFilters(contentTypeStr, platformStr, null); List<ContentJpaEntity> entities = jpaRepository.findByFilters(storeId, platformStr);
return entities.stream() return entities.stream()
.map(contentMapper::toDomain) .map(contentMapper::toDomain)

View File

@ -45,19 +45,16 @@ public interface JpaContentRepositoryInterface extends JpaRepository<ContentJpaE
/** /**
* 필터 조건으로 콘텐츠 목록 조회 * 필터 조건으로 콘텐츠 목록 조회
* @param contentType 콘텐츠 타입 (null 가능) * @param storeId 콘텐츠 타입
* @param platform 플랫폼 (null 가능) * @param platform 플랫폼 (null 가능)
* @param status 상태 (null 가능)
* @return 콘텐츠 엔티티 목록 * @return 콘텐츠 엔티티 목록
*/ */
@Query("SELECT c FROM ContentJpaEntity c WHERE " + @Query("SELECT c FROM ContentJpaEntity c WHERE " +
"(:contentType IS NULL OR c.contentType = :contentType) AND " + "(c.storeId = :storeId) AND " +
"(:platform IS NULL OR c.platform = :platform) AND " + "(:platform IS NULL OR c.platform = :platform)" +
"(:status IS NULL OR c.status = :status) " +
"ORDER BY c.createdAt DESC") "ORDER BY c.createdAt DESC")
List<ContentJpaEntity> findByFilters(@Param("contentType") String contentType, List<ContentJpaEntity> findByFilters(@Param("storeId") Long storeId,
@Param("platform") String platform, @Param("platform") String platform);
@Param("status") String status);
/** /**
* 진행 중인 콘텐츠 목록 조회 (발행된 상태의 콘텐츠) * 진행 중인 콘텐츠 목록 조회 (발행된 상태의 콘텐츠)

View File

@ -101,24 +101,19 @@ public class ContentController {
/** /**
* 콘텐츠 목록 조회 * 콘텐츠 목록 조회
* *
* @param contentType 콘텐츠 타입 필터 * @param storeId 콘텐츠 타입 필터
* @param platform 플랫폼 필터 * @param platform 플랫폼 필터
* @param period 기간 필터 *
* @param sortBy 정렬 기준
* @return 콘텐츠 목록 * @return 콘텐츠 목록
*/ */
@Operation(summary = "콘텐츠 목록 조회", description = "다양한 필터와 정렬 옵션으로 콘텐츠 목록을 조회합니다.") @Operation(summary = "콘텐츠 목록 조회", description = "다양한 필터와 정렬 옵션으로 콘텐츠 목록을 조회합니다.")
@GetMapping @GetMapping
public ResponseEntity<ApiResponse<List<ContentResponse>>> getContents( public ResponseEntity<ApiResponse<List<ContentResponse>>> getContents(
@Parameter(description = "콘텐츠 타입")
@RequestParam(required = false) String contentType,
@Parameter(description = "플랫폼") @Parameter(description = "플랫폼")
@RequestParam(required = false) String platform, @RequestParam(required = false) String platform,
@Parameter(description = "기간") @Parameter(description = "가게 ID")
@RequestParam(required = false) String period, @RequestParam Long storeId) {
@Parameter(description = "정렬 기준") List<ContentResponse> response = contentQueryUseCase.getContents(storeId, platform);
@RequestParam(required = false) String sortBy) {
List<ContentResponse> response = contentQueryUseCase.getContents(contentType, platform, period, sortBy);
return ResponseEntity.ok(ApiResponse.success(response)); return ResponseEntity.ok(ApiResponse.success(response));
} }

View File

@ -1,6 +1,7 @@
// smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentSaveRequest.java // smarketing-java/marketing-content/src/main/java/com/won/smarketing/content/presentation/dto/SnsContentSaveRequest.java
package com.won.smarketing.content.presentation.dto; package com.won.smarketing.content.presentation.dto;
import com.won.smarketing.content.domain.model.ContentType;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
@ -22,14 +23,18 @@ import java.util.List;
@Schema(description = "SNS 콘텐츠 저장 요청") @Schema(description = "SNS 콘텐츠 저장 요청")
public class SnsContentSaveRequest { public class SnsContentSaveRequest {
@Schema(description = "콘텐츠 ID", example = "1", required = true) // @Schema(description = "콘텐츠 ID", example = "1", required = true)
@NotNull(message = "콘텐츠 ID는 필수입니다") // @NotNull(message = "콘텐츠 ID는 필수입니다")
private Long contentId; // private Long contentId;
@Schema(description = "매장 ID", example = "1", required = true) @Schema(description = "매장 ID", example = "1", required = true)
@NotNull(message = "매장 ID는 필수입니다") @NotNull(message = "매장 ID는 필수입니다")
private Long storeId; private Long storeId;
@Schema(description = "콘텐트 타입", example = "1", required = true)
@NotNull(message = "콘텐트 타입은 필수입니다")
private ContentType contentType;
@Schema(description = "플랫폼", example = "INSTAGRAM", required = true) @Schema(description = "플랫폼", example = "INSTAGRAM", required = true)
@NotBlank(message = "플랫폼은 필수입니다") @NotBlank(message = "플랫폼은 필수입니다")
private String platform; private String platform;