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

[BE] feat: 전체 태그 목록 조회 기능 추가 #161

Merged
merged 10 commits into from
Jul 28, 2023
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
Expand Up @@ -2,7 +2,7 @@

import com.funeat.product.domain.Product;
import com.funeat.tag.domain.Tag;
import com.funeat.tag.domain.TagDto;
import com.funeat.tag.dto.TagDto;
import java.util.ArrayList;
import java.util.List;

Expand Down
37 changes: 37 additions & 0 deletions backend/src/main/java/com/funeat/tag/application/TagService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.funeat.tag.application;

import com.funeat.tag.domain.TagType;
import com.funeat.tag.dto.TagDto;
import com.funeat.tag.dto.TagsResponse;
import com.funeat.tag.persistence.TagRepository;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = true)
public class TagService {

private final TagRepository tagRepository;

public TagService(final TagRepository tagRepository) {
this.tagRepository = tagRepository;
}

public List<TagsResponse> getAllTags() {
final List<TagsResponse> responses = new ArrayList<>();
for (final TagType tagType : TagType.values()) {
responses.add(getTagsByTagType(tagType));
}
return responses;
}

private TagsResponse getTagsByTagType(final TagType tagType) {
final List<TagDto> tags = tagRepository.findTagsByTagType(tagType).stream()
.map(TagDto::toDto)
.collect(Collectors.toList());
return TagsResponse.toResponse(tagType.name(), tags);
}
}
12 changes: 11 additions & 1 deletion backend/src/main/java/com/funeat/tag/domain/Tag.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.funeat.tag.domain;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
Expand All @@ -14,11 +16,15 @@ public class Tag {

private String name;

@Enumerated(EnumType.STRING)
private TagType tagType;

protected Tag() {
}

public Tag(final String name) {
public Tag(final String name, final TagType tagType) {
this.name = name;
this.tagType = tagType;
}

public Long getId() {
Expand All @@ -28,4 +34,8 @@ public Long getId() {
public String getName() {
return name;
}

public TagType getTagType() {
return tagType;
}
}
6 changes: 6 additions & 0 deletions backend/src/main/java/com/funeat/tag/domain/TagType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.funeat.tag.domain;

public enum TagType {

TASTE, PRICE, ETC
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package com.funeat.tag.domain;
package com.funeat.tag.dto;

import com.funeat.tag.domain.Tag;

public class TagDto {

Expand Down
26 changes: 26 additions & 0 deletions backend/src/main/java/com/funeat/tag/dto/TagsResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.funeat.tag.dto;

import java.util.List;

public class TagsResponse {

private final String tagType;
private final List<TagDto> tags;

public TagsResponse(final String tagType, final List<TagDto> tags) {
this.tagType = tagType;
this.tags = tags;
}

public static TagsResponse toResponse(final String tagType, final List<TagDto> tags) {
return new TagsResponse(tagType, tags);
}

public String getTagType() {
return tagType;
}

public List<TagDto> getTags() {
return tags;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.funeat.tag.persistence;

import com.funeat.tag.domain.Tag;
import com.funeat.tag.domain.TagType;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TagRepository extends JpaRepository<Tag, Long> {

List<Tag> findTagsByIdIn(final List<Long> tagIds);

List<Tag> findTagsByTagType(final TagType tagType);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.funeat.tag.presentation;

import com.funeat.tag.application.TagService;
import com.funeat.tag.dto.TagsResponse;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TagApiController implements TagController {

private final TagService tagService;

public TagApiController(final TagService tagService) {
this.tagService = tagService;
}

@GetMapping("/api/tags")
public ResponseEntity<List<TagsResponse>> getAllTags() {
final List<TagsResponse> responses = tagService.getAllTags();
return ResponseEntity.ok(responses);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.funeat.tag.presentation;

import com.funeat.tag.dto.TagsResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;

@Tag(name = "04.Tag", description = "태그 기능")
public interface TagController {

@Operation(summary = "전체 태그 목록 조회", description = "전체 태그 목록을 태그 타입 별로 조회한다.")
@ApiResponse(
responseCode = "200",
description = "전체 태그 목록 조회 성공."
)
@GetMapping
ResponseEntity<List<TagsResponse>> getAllTags();
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.funeat.review.domain.Review;
import com.funeat.review.presentation.dto.ReviewCreateRequest;
import com.funeat.tag.domain.Tag;
import com.funeat.tag.domain.TagType;
import io.restassured.common.mapper.TypeRef;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
Expand Down Expand Up @@ -318,7 +319,6 @@ class 리뷰수_기준_내림차순으로_카테고리별_상품_목록_조회 {
review3_1, review3_2, review3_3);
복수_리뷰_가_요청(reviews);


// when
final var response = 카테고리별_상품_목록_조회_요청(categoryId, "reviewCount", "desc", 0);

Expand Down Expand Up @@ -373,9 +373,9 @@ class 리뷰수_기준_내림차순으로_카테고리별_상품_목록_조회 {
final Product product = new Product("삼각김밥1", 1000L, "image.png", "맛있는 삼각김밥1", 간편식사);
final Long productId = 상품_가_요청(product);
final Long memberId = 기본_멤버_가_요청();
final Tag tag1 = 태그_가_요청(new Tag("1번"));
final Tag tag2 = 태그_가_요청(new Tag("2번"));
final Tag tag3 = 태그_가_요청(new Tag("3번"));
final Tag tag1 = 태그_가_요청(new Tag("1번", TagType.ETC));
final Tag tag2 = 태그_가_요청(new Tag("2번", TagType.ETC));
final Tag tag3 = 태그_가_요청(new Tag("3번", TagType.ETC));
final MultiPartSpecification image = 리뷰_사진_명세_요청();

final ReviewCreateRequest request1 = new ReviewCreateRequest(4L,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.funeat.review.presentation.dto.SortingReviewDto;
import com.funeat.review.presentation.dto.SortingReviewsPageDto;
import com.funeat.tag.domain.Tag;
import com.funeat.tag.domain.TagType;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import io.restassured.specification.MultiPartSpecification;
Expand Down Expand Up @@ -106,8 +107,8 @@ class ReviewAcceptanceTest extends AcceptanceTest {
}

private List<Long> 태그_가_요청() {
final Tag testTag1 = tagRepository.save(new Tag("testTag1"));
final Tag testTag2 = tagRepository.save(new Tag("testTag2"));
final Tag testTag1 = tagRepository.save(new Tag("testTag1", TagType.ETC));
final Tag testTag2 = tagRepository.save(new Tag("testTag2", TagType.ETC));
return List.of(testTag1.getId(), testTag2.getId());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.funeat.acceptance.tag;

import static com.funeat.acceptance.common.CommonSteps.STATUS_CODE를_검증한다;
import static com.funeat.acceptance.common.CommonSteps.정상_처리;
import static com.funeat.acceptance.tag.TagSteps.전체_태그_목록_조회_요청;
import static com.funeat.tag.domain.TagType.ETC;
import static com.funeat.tag.domain.TagType.PRICE;
import static com.funeat.tag.domain.TagType.TASTE;
import static org.assertj.core.api.Assertions.assertThat;

import com.funeat.acceptance.common.AcceptanceTest;
import com.funeat.tag.domain.Tag;
import com.funeat.tag.domain.TagType;
import com.funeat.tag.dto.TagsResponse;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;

@SuppressWarnings("NonAsciiCharacters")
public class TagAcceptanceTest extends AcceptanceTest {

@Test
void 전체_태그_목록을_조회할_수_있다() {
// given
final var tag1 = 태그_추가_요청(new Tag("단짠단짠", TASTE));
final var tag2 = 태그_추가_요청(new Tag("매콤해요", TASTE));
final var tag3 = 태그_추가_요청(new Tag("갓성비", PRICE));
final var tag4 = 태그_추가_요청(new Tag("바삭바삭", ETC));

// when
final var response = 전체_태그_목록_조회_요청();

// then
STATUS_CODE를_검증한다(response, 정상_처리);
전체_태그_목록_조회_결과를_검증한다(response, List.of(tag1, tag2, tag3, tag4));
}

private Tag 태그_추가_요청(final Tag tag) {
return tagRepository.save(tag);
}

private void 전체_태그_목록_조회_결과를_검증한다(final ExtractableResponse<Response> response, final List<Tag> tags) {
final var expectedByType = tags.stream()
.collect(Collectors.groupingBy(Tag::getTagType));
final var actual = response.jsonPath()
.getList("", TagsResponse.class);

for (final TagsResponse tagsResponse : actual) {
final TagType tagType = TagType.valueOf(tagsResponse.getTagType());
assertThat(tagType).isIn(expectedByType.keySet());
assertThat(tagsResponse.getTags()).usingRecursiveComparison()
.isEqualTo(expectedByType.get(tagType));
}
}
}
18 changes: 18 additions & 0 deletions backend/src/test/java/com/funeat/acceptance/tag/TagSteps.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.funeat.acceptance.tag;

import static io.restassured.RestAssured.given;

import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;

@SuppressWarnings("NonAsciiCharacters")
public class TagSteps {

public static ExtractableResponse<Response> 전체_태그_목록_조회_요청() {
return given()
.when()
.get("/api/tags")
.then()
.extract();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.funeat.review.presentation.dto.ReviewFavoriteRequest;
import com.funeat.review.presentation.dto.SortingReviewDto;
import com.funeat.tag.domain.Tag;
import com.funeat.tag.domain.TagType;
import com.funeat.tag.persistence.TagRepository;
import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -166,8 +167,8 @@ void init() {
}

private List<Tag> 태그_가_요청() {
final Tag testTag1 = tagRepository.save(new Tag("testTag1"));
final Tag testTag2 = tagRepository.save(new Tag("testTag2"));
final Tag testTag1 = tagRepository.save(new Tag("testTag1", TagType.ETC));
final Tag testTag2 = tagRepository.save(new Tag("testTag2", TagType.ETC));

return List.of(testTag1, testTag2);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.funeat.review.domain.Review;
import com.funeat.review.domain.ReviewTag;
import com.funeat.tag.domain.Tag;
import com.funeat.tag.domain.TagType;
import com.funeat.tag.persistence.TagRepository;
import java.util.List;
import org.junit.jupiter.api.DisplayNameGeneration;
Expand Down Expand Up @@ -53,10 +54,10 @@ class ReviewTagRepositoryTest {
final var product = new Product("망고", 1_000L, "mango.png", "망고망고", null);
productRepository.save(product);

final var tag1 = new Tag("1번");
final var tag2 = new Tag("2번");
final var tag3 = new Tag("3번");
final var tag4 = new Tag("4번");
final var tag1 = new Tag("1번", TagType.ETC);
final var tag2 = new Tag("2번", TagType.ETC);
final var tag3 = new Tag("3번", TagType.ETC);
final var tag4 = new Tag("4번", TagType.ETC);
tagRepository.saveAll(List.of(tag1, tag2, tag3, tag4));

final var review1 = new Review(member, product, "review1.png", 5L, "최고의 망고", true, 25L);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.funeat.tag.persistence;

import static com.funeat.tag.domain.TagType.ETC;
import static com.funeat.tag.domain.TagType.PRICE;
import static com.funeat.tag.domain.TagType.TASTE;
import static org.assertj.core.api.Assertions.assertThat;

import com.funeat.common.DataCleaner;
Expand Down Expand Up @@ -28,7 +31,9 @@ class TagRepositoryTest {
@Test
void 여러_태그_아이디로_태그들을_조회_할_수_있다() {
// given
final var tags = 태그_추가_요청();
final var tag1 = 태그_추가_요청(new Tag("testTag1", ETC));
final var tag2 = 태그_추가_요청(new Tag("testTag2", ETC));
final var tags = List.of(tag1, tag2);
final var tagIds = tags.stream()
.map(Tag::getId)
.collect(Collectors.toList());
Expand All @@ -41,10 +46,23 @@ class TagRepositoryTest {
.isEqualTo(tags);
}

private List<Tag> 태그_추가_요청() {
final var testTag1 = tagRepository.save(new Tag("testTag1"));
final var testTag2 = tagRepository.save(new Tag("testTag2"));
@Test
void 태그_타입으로_태그들을_조회할_수_있다() {
// given
final var tag1 = 태그_추가_요청(new Tag("단짠단짠", TASTE));
final var tag2 = 태그_추가_요청(new Tag("매콤해요", TASTE));
final var tag3 = 태그_추가_요청(new Tag("갓성비", PRICE));
final var expected = List.of(tag1, tag2);

// when
final var actual = tagRepository.findTagsByTagType(TASTE);

// then
assertThat(actual).usingRecursiveComparison()
.isEqualTo(expected);
}

return List.of(testTag1, testTag2);
private Tag 태그_추가_요청(final Tag tag) {
return tagRepository.save(tag);
}
}
Loading