[#3] cafe api 개발 및 전반적인 container 환경 설정 세팅
- docker compose 활용한 컨테이너 환경 구축 - cafe 관련 api 구축 - flyway migration db 및 seed data 설정
This commit is contained in:
34
Dockerfile
Normal file
34
Dockerfile
Normal file
@@ -0,0 +1,34 @@
|
||||
FROM adoptopenjdk/openjdk11:latest as BUILD_IMAGE
|
||||
|
||||
ENV WORK_DIR=/usr/app/
|
||||
|
||||
# app 작업 디렉토리 설정
|
||||
WORKDIR $WORK_DIR
|
||||
|
||||
# gradle 실행을 위한 필수 디렉토리 준비
|
||||
COPY gradlew $WORK_DIR
|
||||
COPY build.gradle $WORK_DIR
|
||||
COPY settings.gradle $WORK_DIR
|
||||
COPY gradle $WORK_DIR/gradle
|
||||
|
||||
RUN ./gradlew -x test build || return 0
|
||||
|
||||
COPY src src
|
||||
|
||||
# jar 파일 build
|
||||
RUN ./gradlew bootjar
|
||||
|
||||
FROM adoptopenjdk/openjdk11:latest
|
||||
|
||||
ENV WORK_DIR=/usr/app/
|
||||
|
||||
WORKDIR $WORK_DIR
|
||||
|
||||
COPY --from=BUILD_IMAGE $WORK_DIR/build/libs/*.jar app-server.jar
|
||||
|
||||
ENTRYPOINT ["java", \
|
||||
"-jar", \
|
||||
"-Dspring.profiles.active=${PROFILE_OPTION}", \
|
||||
"-Dspring.datasource.url=${SPRING_DATASOURCE_URL}", \
|
||||
"-Dredis.host=${REDIS_HOST}", \
|
||||
"app-server.jar"]
|
||||
16
build.gradle
16
build.gradle
@@ -22,14 +22,28 @@ 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'
|
||||
|
||||
// log4j2
|
||||
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-log4j2'
|
||||
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
|
||||
// MySQL
|
||||
runtimeOnly 'mysql:mysql-connector-java'
|
||||
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
}
|
||||
|
||||
configurations {
|
||||
all {
|
||||
// log4j2 적용을 위해 기존 spring boot에서 제공하는 logging exclude
|
||||
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
50
docker-compose.yml
Normal file
50
docker-compose.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
version: "3.8"
|
||||
services:
|
||||
nginx:
|
||||
image: nginx
|
||||
container_name: nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./nginx/:/etc/nginx/conf.d/
|
||||
depends_on:
|
||||
- app-server-1
|
||||
- app-server-2
|
||||
app-server-1:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- env/app.env
|
||||
depends_on:
|
||||
- db-mysql
|
||||
app-server-2:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- env/app.env
|
||||
depends_on:
|
||||
- db-mysql
|
||||
migration:
|
||||
image: flyway/flyway:7.5.1
|
||||
command: -configFiles=/flyway/conf/flyway.config -locations=filesystem:/flyway/sql -connectRetries=60 migrate
|
||||
volumes:
|
||||
- ${PWD}/flyway/db-migration/main:/flyway/sql
|
||||
- ${PWD}/flyway/conf/flyway_main.conf:/flyway/conf/flyway.config
|
||||
depends_on:
|
||||
- db-mysql
|
||||
seed:
|
||||
image: flyway/flyway:7.5.1
|
||||
command: -configFiles=/flyway/conf/flyway.config -locations=filesystem:/flyway/sql -connectRetries=60 migrate
|
||||
volumes:
|
||||
- ${PWD}/flyway/db-migration/seed:/flyway/sql
|
||||
- ${PWD}/flyway/conf/flyway_seed.conf:/flyway/conf/flyway.config
|
||||
depends_on:
|
||||
- db-mysql
|
||||
db-mysql:
|
||||
image: mysql:5.7.34
|
||||
ports:
|
||||
- "3306:3306"
|
||||
env_file:
|
||||
- env/mysql.env
|
||||
4
env/app.env
vendored
Normal file
4
env/app.env
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
PROFILE_OPTION=dev
|
||||
SPRING_DATASOURCE_URL=jdbc:mysql://db-mysql:3306/dongnecafe?autoreconnect=true&characterEncoding=utf8&serverTimezone=Asia/Seoul
|
||||
SPRING_DATASOURCE_USERNAME=root
|
||||
SPRING_DATASOURCE_PASSWORD=dev
|
||||
2
env/mysql.env
vendored
Normal file
2
env/mysql.env
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
MYSQL_DATABASE=dongnecafe
|
||||
MYSQL_ROOT_PASSWORD=dev
|
||||
7
flyway/Dockerfile
Normal file
7
flyway/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM flyway/flyway
|
||||
|
||||
COPY conf/flyway_main.conf main.conf
|
||||
COPY conf/flyway_seed.conf seed.conf
|
||||
|
||||
ENTRYPOINT ["-configFiles=main.conf", "migrate"]
|
||||
ENTRYPOINT ["-configFiles=seed.conf", "migrate"]
|
||||
4
flyway/conf/flyway_main.conf
Normal file
4
flyway/conf/flyway_main.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
flyway.url=jdbc:mysql://db-mysql:3306/dongnecafe
|
||||
flyway.user=root
|
||||
flyway.password=dev
|
||||
flyway.driver=com.mysql.cj.jdbc.Driver
|
||||
4
flyway/conf/flyway_seed.conf
Normal file
4
flyway/conf/flyway_seed.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
flyway.url=jdbc:mysql://db-mysql:3306/dongnecafe
|
||||
flyway.user=root
|
||||
flyway.password=dev
|
||||
flyway.driver=com.mysql.cj.jdbc.Driver
|
||||
10
nginx/default.conf
Normal file
10
nginx/default.conf
Normal file
@@ -0,0 +1,10 @@
|
||||
upstream appserver {
|
||||
server app-server-1:8080;
|
||||
server app-server-2:8080;
|
||||
}
|
||||
server {
|
||||
listen 80;
|
||||
location / {
|
||||
proxy_pass http://appserver;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.beaniejoy.dongecafe;
|
||||
package io.beaniejoy.dongnecafe;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.controller;
|
||||
|
||||
import io.beaniejoy.dongnecafe.cafe.dto.CafeResponseDto;
|
||||
import io.beaniejoy.dongnecafe.cafe.service.CafeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/cafes")
|
||||
public class CafeController {
|
||||
|
||||
private final CafeService cafeService;
|
||||
|
||||
@GetMapping("/")
|
||||
public ResponseEntity<List<CafeResponseDto>> getCafeList(
|
||||
@PageableDefault(sort = "name", direction = Sort.Direction.ASC, size = 10) Pageable pageable) {
|
||||
List<CafeResponseDto> cafeResponseList = cafeService.getCafeList(pageable);
|
||||
|
||||
return ResponseEntity.ok(cafeResponseList);
|
||||
}
|
||||
|
||||
@GetMapping("/{cafeId}")
|
||||
public ResponseEntity<CafeResponseDto> getCafeInfo(@PathVariable("cafeId") UUID cafeId) {
|
||||
CafeResponseDto cafeResponse = cafeService.getCafeByCafeId(cafeId);
|
||||
|
||||
return ResponseEntity.ok(cafeResponse);
|
||||
}
|
||||
}
|
||||
54
src/main/java/io/beaniejoy/dongnecafe/cafe/domain/Cafe.java
Normal file
54
src/main/java/io/beaniejoy/dongnecafe/cafe/domain/Cafe.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.domain;
|
||||
|
||||
import io.beaniejoy.dongnecafe.cafe.dto.CafeResponseDto;
|
||||
import io.beaniejoy.dongnecafe.common.domain.BaseTimeEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
public class Cafe extends BaseTimeEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Column(name = "cafe_id", columnDefinition = "BINARY(16)")
|
||||
private UUID cafeId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String address;
|
||||
|
||||
private String phoneNumber;
|
||||
|
||||
private Double totalRate;
|
||||
|
||||
private String description;
|
||||
|
||||
@OneToMany(mappedBy = "cafe", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
private List<CafeMenu> cafeMenuList;
|
||||
|
||||
@OneToMany(mappedBy = "cafe", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
private List<CafeImage> cafeImageList;
|
||||
|
||||
public CafeResponseDto toResponseDto() {
|
||||
return CafeResponseDto.builder()
|
||||
.cafeId(cafeId)
|
||||
.name(name)
|
||||
.address(address)
|
||||
.phoneNumber(phoneNumber)
|
||||
.totalRate(totalRate)
|
||||
.description(description)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.domain;
|
||||
|
||||
import io.beaniejoy.dongnecafe.common.domain.BaseTimeEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
public class CafeImage extends BaseTimeEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Column(name = "cafe_img_id", columnDefinition = "BINARY(16)")
|
||||
private UUID cafeImgId;
|
||||
|
||||
private String imgUrl;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "cafe_id")
|
||||
private Cafe cafe;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.domain;
|
||||
|
||||
import io.beaniejoy.dongnecafe.common.domain.BaseTimeEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
public class CafeMenu extends BaseTimeEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Column(name = "menu_id", columnDefinition = "BINARY(16)")
|
||||
private UUID menuId;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer price;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "cafe_id")
|
||||
private Cafe cafe;
|
||||
|
||||
@OneToMany(mappedBy = "cafeMenu")
|
||||
private List<MenuOption> menuOptionList;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.domain;
|
||||
|
||||
import io.beaniejoy.dongnecafe.common.domain.BaseTimeEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Entity
|
||||
public class MenuOption extends BaseTimeEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
@GenericGenerator(name = "uuid2", strategy = "uuid2")
|
||||
@Column(name = "option_id", columnDefinition = "BINARY(16)")
|
||||
private UUID optionId;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "menu_id")
|
||||
private CafeMenu cafeMenu;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CafeResponseDto {
|
||||
|
||||
private UUID cafeId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String address;
|
||||
|
||||
private String phoneNumber;
|
||||
|
||||
private Double totalRate;
|
||||
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.error;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class CafeExceptionHandler {
|
||||
|
||||
@ExceptionHandler(CafeNotFoundException.class)
|
||||
public ResponseEntity<String> handleNotFound(CafeNotFoundException exception) {
|
||||
return ResponseEntity.badRequest().body(exception.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.error;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class CafeNotFoundException extends RuntimeException {
|
||||
public CafeNotFoundException(UUID cafeId) {
|
||||
super("Cafe[" + cafeId + "] is not found");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.repository;
|
||||
|
||||
import io.beaniejoy.dongnecafe.cafe.domain.Cafe;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface CafeRepository extends JpaRepository<Cafe, UUID> {
|
||||
|
||||
Page<Cafe> findAll(Pageable pageable);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package io.beaniejoy.dongnecafe.cafe.service;
|
||||
|
||||
import io.beaniejoy.dongnecafe.cafe.domain.Cafe;
|
||||
import io.beaniejoy.dongnecafe.cafe.dto.CafeResponseDto;
|
||||
import io.beaniejoy.dongnecafe.cafe.error.CafeNotFoundException;
|
||||
import io.beaniejoy.dongnecafe.cafe.repository.CafeRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CafeService {
|
||||
|
||||
private final CafeRepository cafeRepository;
|
||||
|
||||
public List<CafeResponseDto> getCafeList(Pageable pageable) {
|
||||
|
||||
Page<Cafe> cafeListWithPagination = cafeRepository.findAll(pageable);
|
||||
|
||||
return cafeListWithPagination.stream()
|
||||
.map(Cafe::toResponseDto)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public CafeResponseDto getCafeByCafeId(UUID cafeId) {
|
||||
Cafe cafe = cafeRepository.findById(cafeId)
|
||||
.orElseThrow(() -> new CafeNotFoundException(cafeId));
|
||||
|
||||
return cafe.toResponseDto();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.beaniejoy.dongnecafe.common.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaAuditing
|
||||
public class AuditingConfig {
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.beaniejoy.dongnecafe.common.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.EntityListeners;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@MappedSuperclass
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
public abstract class BaseTimeEntity {
|
||||
@CreatedDate
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
@LastModifiedDate
|
||||
private LocalDateTime updatedDate;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
6
src/main/resources/application.yml
Normal file
6
src/main/resources/application.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
spring:
|
||||
jpa:
|
||||
properties:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
show-sql: true
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.beaniejoy.dongecafe;
|
||||
package io.beaniejoy.dongnecafe;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
Reference in New Issue
Block a user