Skip to content
Merged
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,44 @@
package com.example.RealMatch.business.application.service;

import java.util.Arrays;
import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.RealMatch.business.domain.enums.ContentTagSort;
import com.example.RealMatch.business.presentation.dto.response.TagContentSortResponse;
import com.example.RealMatch.tag.domain.entity.TagContent;
import com.example.RealMatch.tag.domain.repository.TagContentRepository;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class TagContentSortQueryService {

private final TagContentRepository tagContentRepository;

public List<TagContentSortResponse> getAllGroupedBySort() {

List<TagContent> allTags = tagContentRepository.findAll();

return Arrays.stream(ContentTagSort.values())
.map(sort -> {
List<TagContent> filtered = allTags.stream()
.filter(tag ->
tag.getTagType().name().equals(sort.name())
)
.toList();

return TagContentSortResponse.from(sort, filtered);
})
.toList();
Comment on lines +25 to +37
Copy link
Contributor

Choose a reason for hiding this comment

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

high

현재 tagContentRepository.findAll()을 호출하여 모든 태그를 메모리로 가져온 후, ContentTagType별로 그룹화하고 있습니다. 태그의 수가 많아질 경우, 대규모 컬렉션을 메모리에서 필터링하고 그룹화하는 것은 심각한 성능 저하를 유발할 수 있습니다. findAll() 대신, ContentTagType별로 미리 그룹화된 태그를 반환하는 전용 쿼리 메서드를 TagContentRepository에 추가하여 데이터베이스 계층에서 이 로직을 처리하는 것을 강력히 권장합니다. 이렇게 하면 메모리 사용량을 줄이고 데이터베이스의 효율적인 인덱싱을 활용하여 성능을 크게 향상시킬 수 있습니다.

References
  1. Avoid filtering large collections in memory; instead, push filtering logic down to the database layer by adding specific query methods to the repository for better performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

나중에 수정해볼게 태그 25개라 일단은 그냥 함

}
}





Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.RealMatch.business.domain.enums;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum ContentTagSort {
FORMAT("형식"),
CATEGORY("종류"),
TONE("톤"),
INVOLVEMENT("관여도"),
USAGE_RANGE("활용 범위");

private final String korName;
}
Comment on lines +8 to +16
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

현재 ContentTagSortContentTagType enum은 이름(문자열)을 기준으로 연결되어 있어, 향후 유지보수 시 오류가 발생할 가능성이 있습니다. 예를 들어, 한쪽 enum의 이름만 변경될 경우 연관 로직이 오동작하게 됩니다.

ContentTagSortContentTagType을 직접 필드로 추가하여 타입-세이프(type-safe)하게 연관 관계를 맺는 것을 권장합니다. 이렇게 하면 코드의 안정성과 가독성이 향상됩니다.

참고: 아래 제안을 적용하려면 파일 상단에 import com.example.RealMatch.tag.domain.enums.ContentTagType; 구문을 추가해야 합니다.

Suggested change
public enum ContentTagSort {
FORMAT("형식"),
CATEGORY("종류"),
TONE("톤"),
INVOLVEMENT("관여도"),
USAGE_RANGE("활용 범위");
private final String korName;
}
public enum ContentTagSort {
FORMAT("형식", ContentTagType.FORMAT),
CATEGORY("종류", ContentTagType.CATEGORY),
TONE("톤", ContentTagType.TONE),
INVOLVEMENT("관여도", ContentTagType.INVOLVEMENT),
USAGE_RANGE("활용 범위", ContentTagType.USAGE_RANGE);
private final String korName;
private final ContentTagType tagType;
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.example.RealMatch.business.presentation.controller;

import java.util.List;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.RealMatch.business.application.service.TagContentSortQueryService;
import com.example.RealMatch.business.presentation.dto.response.TagContentSortResponse;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

@Tag(name = "Business-ContentTag", description = "비즈니스 캠페인 콘텐츠 태그")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/tag-contents/sort")
public class TagContentSortController {

private final TagContentSortQueryService tagContentSortQueryService;

@Operation(
summary = "콘텐츠 태그 정렬 기준별 조회",
description = """
콘텐츠 태그를 정렬 기준(ContentTagSort)별로 그룹화하여 조회합니다.

[응답 구조]
- sort: 태그 정렬 기준 (FORMAT, CATEGORY, TONE, INVOLVEMENT, USAGE_RANGE)
- sortKorName: 정렬 기준 한글명 (형식, 종류, 톤, 관여도, 활용 범위)
- tags: 해당 정렬 기준에 속하는 태그 목록
- id: 태그 ID
- name: 태그 한글명
"""
)
@GetMapping
public List<TagContentSortResponse> getAll() {
return tagContentSortQueryService.getAllGroupedBySort();
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.RealMatch.business.presentation.dto.response;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class CollaborationPageResponse {

private List<CollaborationResponse> contents;
private int page;
private int size;
private long totalElements;
private int totalPages;
private boolean hasNext;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.example.RealMatch.business.presentation.dto.response;

import java.util.List;

import com.example.RealMatch.business.domain.enums.ContentTagSort;
import com.example.RealMatch.tag.domain.entity.TagContent;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class TagContentSortResponse {

private ContentTagSort sort;
private String sortKorName;
private List<TagItemResponse> tags;

public static TagContentSortResponse from(
ContentTagSort sort,
List<TagContent> tagContents
) {
return TagContentSortResponse.builder()
.sort(sort)
.sortKorName(sort.getKorName())
.tags(tagContents.stream()
.map(tag -> new TagItemResponse(
tag.getId(),
tag.getKorName()
))
.toList())
.build();
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.RealMatch.business.presentation.dto.response;

public record TagItemResponse(
Long id,
String name
) {}

Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ public interface CampaignProposalSwagger {
@Operation(
summary = "캠페인 제안 생성 API by 박지영",
description = """
크리에이터가 브랜드에 캠페인을 제안합니다.
크리에이터가 브랜드에 캠페인을 제안합니다.
brandId, creatorId를 수정해서 보내야합니다.

신규 캠페인인 경우 campaignId null 을 보내주세요.
기존 캠페인인 경우 campaignId을 보내주세요.

기타인 경우 customValue를 포함해서 보내주세요.

/api/v1/tag-contents/sort에서 태그 id를 확인해주세요.
"""
)
@RequestBody(
Expand Down
Loading