From 96631ee5076f1cb7cff71503710e2cc735edfd6d Mon Sep 17 00:00:00 2001 From: jyjang Date: Sun, 19 Apr 2020 15:37:29 +0900 Subject: [PATCH] first commit --- app/Dockerfile | 4 + app/cloudbuild.yaml | 103 ++++++++++++++++++ app/kubernetes/deployment.yml | 37 +++++++ app/kubernetes/service.yaml | 12 ++ app/pom.xml | 90 +++++++++++++++ .../main/java/fooddelivery/AbstractEvent.java | 78 +++++++++++++ .../main/java/fooddelivery/Application.java | 18 +++ app/src/main/java/fooddelivery/Order.java | 57 ++++++++++ .../main/java/fooddelivery/PolicyHandler.java | 22 ++++ .../config/kafka/KafkaProcessor.java | 19 ++++ .../java/fooddelivery/external/결제이력.java | 33 ++++++ .../external/결제이력Service.java | 21 ++++ .../external/결제이력ServiceFallback.java | 13 +++ .../main/java/fooddelivery/배달시작됨.java | 39 +++++++ .../java/fooddelivery/주문Controller.java | 15 +++ .../java/fooddelivery/주문Repository.java | 8 ++ app/src/main/java/fooddelivery/주문됨.java | 34 ++++++ .../main/java/fooddelivery/주문취소됨.java | 18 +++ app/src/main/resources/application.yml | 82 ++++++++++++++ customer/Dockerfile.command.handler | 9 ++ customer/Dockerfile.policy.handler | 9 ++ customer/LICENSE | 21 ++++ customer/README.md | 1 + customer/command-handler.py | 18 +++ customer/kubernetes/deployment.yml | 23 ++++ customer/kubernetes/service.yaml | 12 ++ customer/policy-handler.py | 17 +++ customer/requirements.txt | 4 + gateway/Dockerfile | 4 + gateway/cloudbuild.yaml | 85 +++++++++++++++ gateway/pom.xml | 54 +++++++++ .../main/java/com/example/Application.java | 18 +++ gateway/src/main/resources/application.yml | 74 +++++++++++++ pay/Dockerfile | 4 + pay/cloudbuild.yaml | 103 ++++++++++++++++++ pay/kubernetes/deployment.yml | 37 +++++++ pay/kubernetes/service.yaml | 12 ++ pay/pom.xml | 90 +++++++++++++++ .../main/java/fooddelivery/AbstractEvent.java | 78 +++++++++++++ .../main/java/fooddelivery/Application.java | 18 +++ .../main/java/fooddelivery/PolicyHandler.java | 22 ++++ .../config/kafka/KafkaProcessor.java | 19 ++++ .../main/java/fooddelivery/결제승인됨.java | 34 ++++++ pay/src/main/java/fooddelivery/결제이력.java | 57 ++++++++++ .../java/fooddelivery/결제이력Controller.java | 15 +++ .../java/fooddelivery/결제이력Repository.java | 8 ++ .../main/java/fooddelivery/결제취소됨.java | 18 +++ .../main/java/fooddelivery/주문취소됨.java | 15 +++ pay/src/main/resources/application.yml | 64 +++++++++++ store/Dockerfile | 4 + store/cloudbuild.yaml | 103 ++++++++++++++++++ store/kubernetes/deployment.yml | 37 +++++++ store/kubernetes/service.yaml | 12 ++ store/pom.xml | 90 +++++++++++++++ .../main/java/fooddelivery/AbstractEvent.java | 78 +++++++++++++ .../main/java/fooddelivery/Application.java | 18 +++ .../main/java/fooddelivery/PolicyHandler.java | 29 +++++ .../config/kafka/KafkaProcessor.java | 19 ++++ .../main/java/fooddelivery/결제승인됨.java | 43 ++++++++ .../main/java/fooddelivery/결제취소됨.java | 15 +++ .../main/java/fooddelivery/배달시작됨.java | 42 +++++++ .../src/main/java/fooddelivery/주문관리.java | 45 ++++++++ .../java/fooddelivery/주문관리Controller.java | 15 +++ .../java/fooddelivery/주문관리Repository.java | 8 ++ .../main/java/fooddelivery/쿠폰발행됨.java | 42 +++++++ store/src/main/resources/application.yml | 64 +++++++++++ 66 files changed, 2310 insertions(+) create mode 100755 app/Dockerfile create mode 100755 app/cloudbuild.yaml create mode 100755 app/kubernetes/deployment.yml create mode 100755 app/kubernetes/service.yaml create mode 100755 app/pom.xml create mode 100755 app/src/main/java/fooddelivery/AbstractEvent.java create mode 100755 app/src/main/java/fooddelivery/Application.java create mode 100755 app/src/main/java/fooddelivery/Order.java create mode 100755 app/src/main/java/fooddelivery/PolicyHandler.java create mode 100755 app/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java create mode 100755 app/src/main/java/fooddelivery/external/결제이력.java create mode 100755 app/src/main/java/fooddelivery/external/결제이력Service.java create mode 100644 app/src/main/java/fooddelivery/external/결제이력ServiceFallback.java create mode 100755 app/src/main/java/fooddelivery/배달시작됨.java create mode 100755 app/src/main/java/fooddelivery/주문Controller.java create mode 100755 app/src/main/java/fooddelivery/주문Repository.java create mode 100755 app/src/main/java/fooddelivery/주문됨.java create mode 100755 app/src/main/java/fooddelivery/주문취소됨.java create mode 100755 app/src/main/resources/application.yml create mode 100755 customer/Dockerfile.command.handler create mode 100755 customer/Dockerfile.policy.handler create mode 100755 customer/LICENSE create mode 100755 customer/README.md create mode 100755 customer/command-handler.py create mode 100755 customer/kubernetes/deployment.yml create mode 100755 customer/kubernetes/service.yaml create mode 100755 customer/policy-handler.py create mode 100755 customer/requirements.txt create mode 100755 gateway/Dockerfile create mode 100755 gateway/cloudbuild.yaml create mode 100755 gateway/pom.xml create mode 100755 gateway/src/main/java/com/example/Application.java create mode 100755 gateway/src/main/resources/application.yml create mode 100755 pay/Dockerfile create mode 100755 pay/cloudbuild.yaml create mode 100755 pay/kubernetes/deployment.yml create mode 100755 pay/kubernetes/service.yaml create mode 100755 pay/pom.xml create mode 100755 pay/src/main/java/fooddelivery/AbstractEvent.java create mode 100755 pay/src/main/java/fooddelivery/Application.java create mode 100755 pay/src/main/java/fooddelivery/PolicyHandler.java create mode 100755 pay/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java create mode 100755 pay/src/main/java/fooddelivery/결제승인됨.java create mode 100755 pay/src/main/java/fooddelivery/결제이력.java create mode 100755 pay/src/main/java/fooddelivery/결제이력Controller.java create mode 100755 pay/src/main/java/fooddelivery/결제이력Repository.java create mode 100755 pay/src/main/java/fooddelivery/결제취소됨.java create mode 100755 pay/src/main/java/fooddelivery/주문취소됨.java create mode 100755 pay/src/main/resources/application.yml create mode 100755 store/Dockerfile create mode 100755 store/cloudbuild.yaml create mode 100755 store/kubernetes/deployment.yml create mode 100755 store/kubernetes/service.yaml create mode 100755 store/pom.xml create mode 100755 store/src/main/java/fooddelivery/AbstractEvent.java create mode 100755 store/src/main/java/fooddelivery/Application.java create mode 100755 store/src/main/java/fooddelivery/PolicyHandler.java create mode 100755 store/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java create mode 100755 store/src/main/java/fooddelivery/결제승인됨.java create mode 100755 store/src/main/java/fooddelivery/결제취소됨.java create mode 100755 store/src/main/java/fooddelivery/배달시작됨.java create mode 100755 store/src/main/java/fooddelivery/주문관리.java create mode 100755 store/src/main/java/fooddelivery/주문관리Controller.java create mode 100755 store/src/main/java/fooddelivery/주문관리Repository.java create mode 100755 store/src/main/java/fooddelivery/쿠폰발행됨.java create mode 100755 store/src/main/resources/application.yml diff --git a/app/Dockerfile b/app/Dockerfile new file mode 100755 index 0000000..a02fed4 --- /dev/null +++ b/app/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:8u212-jdk-alpine +COPY target/*SNAPSHOT.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java","-Xmx400M","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar","--spring.profiles.active=docker"] diff --git a/app/cloudbuild.yaml b/app/cloudbuild.yaml new file mode 100755 index 0000000..4ee6822 --- /dev/null +++ b/app/cloudbuild.yaml @@ -0,0 +1,103 @@ +steps: + ### Test + # - id: 'test' + # name: 'gcr.io/cloud-builders/mvn' + # args: [ + # 'test', + # '-Dspring.profiles.active=test' + # ] + ### Build + - id: 'build' + name: 'gcr.io/cloud-builders/mvn' + args: [ + 'clean', + 'package' + # '-Dmaven.test.skip=true' + ] + # waitFor: ['test'] + ### docker Build + - id: 'docker build' + name: 'gcr.io/cloud-builders/docker' + args: + - 'build' + - '--tag=gcr.io/$PROJECT_ID/$_PROJECT_NAME:latest' + - '.' + ### Publish + - id: 'publish' + name: 'gcr.io/cloud-builders/docker' + entrypoint: 'bash' + args: + - '-c' + - | + docker push gcr.io/$PROJECT_ID/$_PROJECT_NAME:latest + ### deploy + - id: 'deploy' + name: 'gcr.io/cloud-builders/gcloud' + entrypoint: 'bash' + args: + - '-c' + - | + PROJECT=$$(gcloud config get-value core/project) + gcloud container clusters get-credentials "$${CLOUDSDK_CONTAINER_CLUSTER}" \ + --project "$${PROJECT}" \ + --zone "$${CLOUDSDK_COMPUTE_ZONE}" + cat < + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.9.RELEASE + + + fooddelivery + app + 0.0.1-SNAPSHOT + app + Demo project for Spring Boot + + + 1.8 + Greenwich.RELEASE + Germantown.SR1 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-data-rest + + + + com.h2database + h2 + runtime + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + org.springframework.cloud + spring-cloud-stream-dependencies + ${spring-cloud-stream.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/app/src/main/java/fooddelivery/AbstractEvent.java b/app/src/main/java/fooddelivery/AbstractEvent.java new file mode 100755 index 0000000..c7d81cb --- /dev/null +++ b/app/src/main/java/fooddelivery/AbstractEvent.java @@ -0,0 +1,78 @@ +package fooddelivery; + +import fooddelivery.config.kafka.KafkaProcessor; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.MimeTypeUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class AbstractEvent { + + String eventType; + String timestamp; + + public AbstractEvent(){ + this.setEventType(this.getClass().getSimpleName()); + SimpleDateFormat defaultSimpleDateFormat = new SimpleDateFormat("YYYYMMddHHmmss"); + this.timestamp = defaultSimpleDateFormat.format(new Date()); + } + + public String toJson(){ + ObjectMapper objectMapper = new ObjectMapper(); + String json = null; + + try { + json = objectMapper.writeValueAsString(this); + } catch (JsonProcessingException e) { + throw new RuntimeException("JSON format exception", e); + } + + return json; + } + + public void publish(){ + this.publish(this.toJson()); + } + public void publish(String json){ + if( json != null ){ + + /** + * spring streams 방식 + */ + KafkaProcessor processor = Application.applicationContext.getBean(KafkaProcessor.class); + MessageChannel outputChannel = processor.outboundTopic(); + + outputChannel.send(MessageBuilder + .withPayload(json) + .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) + .build()); + + } + } + + + public String getEventType() { + return eventType; + } + + public void setEventType(String eventType) { + this.eventType = eventType; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public boolean isMe(){ + return getEventType().equals(getClass().getSimpleName()); + } +} diff --git a/app/src/main/java/fooddelivery/Application.java b/app/src/main/java/fooddelivery/Application.java new file mode 100755 index 0000000..6aa7e0b --- /dev/null +++ b/app/src/main/java/fooddelivery/Application.java @@ -0,0 +1,18 @@ +package fooddelivery; +import fooddelivery.config.kafka.KafkaProcessor; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.openfeign.EnableFeignClients; + + +@SpringBootApplication +@EnableBinding(KafkaProcessor.class) +@EnableFeignClients +public class Application { + protected static ApplicationContext applicationContext; + public static void main(String[] args) { + applicationContext = SpringApplication.run(Application.class, args); + } +} diff --git a/app/src/main/java/fooddelivery/Order.java b/app/src/main/java/fooddelivery/Order.java new file mode 100755 index 0000000..ac4be60 --- /dev/null +++ b/app/src/main/java/fooddelivery/Order.java @@ -0,0 +1,57 @@ +package fooddelivery; + +import javax.persistence.*; +import org.springframework.beans.BeanUtils; + +@Entity +@Table(name="주문_table") +public class Order { + + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + private Long id; + private String item; + private Integer 수량; + + @PostPersist + public void onPostPersist(){ + + //Following code causes dependency to external APIs + // it is NOT A GOOD PRACTICE. instead, Event-Policy mapping is recommended. + + fooddelivery.external.결제이력 결제이력 = new fooddelivery.external.결제이력(); + // mappings goes here + Application.applicationContext.getBean(fooddelivery.external.결제이력Service.class) + .결제(결제이력); + + + } + + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String getItem() { + return item; + } + + public void setItem(String item) { + this.item = item; + } + public Integer get수량() { + return 수량; + } + + public void set수량(Integer 수량) { + this.수량 = 수량; + } + + + + +} diff --git a/app/src/main/java/fooddelivery/PolicyHandler.java b/app/src/main/java/fooddelivery/PolicyHandler.java new file mode 100755 index 0000000..94642fc --- /dev/null +++ b/app/src/main/java/fooddelivery/PolicyHandler.java @@ -0,0 +1,22 @@ +package fooddelivery; + +import fooddelivery.config.kafka.KafkaProcessor; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Service; + +@Service +public class PolicyHandler{ + + @StreamListener(KafkaProcessor.INPUT) + public void whenever배달시작됨_주문상태변경(@Payload 배달시작됨 배달시작됨){ + + if(배달시작됨.isMe()){ + System.out.println("##### listener 주문상태변경 : " + 배달시작됨.toJson()); + } + } + +} diff --git a/app/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java b/app/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java new file mode 100755 index 0000000..c5b7b46 --- /dev/null +++ b/app/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java @@ -0,0 +1,19 @@ +package fooddelivery.config.kafka; + +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.cloud.stream.annotation.Output; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.SubscribableChannel; + +public interface KafkaProcessor { + + String INPUT = "event-in"; + String OUTPUT = "event-out"; + + @Input(INPUT) + SubscribableChannel inboundTopic(); + + @Output(OUTPUT) + MessageChannel outboundTopic(); + +} diff --git a/app/src/main/java/fooddelivery/external/결제이력.java b/app/src/main/java/fooddelivery/external/결제이력.java new file mode 100755 index 0000000..1871c21 --- /dev/null +++ b/app/src/main/java/fooddelivery/external/결제이력.java @@ -0,0 +1,33 @@ +package fooddelivery.external; + +public class 결제이력 { + + private Long id; + private String orderId; + private Double 금액; + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + public Double get금액() { + return 금액; + } + + public void set금액(Double 금액) { + this.금액 = 금액; + } + +} + diff --git a/app/src/main/java/fooddelivery/external/결제이력Service.java b/app/src/main/java/fooddelivery/external/결제이력Service.java new file mode 100755 index 0000000..c1c4965 --- /dev/null +++ b/app/src/main/java/fooddelivery/external/결제이력Service.java @@ -0,0 +1,21 @@ + +package fooddelivery.external; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import java.util.Date; + +/** + * Created by uengine on 2018. 11. 21.. + */ + +@FeignClient(name="pay", url="http://localhost:8082")//, fallback = 결제이력ServiceFallback.class) +public interface 결제이력Service { + + @RequestMapping(method= RequestMethod.POST, path="/결제이력s") + public void 결제(@RequestBody 결제이력 결제이력); + +} \ No newline at end of file diff --git a/app/src/main/java/fooddelivery/external/결제이력ServiceFallback.java b/app/src/main/java/fooddelivery/external/결제이력ServiceFallback.java new file mode 100644 index 0000000..bcfd1ab --- /dev/null +++ b/app/src/main/java/fooddelivery/external/결제이력ServiceFallback.java @@ -0,0 +1,13 @@ +package fooddelivery.external; + +/** + * Created by uengine on 2020. 4. 18.. + */ +public class 결제이력ServiceFallback implements 결제이력Service { + @Override + public void 결제(결제이력 주문) { + //do nothing if you want to forgive it + + System.out.println("Circuit breaker has been opened. Fallback returned instead."); + } +} diff --git a/app/src/main/java/fooddelivery/배달시작됨.java b/app/src/main/java/fooddelivery/배달시작됨.java new file mode 100755 index 0000000..0ff59c9 --- /dev/null +++ b/app/src/main/java/fooddelivery/배달시작됨.java @@ -0,0 +1,39 @@ +package fooddelivery; + + +public class 배달시작됨 extends AbstractEvent { + + private Long id; + private String 요리종류; + private String 배달지주소; + private String orderId; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String get요리종류() { + return 요리종류; + } + + public void set요리종류(String 요리종류) { + this.요리종류 = 요리종류; + } + public String get배달지주소() { + return 배달지주소; + } + + public void set배달지주소(String 배달지주소) { + this.배달지주소 = 배달지주소; + } + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } +} diff --git a/app/src/main/java/fooddelivery/주문Controller.java b/app/src/main/java/fooddelivery/주문Controller.java new file mode 100755 index 0000000..9712dd5 --- /dev/null +++ b/app/src/main/java/fooddelivery/주문Controller.java @@ -0,0 +1,15 @@ +package fooddelivery; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + + @RestController + public class 주문Controller { + + } diff --git a/app/src/main/java/fooddelivery/주문Repository.java b/app/src/main/java/fooddelivery/주문Repository.java new file mode 100755 index 0000000..b749770 --- /dev/null +++ b/app/src/main/java/fooddelivery/주문Repository.java @@ -0,0 +1,8 @@ +package fooddelivery; + +import org.springframework.data.repository.PagingAndSortingRepository; + +public interface 주문Repository extends PagingAndSortingRepository{ + + +} \ No newline at end of file diff --git a/app/src/main/java/fooddelivery/주문됨.java b/app/src/main/java/fooddelivery/주문됨.java new file mode 100755 index 0000000..da17a56 --- /dev/null +++ b/app/src/main/java/fooddelivery/주문됨.java @@ -0,0 +1,34 @@ +package fooddelivery; + +public class 주문됨 extends AbstractEvent { + + private Long id; + private String 품목; + private Integer 수량; + + public 주문됨(){ + super(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String get품목() { + return 품목; + } + + public void set품목(String 품목) { + this.품목 = 품목; + } + public Integer get수량() { + return 수량; + } + + public void set수량(Integer 수량) { + this.수량 = 수량; + } +} diff --git a/app/src/main/java/fooddelivery/주문취소됨.java b/app/src/main/java/fooddelivery/주문취소됨.java new file mode 100755 index 0000000..fdc2a52 --- /dev/null +++ b/app/src/main/java/fooddelivery/주문취소됨.java @@ -0,0 +1,18 @@ +package fooddelivery; + +public class 주문취소됨 extends AbstractEvent { + + private Long id; + + public 주문취소됨(){ + super(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/app/src/main/resources/application.yml b/app/src/main/resources/application.yml new file mode 100755 index 0000000..dd5a7d0 --- /dev/null +++ b/app/src/main/resources/application.yml @@ -0,0 +1,82 @@ +server: + port: 8080 +--- + +spring: + profiles: default + jpa: + properties: + hibernate: + show_sql: true + format_sql: true + cloud: + stream: + kafka: + binder: + brokers: localhost:9092 + streams: + binder: + configuration: + default: + key: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + value: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + bindings: + event-in: + group: app + destination: fooddelivery + contentType: application/json + event-out: + destination: fooddelivery + contentType: application/json + +logging: + level: + org.hibernate.type: trace + org.springframework.cloud: debug +server: + port: 8081 + +feign: + hystrix: + enabled: true + +# To set thread isolation to SEMAPHORE +#hystrix: +# command: +# default: +# execution: +# isolation: +# strategy: SEMAPHORE + +hystrix: + command: + # 전역설정 + default: + execution.isolation.thread.timeoutInMilliseconds: 610 +--- + +spring: + profiles: docker + cloud: + stream: + kafka: + binder: + brokers: my-kafka.kafka.svc.cluster.local:9092 + streams: + binder: + configuration: + default: + key: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + value: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + bindings: + event-in: + group: app + destination: fooddelivery + contentType: application/json + event-out: + destination: fooddelivery + contentType: application/json diff --git a/customer/Dockerfile.command.handler b/customer/Dockerfile.command.handler new file mode 100755 index 0000000..1ec371e --- /dev/null +++ b/customer/Dockerfile.command.handler @@ -0,0 +1,9 @@ +FROM python:2.7-slim +WORKDIR /app +ADD . /app +RUN pip install --trusted-host pypi.python.org -r requirements.txt +ENV NAME World +EXPOSE 8090 +CMD ["python", "command-handler.py"] + + diff --git a/customer/Dockerfile.policy.handler b/customer/Dockerfile.policy.handler new file mode 100755 index 0000000..d0194e9 --- /dev/null +++ b/customer/Dockerfile.policy.handler @@ -0,0 +1,9 @@ +FROM python:2.7-slim +WORKDIR /app +ADD . /app +RUN pip install --trusted-host pypi.python.org -r requirements.txt +ENV NAME World +EXPOSE 8090 +CMD ["python", "policy-handler.py"] + + diff --git a/customer/LICENSE b/customer/LICENSE new file mode 100755 index 0000000..6ad0b30 --- /dev/null +++ b/customer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 msaez-template + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/customer/README.md b/customer/README.md new file mode 100755 index 0000000..bef7c17 --- /dev/null +++ b/customer/README.md @@ -0,0 +1 @@ +# python \ No newline at end of file diff --git a/customer/command-handler.py b/customer/command-handler.py new file mode 100755 index 0000000..54f1b6b --- /dev/null +++ b/customer/command-handler.py @@ -0,0 +1,18 @@ +from flask import Flask +from redis import Redis, RedisError +from kafka import KafkaConsumer +import os +import socket + +app = Flask(__name__) + +@app.route("/customer") +def hello(): + + html = "

Hello {name}!

" \ + "Hostname: {hostname}
" + + return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname()) + +if __name__ == "__main__": + app.run(host='0.0.0.0', port=8084) diff --git a/customer/kubernetes/deployment.yml b/customer/kubernetes/deployment.yml new file mode 100755 index 0000000..b56ed2c --- /dev/null +++ b/customer/kubernetes/deployment.yml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: customer + labels: + app: customer +spec: + replicas: 1 + selector: + matchLabels: + app: customer + template: + metadata: + labels: + app: customer + spec: + containers: + - name: command-handler + image: username/customer-command-handler:latest + ports: + - containerPort: 8084 + - name: policy-handler + image: username/customer-policy-handler:latest diff --git a/customer/kubernetes/service.yaml b/customer/kubernetes/service.yaml new file mode 100755 index 0000000..3867018 --- /dev/null +++ b/customer/kubernetes/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: customer + labels: + app: customer +spec: + ports: + - port: 8080 + targetPort: 8080 + selector: + app: customer \ No newline at end of file diff --git a/customer/policy-handler.py b/customer/policy-handler.py new file mode 100755 index 0000000..96818df --- /dev/null +++ b/customer/policy-handler.py @@ -0,0 +1,17 @@ +from flask import Flask +from redis import Redis, RedisError +from kafka import KafkaConsumer +import os +import socket + + +# To consume latest messages and auto-commit offsets +consumer = KafkaConsumer('fooddelivery', + group_id='', + bootstrap_servers=['localhost:9092']) +for message in consumer: + print ("%s:%d:%d: key=%s value=%s" % (message.topic, message.partition, + message.offset, message.key, + message.value)) + + diff --git a/customer/requirements.txt b/customer/requirements.txt new file mode 100755 index 0000000..1db1132 --- /dev/null +++ b/customer/requirements.txt @@ -0,0 +1,4 @@ +Flask +Redis +kafka-python + diff --git a/gateway/Dockerfile b/gateway/Dockerfile new file mode 100755 index 0000000..a02fed4 --- /dev/null +++ b/gateway/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:8u212-jdk-alpine +COPY target/*SNAPSHOT.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java","-Xmx400M","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar","--spring.profiles.active=docker"] diff --git a/gateway/cloudbuild.yaml b/gateway/cloudbuild.yaml new file mode 100755 index 0000000..8c8f2a9 --- /dev/null +++ b/gateway/cloudbuild.yaml @@ -0,0 +1,85 @@ +steps: + - id: 'build' + name: 'gcr.io/cloud-builders/mvn' + args: [ + 'clean', + 'package', + '-Dmaven.test.skip=true' + ] + ### Build + - id: 'docker build' + name: 'gcr.io/cloud-builders/docker' + entrypoint: 'bash' + args: + - '-c' + - | + echo '$COMMIT_SHA =' $COMMIT_SHA + docker build -t gcr.io/$PROJECT_ID/$_PROJECT_NAME:$COMMIT_SHA . + ### Test + ### Publish + - id: 'publish' + name: 'gcr.io/cloud-builders/docker' + entrypoint: 'bash' + args: + - '-c' + - | + docker push gcr.io/$PROJECT_ID/$_PROJECT_NAME:$COMMIT_SHA + ### deploy + - id: 'deploy' + name: 'gcr.io/cloud-builders/gcloud' + entrypoint: 'bash' + args: + - '-c' + - | + PROJECT=$$(gcloud config get-value core/project) + gcloud container clusters get-credentials "$${CLOUDSDK_CONTAINER_CLUSTER}" \ + --project "$${PROJECT}" \ + --zone "$${CLOUDSDK_COMPUTE_ZONE}" + + cat < + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.1.RELEASE + + + com.example + boot-camp-gateway + 0.0.1-SNAPSHOT + boot-camp-gateway + + + 1.8 + Greenwich.SR2 + + + + + + org.springframework.boot + spring-boot-actuator + + + org.springframework.cloud + spring-cloud-starter-gateway + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/gateway/src/main/java/com/example/Application.java b/gateway/src/main/java/com/example/Application.java new file mode 100755 index 0000000..e8ff20f --- /dev/null +++ b/gateway/src/main/java/com/example/Application.java @@ -0,0 +1,18 @@ +package com.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; + +@SpringBootApplication +public class Application { + + public static ApplicationContext applicationContext; + public static void main(String[] args) { + applicationContext = SpringApplication.run(Application.class, args); + } + + +} + + diff --git a/gateway/src/main/resources/application.yml b/gateway/src/main/resources/application.yml new file mode 100755 index 0000000..1dfae42 --- /dev/null +++ b/gateway/src/main/resources/application.yml @@ -0,0 +1,74 @@ +server: + port: 8088 + +--- + +spring: + profiles: default + cloud: + gateway: + routes: + - id: app + uri: http://localhost:8081 + predicates: + - Path=/주문/** /메뉴판/**/통합주문상태/** + - id: pay + uri: http://localhost:8082 + predicates: + - Path=/결제이력/** + - id: store + uri: http://localhost:8083 + predicates: + - Path=/주문관리/** /주문상세보기/** + - id: customer + uri: http://localhost:8084 + predicates: + - Path= + globalcors: + corsConfigurations: + '[/**]': + allowedOrigins: + - "*" + allowedMethods: + - "*" + allowedHeaders: + - "*" + allowCredentials: true + + +--- + +spring: + profiles: docker + cloud: + gateway: + routes: + - id: app + uri: http://app:8080 + predicates: + - Path=/주문/** /메뉴판/**/통합주문상태/** + - id: pay + uri: http://pay:8080 + predicates: + - Path=/결제이력/** + - id: store + uri: http://store:8080 + predicates: + - Path=/주문관리/** /주문상세보기/** + - id: customer + uri: http://customer:8080 + predicates: + - Path= + globalcors: + corsConfigurations: + '[/**]': + allowedOrigins: + - "*" + allowedMethods: + - "*" + allowedHeaders: + - "*" + allowCredentials: true + +server: + port: 8080 diff --git a/pay/Dockerfile b/pay/Dockerfile new file mode 100755 index 0000000..a02fed4 --- /dev/null +++ b/pay/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:8u212-jdk-alpine +COPY target/*SNAPSHOT.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java","-Xmx400M","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar","--spring.profiles.active=docker"] diff --git a/pay/cloudbuild.yaml b/pay/cloudbuild.yaml new file mode 100755 index 0000000..43c8e81 --- /dev/null +++ b/pay/cloudbuild.yaml @@ -0,0 +1,103 @@ +steps: + ### Test + # - id: 'test' + # name: 'gcr.io/cloud-builders/mvn' + # args: [ + # 'test', + # '-Dspring.profiles.active=test' + # ] + ### Build + - id: 'build' + name: 'gcr.io/cloud-builders/mvn' + args: [ + 'clean', + 'package' + # '-Dmaven.test.skip=true' + ] + # waitFor: ['test'] + ### docker Build + - id: 'docker build' + name: 'gcr.io/cloud-builders/docker' + args: + - 'build' + - '--tag=gcr.io/$PROJECT_ID/$_PROJECT_NAME:latest' + - '.' + ### Publish + - id: 'publish' + name: 'gcr.io/cloud-builders/docker' + entrypoint: 'bash' + args: + - '-c' + - | + docker push gcr.io/$PROJECT_ID/$_PROJECT_NAME:latest + ### deploy + - id: 'deploy' + name: 'gcr.io/cloud-builders/gcloud' + entrypoint: 'bash' + args: + - '-c' + - | + PROJECT=$$(gcloud config get-value core/project) + gcloud container clusters get-credentials "$${CLOUDSDK_CONTAINER_CLUSTER}" \ + --project "$${PROJECT}" \ + --zone "$${CLOUDSDK_COMPUTE_ZONE}" + cat < + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.9.RELEASE + + + fooddelivery + pay + 0.0.1-SNAPSHOT + pay + Demo project for Spring Boot + + + 1.8 + Greenwich.RELEASE + Germantown.SR1 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-data-rest + + + + com.h2database + h2 + runtime + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + org.springframework.cloud + spring-cloud-stream-dependencies + ${spring-cloud-stream.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/pay/src/main/java/fooddelivery/AbstractEvent.java b/pay/src/main/java/fooddelivery/AbstractEvent.java new file mode 100755 index 0000000..c7d81cb --- /dev/null +++ b/pay/src/main/java/fooddelivery/AbstractEvent.java @@ -0,0 +1,78 @@ +package fooddelivery; + +import fooddelivery.config.kafka.KafkaProcessor; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.MimeTypeUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class AbstractEvent { + + String eventType; + String timestamp; + + public AbstractEvent(){ + this.setEventType(this.getClass().getSimpleName()); + SimpleDateFormat defaultSimpleDateFormat = new SimpleDateFormat("YYYYMMddHHmmss"); + this.timestamp = defaultSimpleDateFormat.format(new Date()); + } + + public String toJson(){ + ObjectMapper objectMapper = new ObjectMapper(); + String json = null; + + try { + json = objectMapper.writeValueAsString(this); + } catch (JsonProcessingException e) { + throw new RuntimeException("JSON format exception", e); + } + + return json; + } + + public void publish(){ + this.publish(this.toJson()); + } + public void publish(String json){ + if( json != null ){ + + /** + * spring streams 방식 + */ + KafkaProcessor processor = Application.applicationContext.getBean(KafkaProcessor.class); + MessageChannel outputChannel = processor.outboundTopic(); + + outputChannel.send(MessageBuilder + .withPayload(json) + .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) + .build()); + + } + } + + + public String getEventType() { + return eventType; + } + + public void setEventType(String eventType) { + this.eventType = eventType; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public boolean isMe(){ + return getEventType().equals(getClass().getSimpleName()); + } +} diff --git a/pay/src/main/java/fooddelivery/Application.java b/pay/src/main/java/fooddelivery/Application.java new file mode 100755 index 0000000..6aa7e0b --- /dev/null +++ b/pay/src/main/java/fooddelivery/Application.java @@ -0,0 +1,18 @@ +package fooddelivery; +import fooddelivery.config.kafka.KafkaProcessor; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.openfeign.EnableFeignClients; + + +@SpringBootApplication +@EnableBinding(KafkaProcessor.class) +@EnableFeignClients +public class Application { + protected static ApplicationContext applicationContext; + public static void main(String[] args) { + applicationContext = SpringApplication.run(Application.class, args); + } +} diff --git a/pay/src/main/java/fooddelivery/PolicyHandler.java b/pay/src/main/java/fooddelivery/PolicyHandler.java new file mode 100755 index 0000000..8a428cf --- /dev/null +++ b/pay/src/main/java/fooddelivery/PolicyHandler.java @@ -0,0 +1,22 @@ +package fooddelivery; + +import fooddelivery.config.kafka.KafkaProcessor; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Service; + +@Service +public class PolicyHandler{ + + @StreamListener(KafkaProcessor.INPUT) + public void whenever주문취소됨_결재취소함(@Payload 주문취소됨 주문취소됨){ + + if(주문취소됨.isMe()){ + System.out.println("##### listener 결재취소함 : " + 주문취소됨.toJson()); + } + } + +} diff --git a/pay/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java b/pay/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java new file mode 100755 index 0000000..c5b7b46 --- /dev/null +++ b/pay/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java @@ -0,0 +1,19 @@ +package fooddelivery.config.kafka; + +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.cloud.stream.annotation.Output; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.SubscribableChannel; + +public interface KafkaProcessor { + + String INPUT = "event-in"; + String OUTPUT = "event-out"; + + @Input(INPUT) + SubscribableChannel inboundTopic(); + + @Output(OUTPUT) + MessageChannel outboundTopic(); + +} diff --git a/pay/src/main/java/fooddelivery/결제승인됨.java b/pay/src/main/java/fooddelivery/결제승인됨.java new file mode 100755 index 0000000..ce3de68 --- /dev/null +++ b/pay/src/main/java/fooddelivery/결제승인됨.java @@ -0,0 +1,34 @@ +package fooddelivery; + +public class 결제승인됨 extends AbstractEvent { + + private Long id; + private String orderId; + private Double 금액; + + public 결제승인됨(){ + super(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + public Double get금액() { + return 금액; + } + + public void set금액(Double 금액) { + this.금액 = 금액; + } +} diff --git a/pay/src/main/java/fooddelivery/결제이력.java b/pay/src/main/java/fooddelivery/결제이력.java new file mode 100755 index 0000000..fb2065a --- /dev/null +++ b/pay/src/main/java/fooddelivery/결제이력.java @@ -0,0 +1,57 @@ +package fooddelivery; + +import javax.persistence.*; +import org.springframework.beans.BeanUtils; +import java.util.List; + +@Entity +@Table(name="결제이력_table") +public class 결제이력 { + + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + private Long id; + private String orderId; + private Double 금액; + + @PrePersist + public void onPrePersist(){ + 결제승인됨 결제승인됨 = new 결제승인됨(); + BeanUtils.copyProperties(this, 결제승인됨); + 결제승인됨.publish(); + + + try { + Thread.currentThread().sleep((long) (400 + Math.random() * 220)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + public Double get금액() { + return 금액; + } + + public void set금액(Double 금액) { + this.금액 = 금액; + } + + + + +} diff --git a/pay/src/main/java/fooddelivery/결제이력Controller.java b/pay/src/main/java/fooddelivery/결제이력Controller.java new file mode 100755 index 0000000..602e972 --- /dev/null +++ b/pay/src/main/java/fooddelivery/결제이력Controller.java @@ -0,0 +1,15 @@ +package fooddelivery; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + + @RestController + public class 결제이력Controller { + + } diff --git a/pay/src/main/java/fooddelivery/결제이력Repository.java b/pay/src/main/java/fooddelivery/결제이력Repository.java new file mode 100755 index 0000000..9a9e521 --- /dev/null +++ b/pay/src/main/java/fooddelivery/결제이력Repository.java @@ -0,0 +1,8 @@ +package fooddelivery; + +import org.springframework.data.repository.PagingAndSortingRepository; + +public interface 결제이력Repository extends PagingAndSortingRepository<결제이력, Long>{ + + +} \ No newline at end of file diff --git a/pay/src/main/java/fooddelivery/결제취소됨.java b/pay/src/main/java/fooddelivery/결제취소됨.java new file mode 100755 index 0000000..e3682ce --- /dev/null +++ b/pay/src/main/java/fooddelivery/결제취소됨.java @@ -0,0 +1,18 @@ +package fooddelivery; + +public class 결제취소됨 extends AbstractEvent { + + private Long id; + + public 결제취소됨(){ + super(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/pay/src/main/java/fooddelivery/주문취소됨.java b/pay/src/main/java/fooddelivery/주문취소됨.java new file mode 100755 index 0000000..cad61b3 --- /dev/null +++ b/pay/src/main/java/fooddelivery/주문취소됨.java @@ -0,0 +1,15 @@ +package fooddelivery; + + +public class 주문취소됨 extends AbstractEvent { + + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/pay/src/main/resources/application.yml b/pay/src/main/resources/application.yml new file mode 100755 index 0000000..b7ea465 --- /dev/null +++ b/pay/src/main/resources/application.yml @@ -0,0 +1,64 @@ +server: + port: 8080 +--- + +spring: + profiles: default + jpa: + properties: + hibernate: + show_sql: true + format_sql: true + cloud: + stream: + kafka: + binder: + brokers: localhost:9092 + streams: + binder: + configuration: + default: + key: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + value: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + bindings: + event-in: + group: pay + destination: fooddelivery + contentType: application/json + event-out: + destination: fooddelivery + contentType: application/json + +logging: + level: + org.hibernate.type: trace + org.springframework.cloud: debug +server: + port: 8082 +--- + +spring: + profiles: docker + cloud: + stream: + kafka: + binder: + brokers: my-kafka.kafka.svc.cluster.local:9092 + streams: + binder: + configuration: + default: + key: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + value: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + bindings: + event-in: + group: pay + destination: fooddelivery + contentType: application/json + event-out: + destination: fooddelivery + contentType: application/json diff --git a/store/Dockerfile b/store/Dockerfile new file mode 100755 index 0000000..a02fed4 --- /dev/null +++ b/store/Dockerfile @@ -0,0 +1,4 @@ +FROM openjdk:8u212-jdk-alpine +COPY target/*SNAPSHOT.jar app.jar +EXPOSE 8080 +ENTRYPOINT ["java","-Xmx400M","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar","--spring.profiles.active=docker"] diff --git a/store/cloudbuild.yaml b/store/cloudbuild.yaml new file mode 100755 index 0000000..29e2b45 --- /dev/null +++ b/store/cloudbuild.yaml @@ -0,0 +1,103 @@ +steps: + ### Test + # - id: 'test' + # name: 'gcr.io/cloud-builders/mvn' + # args: [ + # 'test', + # '-Dspring.profiles.active=test' + # ] + ### Build + - id: 'build' + name: 'gcr.io/cloud-builders/mvn' + args: [ + 'clean', + 'package' + # '-Dmaven.test.skip=true' + ] + # waitFor: ['test'] + ### docker Build + - id: 'docker build' + name: 'gcr.io/cloud-builders/docker' + args: + - 'build' + - '--tag=gcr.io/$PROJECT_ID/$_PROJECT_NAME:latest' + - '.' + ### Publish + - id: 'publish' + name: 'gcr.io/cloud-builders/docker' + entrypoint: 'bash' + args: + - '-c' + - | + docker push gcr.io/$PROJECT_ID/$_PROJECT_NAME:latest + ### deploy + - id: 'deploy' + name: 'gcr.io/cloud-builders/gcloud' + entrypoint: 'bash' + args: + - '-c' + - | + PROJECT=$$(gcloud config get-value core/project) + gcloud container clusters get-credentials "$${CLOUDSDK_CONTAINER_CLUSTER}" \ + --project "$${PROJECT}" \ + --zone "$${CLOUDSDK_COMPUTE_ZONE}" + cat < + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.9.RELEASE + + + fooddelivery + store + 0.0.1-SNAPSHOT + store + Demo project for Spring Boot + + + 1.8 + Greenwich.RELEASE + Germantown.SR1 + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-data-rest + + + + com.h2database + h2 + runtime + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + org.springframework.cloud + spring-cloud-stream-dependencies + ${spring-cloud-stream.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/store/src/main/java/fooddelivery/AbstractEvent.java b/store/src/main/java/fooddelivery/AbstractEvent.java new file mode 100755 index 0000000..c7d81cb --- /dev/null +++ b/store/src/main/java/fooddelivery/AbstractEvent.java @@ -0,0 +1,78 @@ +package fooddelivery; + +import fooddelivery.config.kafka.KafkaProcessor; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.MimeTypeUtils; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class AbstractEvent { + + String eventType; + String timestamp; + + public AbstractEvent(){ + this.setEventType(this.getClass().getSimpleName()); + SimpleDateFormat defaultSimpleDateFormat = new SimpleDateFormat("YYYYMMddHHmmss"); + this.timestamp = defaultSimpleDateFormat.format(new Date()); + } + + public String toJson(){ + ObjectMapper objectMapper = new ObjectMapper(); + String json = null; + + try { + json = objectMapper.writeValueAsString(this); + } catch (JsonProcessingException e) { + throw new RuntimeException("JSON format exception", e); + } + + return json; + } + + public void publish(){ + this.publish(this.toJson()); + } + public void publish(String json){ + if( json != null ){ + + /** + * spring streams 방식 + */ + KafkaProcessor processor = Application.applicationContext.getBean(KafkaProcessor.class); + MessageChannel outputChannel = processor.outboundTopic(); + + outputChannel.send(MessageBuilder + .withPayload(json) + .setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON) + .build()); + + } + } + + + public String getEventType() { + return eventType; + } + + public void setEventType(String eventType) { + this.eventType = eventType; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public boolean isMe(){ + return getEventType().equals(getClass().getSimpleName()); + } +} diff --git a/store/src/main/java/fooddelivery/Application.java b/store/src/main/java/fooddelivery/Application.java new file mode 100755 index 0000000..6aa7e0b --- /dev/null +++ b/store/src/main/java/fooddelivery/Application.java @@ -0,0 +1,18 @@ +package fooddelivery; +import fooddelivery.config.kafka.KafkaProcessor; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.openfeign.EnableFeignClients; + + +@SpringBootApplication +@EnableBinding(KafkaProcessor.class) +@EnableFeignClients +public class Application { + protected static ApplicationContext applicationContext; + public static void main(String[] args) { + applicationContext = SpringApplication.run(Application.class, args); + } +} diff --git a/store/src/main/java/fooddelivery/PolicyHandler.java b/store/src/main/java/fooddelivery/PolicyHandler.java new file mode 100755 index 0000000..e00b4d5 --- /dev/null +++ b/store/src/main/java/fooddelivery/PolicyHandler.java @@ -0,0 +1,29 @@ +package fooddelivery; + +import fooddelivery.config.kafka.KafkaProcessor; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.stereotype.Service; + +@Service +public class PolicyHandler{ + + @StreamListener(KafkaProcessor.INPUT) + public void whenever결제승인됨_주문정보받음(@Payload 결제승인됨 결제승인됨){ + + if(결제승인됨.isMe()){ + System.out.println("##### listener 주문정보받음 : " + 결제승인됨.toJson()); + } + } + @StreamListener(KafkaProcessor.INPUT) + public void whenever결제취소됨_주문취소처리(@Payload 결제취소됨 결제취소됨){ + + if(결제취소됨.isMe()){ + System.out.println("##### listener 주문취소처리 : " + 결제취소됨.toJson()); + } + } + +} diff --git a/store/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java b/store/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java new file mode 100755 index 0000000..c5b7b46 --- /dev/null +++ b/store/src/main/java/fooddelivery/config/kafka/KafkaProcessor.java @@ -0,0 +1,19 @@ +package fooddelivery.config.kafka; + +import org.springframework.cloud.stream.annotation.Input; +import org.springframework.cloud.stream.annotation.Output; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.SubscribableChannel; + +public interface KafkaProcessor { + + String INPUT = "event-in"; + String OUTPUT = "event-out"; + + @Input(INPUT) + SubscribableChannel inboundTopic(); + + @Output(OUTPUT) + MessageChannel outboundTopic(); + +} diff --git a/store/src/main/java/fooddelivery/결제승인됨.java b/store/src/main/java/fooddelivery/결제승인됨.java new file mode 100755 index 0000000..5e20f5e --- /dev/null +++ b/store/src/main/java/fooddelivery/결제승인됨.java @@ -0,0 +1,43 @@ + +package fooddelivery; + +import javax.persistence.PrePersist; + +public class 결제승인됨 extends AbstractEvent { + + private Long id; + private String orderId; + private Double 금액; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + public Double get금액() { + return 금액; + } + + public void set금액(Double 금액) { + this.금액 = 금액; + } + + + @PrePersist + public void delay(){ + try { + Thread.currentThread().sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/store/src/main/java/fooddelivery/결제취소됨.java b/store/src/main/java/fooddelivery/결제취소됨.java new file mode 100755 index 0000000..465c1d7 --- /dev/null +++ b/store/src/main/java/fooddelivery/결제취소됨.java @@ -0,0 +1,15 @@ +package fooddelivery; + + +public class 결제취소됨 extends AbstractEvent { + + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/store/src/main/java/fooddelivery/배달시작됨.java b/store/src/main/java/fooddelivery/배달시작됨.java new file mode 100755 index 0000000..4960127 --- /dev/null +++ b/store/src/main/java/fooddelivery/배달시작됨.java @@ -0,0 +1,42 @@ +package fooddelivery; + +public class 배달시작됨 extends AbstractEvent { + + private Long id; + private String 요리종류; + private String 배달지주소; + private String orderId; + + public 배달시작됨(){ + super(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String get요리종류() { + return 요리종류; + } + + public void set요리종류(String 요리종류) { + this.요리종류 = 요리종류; + } + public String get배달지주소() { + return 배달지주소; + } + + public void set배달지주소(String 배달지주소) { + this.배달지주소 = 배달지주소; + } + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } +} diff --git a/store/src/main/java/fooddelivery/주문관리.java b/store/src/main/java/fooddelivery/주문관리.java new file mode 100755 index 0000000..1414c94 --- /dev/null +++ b/store/src/main/java/fooddelivery/주문관리.java @@ -0,0 +1,45 @@ +package fooddelivery; + +import javax.persistence.*; +import org.springframework.beans.BeanUtils; +import java.util.List; + +@Entity +@Table(name="주문관리_table") +public class 주문관리 { + + @Id + @GeneratedValue(strategy=GenerationType.AUTO) + private Long id; + + @PostPersist + public void onPostPersist(){ + 배달시작됨 배달시작됨 = new 배달시작됨(); + BeanUtils.copyProperties(this, 배달시작됨); + 배달시작됨.publish(); + + + } + + @PrePersist + public void onPrePersist(){ + 쿠폰발행됨 쿠폰발행됨 = new 쿠폰발행됨(); + BeanUtils.copyProperties(this, 쿠폰발행됨); + 쿠폰발행됨.publish(); + + + } + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + + + +} diff --git a/store/src/main/java/fooddelivery/주문관리Controller.java b/store/src/main/java/fooddelivery/주문관리Controller.java new file mode 100755 index 0000000..e79ec11 --- /dev/null +++ b/store/src/main/java/fooddelivery/주문관리Controller.java @@ -0,0 +1,15 @@ +package fooddelivery; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + + @RestController + public class 주문관리Controller { + + } diff --git a/store/src/main/java/fooddelivery/주문관리Repository.java b/store/src/main/java/fooddelivery/주문관리Repository.java new file mode 100755 index 0000000..752af7a --- /dev/null +++ b/store/src/main/java/fooddelivery/주문관리Repository.java @@ -0,0 +1,8 @@ +package fooddelivery; + +import org.springframework.data.repository.PagingAndSortingRepository; + +public interface 주문관리Repository extends PagingAndSortingRepository<주문관리, Long>{ + + +} \ No newline at end of file diff --git a/store/src/main/java/fooddelivery/쿠폰발행됨.java b/store/src/main/java/fooddelivery/쿠폰발행됨.java new file mode 100755 index 0000000..c459dba --- /dev/null +++ b/store/src/main/java/fooddelivery/쿠폰발행됨.java @@ -0,0 +1,42 @@ +package fooddelivery; + +public class 쿠폰발행됨 extends AbstractEvent { + + private Long id; + private String 요리종류; + private String 배달지주소; + private String orderId; + + public 쿠폰발행됨(){ + super(); + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + public String get요리종류() { + return 요리종류; + } + + public void set요리종류(String 요리종류) { + this.요리종류 = 요리종류; + } + public String get배달지주소() { + return 배달지주소; + } + + public void set배달지주소(String 배달지주소) { + this.배달지주소 = 배달지주소; + } + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } +} diff --git a/store/src/main/resources/application.yml b/store/src/main/resources/application.yml new file mode 100755 index 0000000..ea3b87d --- /dev/null +++ b/store/src/main/resources/application.yml @@ -0,0 +1,64 @@ +server: + port: 8080 +--- + +spring: + profiles: default + jpa: + properties: + hibernate: + show_sql: true + format_sql: true + cloud: + stream: + kafka: + binder: + brokers: localhost:9092 + streams: + binder: + configuration: + default: + key: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + value: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + bindings: + event-in: + group: store + destination: fooddelivery + contentType: application/json + event-out: + destination: fooddelivery + contentType: application/json + +logging: + level: + org.hibernate.type: trace + org.springframework.cloud: debug +server: + port: 8083 +--- + +spring: + profiles: docker + cloud: + stream: + kafka: + binder: + brokers: my-kafka.kafka.svc.cluster.local:9092 + streams: + binder: + configuration: + default: + key: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + value: + serde: org.apache.kafka.common.serialization.Serdes$StringSerde + bindings: + event-in: + group: store + destination: fooddelivery + contentType: application/json + event-out: + destination: fooddelivery + contentType: application/json