Skip to content

Commit

Permalink
feat: 음식점 전체 조회 api 구현 (#135)
Browse files Browse the repository at this point in the history
* feat: 음식점 전체 조회 서비스 구현 (#133)

* refactor: fixture 분리 (#133)

* feat: 음식점 전체 조회 API 구현 (#133)

* test: 인수테스트 공통화 (#133)

* style: polishing (#133)

* style: polishing (#133)

---------

Co-authored-by: TaeyeonRoyce <[email protected]>
Co-authored-by: shin-mallang <[email protected]>
Co-authored-by: kdkdhoho <[email protected]>
  • Loading branch information
4 people authored Jul 18, 2023
1 parent dc62719 commit ae71fa3
Show file tree
Hide file tree
Showing 20 changed files with 597 additions and 28 deletions.
38 changes: 20 additions & 18 deletions backend/build.gradle
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
id 'java'
id 'org.springframework.boot' version '3.1.1'
id 'io.spring.dependency-management' version '1.1.0'
}

group = 'com.celuveat'
version = '0.0.1-SNAPSHOT'

java {
sourceCompatibility = '17'
sourceCompatibility = '17'
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.0'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.0'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}
6 changes: 3 additions & 3 deletions backend/src/main/java/com/celuveat/CeluveatApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
@SpringBootApplication
public class CeluveatApplication {

public static void main(String[] args) {
SpringApplication.run(CeluveatApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(CeluveatApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.celuveat.restaurant.application;

import static java.util.stream.Collectors.groupingBy;

import com.celuveat.celeb.domain.Celeb;
import com.celuveat.restaurant.application.dto.RestaurantQueryResponse;
import com.celuveat.restaurant.domain.Restaurant;
import com.celuveat.restaurant.domain.RestaurantImage;
import com.celuveat.restaurant.domain.RestaurantImageRepository;
import com.celuveat.video.domain.Video;
import com.celuveat.video.domain.VideoRepository;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class RestaurantQueryService {

private final RestaurantImageRepository restaurantImageRepository;
private final VideoRepository videoRepository;

public List<RestaurantQueryResponse> findAll() {
Map<Restaurant, List<Celeb>> celebs = restaurantCelebsMap();
Map<Restaurant, List<RestaurantImage>> images = restaurantImagesMap();
return images.keySet().stream()
.map(restaurant -> mapToRestaurantQueryResponse(celebs, images, restaurant))
.toList();
}

private Map<Restaurant, List<Celeb>> restaurantCelebsMap() {
List<Video> videos = videoRepository.findAll();
Map<Restaurant, List<Video>> restaurantVideos = videos.stream()
.collect(groupingBy(Video::restaurant, LinkedHashMap::new, Collectors.toList()));
Map<Restaurant, List<Celeb>> celebs = new LinkedHashMap<>();
for (Restaurant restaurant : restaurantVideos.keySet()) {
List<Celeb> list = restaurantVideos.get(restaurant).stream()
.map(Video::celeb)
.toList();
celebs.put(restaurant, list);
}
return celebs;
}

private Map<Restaurant, List<RestaurantImage>> restaurantImagesMap() {
List<RestaurantImage> restaurantImages = restaurantImageRepository.findAll();
return restaurantImages.stream()
.collect(groupingBy(RestaurantImage::restaurant, LinkedHashMap::new, Collectors.toList()));
}

private RestaurantQueryResponse mapToRestaurantQueryResponse(
Map<Restaurant, List<Celeb>> restaurantCelebsMap,
Map<Restaurant, List<RestaurantImage>> restaurantImagesMap,
Restaurant restaurant
) {
return RestaurantQueryResponse.from(restaurant, restaurantCelebsMap.get(restaurant),
restaurantImagesMap.get(restaurant));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.celuveat.restaurant.application.dto;

import com.celuveat.celeb.domain.Celeb;

public record CelebQueryResponse(
Long id,
String name,
String youtubeChannelName,
String profileImageUrl
) {

public static CelebQueryResponse of(Celeb it) {
return new CelebQueryResponse(
it.id(),
it.name(),
it.youtubeChannelName(),
it.profileImageUrl()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.celuveat.restaurant.application.dto;

import com.celuveat.restaurant.domain.RestaurantImage;

public record RestaurantImageQueryResponse(
Long id,
String name,
String author,
String sns
) {

public static RestaurantImageQueryResponse of(RestaurantImage restaurantImage) {
return new RestaurantImageQueryResponse(
restaurantImage.id(),
restaurantImage.name(),
restaurantImage.author(),
restaurantImage.author()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.celuveat.restaurant.application.dto;

import com.celuveat.celeb.domain.Celeb;
import com.celuveat.restaurant.domain.Restaurant;
import com.celuveat.restaurant.domain.RestaurantImage;
import java.util.List;

public record RestaurantQueryResponse(
Long id,
String name,
String category,
String roadAddress,
String latitude,
String longitude,
String phoneNumber,
String naverMapUrl,
List<CelebQueryResponse> celebs,
List<RestaurantImageQueryResponse> images
) {

public static RestaurantQueryResponse from(
Restaurant restaurant,
List<Celeb> celebs,
List<RestaurantImage> restaurantImages
) {
return new RestaurantQueryResponse(
restaurant.id(),
restaurant.name(),
restaurant.category(),
restaurant.roadAddress(),
restaurant.latitude(),
restaurant.longitude(),
restaurant.phoneNumber(),
restaurant.naverMapUrl(),
celebs.stream().map(CelebQueryResponse::of).toList(),
restaurantImages.stream().map(RestaurantImageQueryResponse::of).toList()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.celuveat.restaurant.domain;

import static jakarta.persistence.EnumType.*;
import static jakarta.persistence.FetchType.*;
import static jakarta.persistence.EnumType.STRING;
import static jakarta.persistence.FetchType.LAZY;
import static lombok.AccessLevel.PROTECTED;

import com.celuveat.common.domain.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AllArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.celuveat.restaurant.presentation;

import com.celuveat.restaurant.application.RestaurantQueryService;
import com.celuveat.restaurant.application.dto.RestaurantQueryResponse;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/restaurants")
public class RestaurantController {

private final RestaurantQueryService restaurantQueryService;

@GetMapping
ResponseEntity<List<RestaurantQueryResponse>> findAll() {
return ResponseEntity.ok(restaurantQueryService.findAll());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
@SpringBootTest
class CeluveatApplicationTests {

@Test
void contextLoads() {
}
@Test
void contextLoads() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.celuveat.acceptance.common;

import static io.restassured.http.ContentType.JSON;
import static org.assertj.core.api.Assertions.assertThat;

import com.celuveat.common.exception.BaseExceptionType;
import com.celuveat.common.exception.ExceptionResponse;
import io.restassured.RestAssured;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;
import java.time.LocalDateTime;
import org.springframework.http.HttpStatus;

public class AcceptanceSteps {

public static final HttpStatus 정상_처리 = HttpStatus.OK;
public static final HttpStatus 생성됨 = HttpStatus.CREATED;
public static final HttpStatus 잘못된_요청 = HttpStatus.BAD_REQUEST;
public static final HttpStatus 권한_없음 = HttpStatus.FORBIDDEN;
public static final HttpStatus 찾을수_없음 = HttpStatus.NOT_FOUND;
public static final HttpStatus 중복됨 = HttpStatus.CONFLICT;

public static LocalDateTime 현재시간() {
return LocalDateTime.now();
}

public static RequestSpecification given() {
return RestAssured
.given().log().all()
.contentType(JSON);
}

public static void 발생한_예외를_검증한다(
ExtractableResponse<Response> 응답,
BaseExceptionType 예외_타입
) {
ExceptionResponse exceptionResponse = 응답.as(ExceptionResponse.class);
assertThat(exceptionResponse.message())
.isEqualTo(예외_타입.errorMessage());
}

public static <T> void 값이_존재한다(T t) {
assertThat(t).isNotNull();
}

public static <T> void_값이_같다(T 첫번째_값, T 두번째_값) {
assertThat(첫번째_값).isEqualTo(두번째_값);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.celuveat.acceptance.common;

import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;

@DisplayNameGeneration(ReplaceUnderscores.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class AcceptanceTest {

@LocalServerPort
private int port;

@BeforeEach
void setUp() {
RestAssured.port = port;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.celuveat.acceptance.restaurant;

import static com.celuveat.acceptance.common.AcceptanceSteps.given;
import static org.assertj.core.api.Assertions.assertThat;

import com.celuveat.restaurant.application.dto.RestaurantQueryResponse;
import io.restassured.common.mapper.TypeRef;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import java.util.List;

public class RestaurantAcceptanceSteps {

public static ExtractableResponse<Response> 음식점_전체_조회_요청() {
return given()
.when().get("/restaurants")
.then().log().all()
.extract();
}

public static void 조회_결과를_검증한다(List<RestaurantQueryResponse> 예상_응답, ExtractableResponse<Response> 응답) {
List<RestaurantQueryResponse> restaurantQueryResponse = 응답.as(new TypeRef<>() {
});
assertThat(restaurantQueryResponse).usingRecursiveComparison()
.isEqualTo(예상_응답);
}
}
Loading

0 comments on commit ae71fa3

Please sign in to comment.