├── .gitignore ├── .travis.yml ├── README.adoc ├── build.gradle ├── modules ├── props-module │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── daggerok │ │ │ ├── PropsModuleConfig.java │ │ │ └── props │ │ │ ├── BrokerProperties.java │ │ │ ├── DatabaseProperties.java │ │ │ └── common │ │ │ └── Server.java │ │ └── resources │ │ ├── application.yml │ │ └── config │ │ └── application-props.yml └── twitter-domain-module │ ├── build.gradle │ ├── settings.gradle │ ├── src │ └── main │ │ └── java │ │ └── daggerok │ │ ├── TwitterDomainModuleApplication.java │ │ └── twitter │ │ └── TwitterRepository.java │ └── twitter-entity-module │ ├── build.gradle │ └── src │ └── main │ └── java │ └── daggerok │ ├── TwitterEntityModuleApplication.java │ └── twitter │ └── Twitter.java ├── settings.gradle ├── twitter-api-gateway ├── build.gradle └── src │ ├── main │ ├── java │ │ └── daggerok │ │ │ └── TwitterApiGatewayApplication.java │ └── resources │ │ ├── application.yml │ │ └── config │ │ ├── application-mq.yml │ │ ├── application-props.yml │ │ ├── application-server.yml │ │ └── application-twitter.yml │ └── test │ └── java │ └── daggerok │ └── TwitterApiGatewayApplicationTests.java ├── twitter-command ├── build.gradle └── src │ ├── main │ ├── java │ │ └── daggerok │ │ │ ├── TwitterCommandApplication.java │ │ │ └── twitter │ │ │ ├── TwitterCommand.java │ │ │ ├── TwitterCommandApplicationConfig.java │ │ │ └── TwitterResource.java │ └── resources │ │ ├── application.yml │ │ └── config │ │ ├── application-mq.yml │ │ ├── application-props.yml │ │ └── application-server.yml │ └── test │ └── java │ └── daggerok │ └── TwitterCommandApplicationTests.java ├── twitter-data ├── build.gradle └── src │ ├── main │ ├── java │ │ └── daggerok │ │ │ ├── TwitterDataApplication.java │ │ │ └── config │ │ │ └── TwitterDataConfig.java │ └── resources │ │ ├── application.yml │ │ └── config │ │ ├── application-db.yml │ │ ├── application-mq.yml │ │ ├── application-props.yml │ │ └── application-server.yml │ └── test │ └── java │ └── daggerok │ └── TwitterDataApplicationTests.java ├── twitter-docker ├── build.gradle ├── settings.gradle ├── twitter-docker-backing-services │ └── src │ │ └── docker-compose.yml └── twitter-docker-services │ └── src │ └── docker-compose.yml └── twitter-query ├── build.gradle └── src ├── main ├── java │ └── daggerok │ │ ├── TwitterQueryApplication.java │ │ └── twitter │ │ └── TwitterResource.java └── resources │ ├── application.yml │ └── config │ ├── application-db.yml │ ├── application-props.yml │ └── application-server.yml └── test └── java └── daggerok └── TwitterQueryApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | **/.gradle/ 3 | **/gradle/ 4 | **/build/ 5 | **/gradlew* 6 | **/.idea/ 7 | **/*.ipr 8 | **/*.iml 9 | **/*.iws 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | group: edge 2 | dist: trusty 3 | language: java 4 | jdk: oraclejdk8 5 | install: true 6 | before_install: 7 | # install docker-compose 8 | - sudo apt update 9 | - sudo apt install -y python-pip curl jq libxml2-utils 10 | - sudo pip install docker-compose 11 | - sudo usermod -aG docker $(whoami) 12 | # kill whatever punning on postgres / rabbitmq port 13 | - sudo kill $(sudo lsof -t -i:5432) | true 14 | - sudo kill $(sudo lsof -t -i:5672) | true 15 | # gradle 16 | - curl -s "https://get.sdkman.io" | bash 17 | - mkdir -p "$HOME/.sdkman/etc" 18 | - touch "$HOME/.sdkman/etc/config" 19 | - sed -i -e 's/^sdkman_auto_answer=false$/sdkman_auto_answer=true/g' "$HOME/.sdkman/etc/config" 20 | - source "$HOME/.sdkman/bin/sdkman-init.sh" 21 | - sdk use gradle 22 | - source "$HOME/.sdkman/bin/sdkman-init.sh" 23 | script: 24 | # package 25 | - gradle clean assemble 26 | # test docker files 27 | - docker-compose -f twitter-docker/twitter-docker-backing-services/src/docker-compose.yml up -d --build 28 | - sleep 3 29 | - docker-compose -f twitter-docker/twitter-docker-backing-services/src/docker-compose.yml down -v 30 | - docker-compose -f twitter-docker/twitter-docker-services/src/docker-compose.yml up -d --build 31 | - sleep 3 32 | - docker-compose -f twitter-docker/twitter-docker-services/src/docker-compose.yml down -v 33 | # compile and test with auto docker bootstrap / tear down 34 | - gradle test build 35 | # functional testing: twitter apps as linux system services 36 | - gradle backingServicesUp 37 | - sudo mkdir -p /var/twitter-{api-gateway,command,data,query}-app 38 | - sudo cp -Rf twitter-api-gateway/build/libs/*.jar /var/twitter-api-gateway-app/twitter-api-gateway-app.jar 39 | - sudo cp -Rf twitter-command/build/libs/*.jar /var/twitter-command-app/twitter-command-app.jar 40 | - sudo cp -Rf twitter-data/build/libs/*.jar /var/twitter-data-app/twitter-data-app.jar 41 | - sudo cp -Rf twitter-query/build/libs/*.jar /var/twitter-query-app/twitter-query-app.jar 42 | - sudo ln -s /var/twitter-api-gateway-app/twitter-api-gateway-app.jar /etc/init.d/twitter-api-gateway-app 43 | - sudo ln -s /var/twitter-command-app/twitter-command-app.jar /etc/init.d/twitter-command-app 44 | - sudo ln -s /var/twitter-data-app/twitter-data-app.jar /etc/init.d/twitter-data-app 45 | - sudo ln -s /var/twitter-query-app/twitter-query-app.jar /etc/init.d/twitter-query-app 46 | - sudo service twitter-api-gateway-app start 47 | - sleep 15 48 | - sudo service twitter-data-app start 49 | - sleep 15 50 | - sudo service twitter-command-app start 51 | - sleep 15 52 | - sudo service twitter-query-app start 53 | - sleep 15 54 | - curl -sS http://localhost:8882 | jq 55 | - curl -sS http://localhost:8881 -H'content-type:application/json' -d'{"data":"test1"}' 56 | - sleep 1 57 | - curl -sS http://localhost:8882 | jq 58 | - curl -sS http://localhost:8881 -H'content-type:application/json' -d'{"data":"test2"}' 59 | - curl -sS http://localhost:8881 -H'content-type:application/json' -d'{"data":"test3"}' 60 | - curl -sS http://localhost:8881 -H'content-type:application/json' -d'{"data":"test4"}' 61 | - sleep 1 62 | - curl -sS http://localhost:8882 | jq 63 | - sudo service twitter-query-app stop 64 | - sudo service twitter-data-app stop 65 | - sudo service twitter-command-app stop 66 | - sudo service twitter-api-gateway-app stop 67 | - gradle backingServicesDown 68 | # functional testing: bootstrap all twitter apps in docker compose 69 | - gradle twitterServicesUp 70 | - curl -sS http://localhost:8882 | jq 71 | - curl -sS http://localhost:8881 -H'content-type:application/json' -d'{"data":"test5"}' 72 | - sleep 1 73 | - curl -sS http://localhost:8882 | jq 74 | - curl -sS http://localhost:8881 -H'content-type:application/json' -d'{"data":"test6"}' 75 | - curl -sS http://localhost:8881 -H'content-type:application/json' -d'{"data":"test7"}' 76 | - curl -sS http://localhost:8881 -H'content-type:application/json' -d'{"data":"test8"}' 77 | - sleep 1 78 | - curl -sS http://localhost:8882 | jq 79 | - gradle twitterServicesDown 80 | before_cache: 81 | - gradle --stop 82 | - rm -rf $HOME/.gradle/caches/modules-2/modules-2.lock 83 | - rm -rf $HOME/.gradle/caches/*/plugin-resolution/ 84 | cache: 85 | directories: 86 | - $HOME/.m2/ 87 | - $HOME/.gradle/caches/ 88 | - $HOME/.gradle/wrapper/ 89 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = spring-boot-twitter image:https://travis-ci.org/daggerok/spring-boot-twitter.svg?branch=master["Build Status", link="https://travis-ci.org/daggerok/spring-boot-twitter"] 2 | 3 | == added all backing- and micro- services into sinle docker-compose 4 | 5 | see: `./twitter-docker/twitter-docker-services/src/docker-compose.yml` 6 | 7 | this repo demonstrate CQRS data transfer in REST API and messaging microservices. it's containing (async `RabbitMQ messaging` and sync `REST` microservices) data models processing: 8 | 9 | . main idea here is: each microservice doing single simple job, but doing it well, efficient and fast 10 | . actor 1: `twitter-data` - single service which is listenning creation entity command (event) and store input data into RDBMS (Postgre SQL) 11 | . actor 2: scalable `twitter-commander` service, which is send async tweets creation commands 12 | . actor 3: scalable `twitter-query` service, which is only reading tweets from read-only datasorce. in production systems should be moved out from operational RDBMS to some nosql scalable / replicateble solution, such mongodb, or any other more siutable for you 13 | . in addition: common reusable subprojects, such domain and entity api... 14 | . important keywords: 15 | - CQRS, event sourcing 16 | - reactive streams, event-driven architecture 17 | - messaging pipelines, non-blocking data processing 18 | 19 | == reads (can be improoved by spring 5 reactive programming model using Mono / Flux) 20 | 21 | [source] 22 | ---- 23 | [client] <-> (http get) <-> [twitter-query] <-> (jdbc select) <-> [rdbms] 24 | 25 | # with webflux and reactive data-source could also be non blocking: 26 | [client] <~> (http get sse) <~> [twitter-query (webflux)] <~> (reactive flux) <~> [mongo] 27 | ---- 28 | 29 | == writes (also can be improved by replacing rdbms solution with some siutable reactive nosql) 30 | 31 | [source] 32 | ---- 33 | [client] -> (http post) -> [twitter-command] ~> (send async) ~> [twitter-data] <-> (jdbc insert) <-> [rdbms] 34 | ---- 35 | 36 | note: 37 | 38 | . `\<\->` - sync processing 39 | . `<~>` - async processing 40 | 41 | == quick start 42 | 43 | [source,bash] 44 | ---- 45 | gradle --parallel bootRun 46 | 47 | http post :8881 data=test-tweet1 48 | http post :8881 data=test-tweet2 49 | 50 | http get :8882 51 | 52 | gradle --stop 53 | ---- 54 | 55 | == stack: 56 | 57 | . spring-boot 58 | . spring-data 59 | . spring-cloud-stream 60 | . RabbitMQ 61 | . Postgres 62 | . docker (docker-compose) 63 | . gradle 64 | . install spring app as linux service 65 | . CQRS and Event Sourcing 66 | . event-driven architecture 67 | . reactive streams, non-blocking data processing 68 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.5.4.RELEASE' 4 | springCloudVersion = 'Dalston.SR1' 5 | lombokVersion = '1.16.16' 6 | hibernateJpa21Api = '1.0.0.Final' 7 | } 8 | } 9 | 10 | plugins { 11 | id 'java' 12 | id 'idea' 13 | id 'eclipse' 14 | id 'cn.bestwu.propdeps-idea' version '0.0.10' 15 | id 'cn.bestwu.propdeps-eclipse' version '0.0.10' 16 | id 'cn.bestwu.propdeps' version '0.0.10' apply false 17 | id 'cn.bestwu.propdeps-maven' version '0.0.10' apply false 18 | id 'org.springframework.boot' version '1.5.4.RELEASE' apply false 19 | id 'io.spring.dependency-management' version '1.0.3.RELEASE' apply false 20 | } 21 | 22 | configure(allprojects) { p -> 23 | 24 | group 'daggerok' 25 | version '0.0.1' 26 | 27 | def self = p.toString() 28 | 29 | if (self?.contains('twitter-docker') || p.name.endsWith('modules')) { 30 | task clean { 31 | doLast { 32 | delete p.buildDir 33 | } 34 | } 35 | println "early stopped $self configuration" 36 | return 37 | } 38 | 39 | apply plugin: 'java' 40 | apply plugin: 'maven' 41 | 42 | sourceCompatibility = JavaVersion.VERSION_1_8 43 | targetCompatibility = JavaVersion.VERSION_1_8 44 | 45 | repositories { 46 | mavenCentral() 47 | } 48 | 49 | if (rootProject.name == p.name) { 50 | println "early stopped $self" 51 | return 52 | } 53 | 54 | apply plugin: 'io.spring.dependency-management' 55 | 56 | dependencyManagement { 57 | imports { 58 | mavenBom "org.springframework.boot:spring-boot-dependencies:$springBootVersion" 59 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:$springCloudVersion" 60 | } 61 | } 62 | 63 | apply plugin: 'cn.bestwu.propdeps' 64 | apply plugin: 'cn.bestwu.propdeps-maven' 65 | 66 | dependencies { 67 | compile 'org.springframework.boot:spring-boot-starter', 68 | 'com.fasterxml.jackson.core:jackson-databind', 69 | 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' 70 | compileOnly('org.projectlombok:lombok') 71 | optional("org.springframework.boot:spring-boot-configuration-processor") 72 | testCompile('org.springframework.boot:spring-boot-starter-test') 73 | testCompileOnly('org.projectlombok:lombok') 74 | } 75 | 76 | apply plugin: 'org.springframework.boot' 77 | 78 | springBoot { 79 | executable = true 80 | } 81 | 82 | def backingServicesUp = ':twitter-docker:twitter-docker-backing-services:backingServicesUp' 83 | def backingServicesDown = ':twitter-docker:twitter-docker-backing-services:backingServicesDown' 84 | 85 | if (p.name.startsWith('twitter-docker')) return 86 | 87 | [test, build, bootRun].each { task -> 88 | task.dependsOn ':assemble', backingServicesUp 89 | task.finalizedBy backingServicesDown 90 | task.shouldRunAfter clean, ':assemble', backingServicesDown 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /modules/props-module/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile("org.springframework.boot:spring-boot-starter:$springBootVersion") 3 | compileOnly("org.projectlombok:lombok:$lombokVersion") 4 | } 5 | -------------------------------------------------------------------------------- /modules/props-module/src/main/java/daggerok/PropsModuleConfig.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import daggerok.props.BrokerProperties; 4 | import daggerok.props.DatabaseProperties; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.boot.CommandLineRunner; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Slf4j 12 | @Configuration 13 | @RequiredArgsConstructor 14 | public class PropsModuleConfig { 15 | 16 | final BrokerProperties mq; 17 | final DatabaseProperties db; 18 | 19 | public static void main(String[] args) { 20 | // stub 21 | } 22 | 23 | @Bean 24 | public CommandLineRunner init() { 25 | return args -> { 26 | log.info("mq: {}", mq); 27 | log.info("db: {}", db); 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /modules/props-module/src/main/java/daggerok/props/BrokerProperties.java: -------------------------------------------------------------------------------- 1 | package daggerok.props; 2 | 3 | import daggerok.props.common.Server; 4 | import lombok.Data; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.io.Serializable; 9 | 10 | @Data 11 | @Component 12 | @ConfigurationProperties(prefix = "mq") 13 | public class BrokerProperties implements Serializable { 14 | 15 | private static final long serialVersionUID = 7814185782402980920L; 16 | 17 | String destination; 18 | Server server; 19 | } 20 | -------------------------------------------------------------------------------- /modules/props-module/src/main/java/daggerok/props/DatabaseProperties.java: -------------------------------------------------------------------------------- 1 | package daggerok.props; 2 | 3 | import daggerok.props.common.Server; 4 | import lombok.Data; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.io.Serializable; 9 | 10 | @Data 11 | @Component 12 | @ConfigurationProperties(prefix = "db") 13 | public class DatabaseProperties implements Serializable { 14 | 15 | private static final long serialVersionUID = -323895804947475572L; 16 | 17 | String name; 18 | Server server; 19 | } 20 | -------------------------------------------------------------------------------- /modules/props-module/src/main/java/daggerok/props/common/Server.java: -------------------------------------------------------------------------------- 1 | package daggerok.props.common; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | @Data 8 | public class Server implements Serializable { 9 | 10 | private static final long serialVersionUID = -7151585064476879633L; 11 | 12 | String type; 13 | String host; 14 | Integer port; 15 | String user; 16 | String pass; 17 | } 18 | -------------------------------------------------------------------------------- /modules/props-module/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: props-module 4 | profiles: 5 | include: > 6 | props 7 | -------------------------------------------------------------------------------- /modules/props-module/src/main/resources/config/application-props.yml: -------------------------------------------------------------------------------- 1 | db: 2 | name: ${DB_NAME:twitter} 3 | server: 4 | type: ${DB_SERVER_TYPE:postgresql} 5 | host: ${DB_SERVER_HOST:localhost} 6 | port: ${DB_SERVER_PORT:5432} 7 | user: ${DB_SERVER_USER:twitter} 8 | pass: ${DB_SERVER_PASS:twitter} 9 | mq: 10 | input: 11 | destination: ${MQ_INPUT_DESTINATION:twitter} 12 | output: 13 | destination: ${MQ_OUTPUT_DESTINATION:twitter} 14 | server: 15 | type: ${MQ_SERVER_TYPE:rabbitmq} 16 | host: ${MQ_SERVER_HOST:localhost} 17 | port: ${MQ_SERVER_PORT:5672} 18 | user: ${MQ_SERVER_USER:twitter} 19 | pass: ${MQ_SERVER_PASS:twitter} 20 | -------------------------------------------------------------------------------- /modules/twitter-domain-module/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(':modules:twitter-domain-module:twitter-entity-module'), 3 | "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion", 4 | 'org.hibernate:hibernate-java8' 5 | compileOnly("org.projectlombok:lombok:$lombokVersion") 6 | runtime('org.postgresql:postgresql') 7 | } 8 | -------------------------------------------------------------------------------- /modules/twitter-domain-module/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'twitter-domain-module' 2 | include 'twitter-entity-module' 3 | -------------------------------------------------------------------------------- /modules/twitter-domain-module/src/main/java/daggerok/TwitterDomainModuleApplication.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | @Configuration 6 | public class TwitterDomainModuleApplication { 7 | 8 | public static void main(String[] args) { 9 | // stub 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /modules/twitter-domain-module/src/main/java/daggerok/twitter/TwitterRepository.java: -------------------------------------------------------------------------------- 1 | package daggerok.twitter; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.data.repository.query.Param; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.Optional; 8 | import java.util.stream.Stream; 9 | 10 | @Repository 11 | public interface TwitterRepository extends JpaRepository { 12 | 13 | Optional findFirstById(@Param("id") final Long id); 14 | 15 | Stream findAllByDataContaining(@Param("data") final String data); 16 | } 17 | -------------------------------------------------------------------------------- /modules/twitter-domain-module/twitter-entity-module/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile "org.hibernate.javax.persistence:hibernate-jpa-2.1-api:$hibernateJpa21Api" 3 | compileOnly("org.projectlombok:lombok:$lombokVersion") 4 | } 5 | -------------------------------------------------------------------------------- /modules/twitter-domain-module/twitter-entity-module/src/main/java/daggerok/TwitterEntityModuleApplication.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | @Configuration 6 | public class TwitterEntityModuleApplication { 7 | 8 | public static void main(String[] args) { 9 | // stub 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /modules/twitter-domain-module/twitter-entity-module/src/main/java/daggerok/twitter/Twitter.java: -------------------------------------------------------------------------------- 1 | package daggerok.twitter; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.Accessors; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.Entity; 10 | import javax.persistence.GeneratedValue; 11 | import javax.persistence.Id; 12 | import java.io.Serializable; 13 | 14 | import static javax.persistence.GenerationType.IDENTITY; 15 | 16 | @Data 17 | @Entity 18 | @NoArgsConstructor 19 | @Accessors(chain = true) 20 | @JsonIgnoreProperties(ignoreUnknown = true) 21 | public class Twitter implements Serializable { 22 | 23 | private static final long serialVersionUID = 1349410454351785631L; 24 | 25 | @Id 26 | @GeneratedValue(strategy = IDENTITY) 27 | Long id; 28 | 29 | @Column(nullable = false) 30 | String data; 31 | } 32 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'twitter' 2 | include 'modules:twitter-domain-module:twitter-entity-module' 3 | include 'twitter-docker:twitter-docker-backing-services' 4 | include 'twitter-docker:twitter-docker-services' 5 | 6 | def modules = 'modules' 7 | file(modules).listFiles().findAll({ it.isDirectory() && it.name.contains('module') }).each { 8 | include ":$modules:$it.name" 9 | } 10 | 11 | def twitterModules = rootProject.projectDir.listFiles({ File file -> 12 | file.isDirectory() && file.name.startsWith(rootProject.name) 13 | } as FileFilter) 14 | 15 | twitterModules.each { include(it.name) } 16 | -------------------------------------------------------------------------------- /twitter-api-gateway/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compileOnly('org.projectlombok:lombok') 3 | compile project(':modules:props-module'), 4 | project(':modules:twitter-domain-module:twitter-entity-module'), 5 | 'org.springframework.boot:spring-boot-starter-web', 6 | 'org.springframework.boot:spring-boot-starter-social-twitter', 7 | 'org.springframework.cloud:spring-cloud-starter-stream-rabbit' 8 | } 9 | -------------------------------------------------------------------------------- /twitter-api-gateway/src/main/java/daggerok/TwitterApiGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TwitterApiGatewayApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TwitterApiGatewayApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /twitter-api-gateway/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: twitter-api-gateway 4 | profiles: 5 | include: > 6 | twitter, 7 | server, 8 | props, 9 | mq 10 | -------------------------------------------------------------------------------- /twitter-api-gateway/src/main/resources/config/application-mq.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | rabbitmq: 3 | host: ${mq.server.host} 4 | port: ${mq.server.port} 5 | username: ${mq.server.user} 6 | password: ${mq.server.pass} 7 | cloud: 8 | stream: 9 | bindings: 10 | output: 11 | destination: ${mq.output.destination} 12 | -------------------------------------------------------------------------------- /twitter-api-gateway/src/main/resources/config/application-props.yml: -------------------------------------------------------------------------------- 1 | mq: 2 | output: 3 | destination: ${MQ_OUTPUT_DESTINATION:twitter} 4 | server: 5 | type: ${MQ_SERVER_TYPE:rabbitmq} 6 | host: ${MQ_SERVER_HOST:localhost} 7 | port: ${MQ_SERVER_PORT:5672} 8 | user: ${MQ_SERVER_USER:twitter} 9 | pass: ${MQ_SERVER_PASS:twitter} 10 | -------------------------------------------------------------------------------- /twitter-api-gateway/src/main/resources/config/application-server.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8883 3 | -------------------------------------------------------------------------------- /twitter-api-gateway/src/main/resources/config/application-twitter.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | social: 3 | twitter: 4 | app-id: TODO 5 | app-secret: TODO 6 | -------------------------------------------------------------------------------- /twitter-api-gateway/src/test/java/daggerok/TwitterApiGatewayApplicationTests.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 10 | public class TwitterApiGatewayApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() {} 14 | } 15 | -------------------------------------------------------------------------------- /twitter-command/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(':modules:props-module'), 3 | project(':modules:twitter-domain-module:twitter-entity-module'), 4 | 'org.springframework.boot:spring-boot-starter-web', 5 | 'org.springframework.cloud:spring-cloud-starter-stream-rabbit' 6 | } 7 | -------------------------------------------------------------------------------- /twitter-command/src/main/java/daggerok/TwitterCommandApplication.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TwitterCommandApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TwitterCommandApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /twitter-command/src/main/java/daggerok/twitter/TwitterCommand.java: -------------------------------------------------------------------------------- 1 | package daggerok.twitter; 2 | 3 | import lombok.NonNull; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.cloud.stream.annotation.EnableBinding; 6 | import org.springframework.cloud.stream.messaging.Source; 7 | import org.springframework.messaging.support.MessageBuilder; 8 | import org.springframework.scheduling.annotation.Async; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | @Service 13 | @RequiredArgsConstructor 14 | @EnableBinding(Source.class) 15 | @Transactional(readOnly = true) 16 | public class TwitterCommand { 17 | 18 | final Source source; 19 | 20 | @Async 21 | @Transactional 22 | public void save(@NonNull final Twitter twitter) { 23 | 24 | source.output() 25 | .send(MessageBuilder.withPayload(twitter) 26 | .build()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /twitter-command/src/main/java/daggerok/twitter/TwitterCommandApplicationConfig.java: -------------------------------------------------------------------------------- 1 | package daggerok.twitter; 2 | 3 | import lombok.val; 4 | import org.springframework.cloud.stream.annotation.EnableBinding; 5 | import org.springframework.cloud.stream.messaging.Source; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.ComponentScan; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.scheduling.annotation.EnableAsync; 10 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 11 | 12 | import static java.lang.Integer.MAX_VALUE; 13 | 14 | @EnableAsync 15 | @Configuration 16 | @EnableBinding(Source.class) 17 | @ComponentScan(basePackageClasses = { 18 | TwitterCommand.class, 19 | TwitterResource.class, 20 | }) 21 | public class TwitterCommandApplicationConfig { 22 | 23 | @Bean 24 | public ThreadPoolTaskExecutor threadPoolTaskExecutor() { 25 | val executor = new ThreadPoolTaskExecutor(); 26 | executor.setThreadNamePrefix(TwitterCommand.class.getSimpleName()); 27 | executor.setCorePoolSize(MAX_VALUE); 28 | executor.initialize(); 29 | return executor; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /twitter-command/src/main/java/daggerok/twitter/TwitterResource.java: -------------------------------------------------------------------------------- 1 | package daggerok.twitter; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.scheduling.annotation.Async; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.ResponseStatus; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import static org.springframework.http.HttpStatus.ACCEPTED; 12 | 13 | @Slf4j 14 | @RestController 15 | @RequiredArgsConstructor 16 | public class TwitterResource { 17 | 18 | final TwitterCommand command; 19 | 20 | @Async 21 | @PostMapping("/") 22 | @ResponseStatus(ACCEPTED) 23 | public void post(@RequestBody final Twitter twitter) { 24 | 25 | log.info("saving {}", twitter); 26 | command.save(twitter); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /twitter-command/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: twitter-query 4 | profiles: 5 | include: > 6 | server, 7 | props, 8 | mq 9 | -------------------------------------------------------------------------------- /twitter-command/src/main/resources/config/application-mq.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | rabbitmq: 3 | host: ${mq.server.host} 4 | port: ${mq.server.port} 5 | username: ${mq.server.user} 6 | password: ${mq.server.pass} 7 | cloud: 8 | stream: 9 | bindings: 10 | output: 11 | content-type: application/json 12 | destination: ${mq.output.destination} 13 | -------------------------------------------------------------------------------- /twitter-command/src/main/resources/config/application-props.yml: -------------------------------------------------------------------------------- 1 | mq: 2 | output: 3 | destination: ${MQ_OUTPUT_DESTINATION:twitter} 4 | server: 5 | type: ${MQ_SERVER_TYPE:rabbitmq} 6 | host: ${MQ_SERVER_HOST:localhost} 7 | port: ${MQ_SERVER_PORT:5672} 8 | user: ${MQ_SERVER_USER:twitter} 9 | pass: ${MQ_SERVER_PASS:twitter} 10 | -------------------------------------------------------------------------------- /twitter-command/src/main/resources/config/application-server.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8881 3 | -------------------------------------------------------------------------------- /twitter-command/src/test/java/daggerok/TwitterCommandApplicationTests.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 10 | public class TwitterCommandApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() {} 14 | } 15 | -------------------------------------------------------------------------------- /twitter-data/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(':modules:props-module'), 3 | project(':modules:twitter-domain-module'), 4 | 'org.springframework.cloud:spring-cloud-starter-stream-rabbit' 5 | } 6 | -------------------------------------------------------------------------------- /twitter-data/src/main/java/daggerok/TwitterDataApplication.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TwitterDataApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TwitterDataApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /twitter-data/src/main/java/daggerok/config/TwitterDataConfig.java: -------------------------------------------------------------------------------- 1 | package daggerok.config; 2 | 3 | import daggerok.twitter.Twitter; 4 | import daggerok.twitter.TwitterRepository; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 7 | import lombok.val; 8 | import org.springframework.cloud.stream.annotation.EnableBinding; 9 | import org.springframework.cloud.stream.annotation.StreamListener; 10 | import org.springframework.cloud.stream.messaging.Sink; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | @Slf4j 15 | @Configuration 16 | @RequiredArgsConstructor 17 | @EnableBinding(Sink.class) 18 | @Transactional(readOnly = true) 19 | public class TwitterDataConfig { 20 | 21 | final TwitterRepository twitterRepository; 22 | 23 | @Transactional 24 | @StreamListener(Sink.INPUT) 25 | public void onTwitter(final Twitter twitter) { 26 | 27 | log.info("received: {}", twitter); 28 | val saved = twitterRepository.save(twitter); 29 | log.info("saved: {}", saved); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /twitter-data/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: twitter-data 4 | profiles: 5 | include: > 6 | server, 7 | props, 8 | db, 9 | mq 10 | -------------------------------------------------------------------------------- /twitter-data/src/main/resources/config/application-db.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:${db.server.type}://${db.server.host}:${db.server.port}/${db.name} 4 | username: ${db.server.user} 5 | password: ${db.server.pass} 6 | jpa: 7 | hibernate: 8 | ddl-auto: create 9 | show-sql: true 10 | database: ${db.server.type} 11 | -------------------------------------------------------------------------------- /twitter-data/src/main/resources/config/application-mq.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | rabbitmq: 3 | host: ${mq.server.host} 4 | port: ${mq.server.port} 5 | username: ${mq.server.user} 6 | password: ${mq.server.pass} 7 | cloud: 8 | stream: 9 | bindings: 10 | input: 11 | destination: ${mq.input.destination} 12 | -------------------------------------------------------------------------------- /twitter-data/src/main/resources/config/application-props.yml: -------------------------------------------------------------------------------- 1 | db: 2 | name: ${DB_NAME:twitter} 3 | server: 4 | type: ${DB_SERVER_TYPE:postgresql} 5 | host: ${DB_SERVER_HOST:localhost} 6 | port: ${DB_SERVER_PORT:5432} 7 | user: ${DB_SERVER_USER:twitter} 8 | pass: ${DB_SERVER_PASS:twitter} 9 | mq: 10 | input: 11 | destination: ${MQ_INPUT_DESTINATION:twitter} 12 | server: 13 | type: ${MQ_SERVER_TYPE:rabbitmq} 14 | host: ${MQ_SERVER_HOST:localhost} 15 | port: ${MQ_SERVER_PORT:5672} 16 | user: ${MQ_SERVER_USER:twitter} 17 | pass: ${MQ_SERVER_PASS:twitter} 18 | -------------------------------------------------------------------------------- /twitter-data/src/main/resources/config/application-server.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 0 3 | -------------------------------------------------------------------------------- /twitter-data/src/test/java/daggerok/TwitterDataApplicationTests.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 10 | public class TwitterDataApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() {} 14 | } 15 | -------------------------------------------------------------------------------- /twitter-docker/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.avast.gradle.docker-compose" version "0.4.3" 3 | } 4 | 5 | configure(subprojects) { p -> 6 | 7 | // fix windows paths: '\\' -> '/' 8 | def root = p.projectDir.absolutePath.replaceAll("\\\\", '/') 9 | 10 | dockerCompose { 11 | useComposeFiles = ["$root/src/docker-compose.yml"] 12 | captureContainersOutput = true 13 | stopContainers = true 14 | removeContainers = true 15 | removeImages = "Local" 16 | removeVolumes = true 17 | removeOrphans = true 18 | projectName = "$project.name" 19 | } 20 | 21 | composeUp.dependsOn ':assemble' 22 | composeUp.shouldRunAfter clean, ':clean', ':assemble' 23 | 24 | if (p.name.contains('twitter-docker-backing-services')) { 25 | 26 | task backingServicesUp(dependsOn: composeUp) 27 | task backingServicesDown(dependsOn: composeDown) 28 | } 29 | 30 | if (p.name.contains('twitter-docker-services')) { 31 | 32 | task twitterServicesUp(dependsOn: composeUp) 33 | task twitterServicesDown(dependsOn: composeDown) 34 | 35 | /* 36 | tasks.create('twitterServices') { t3 -> 37 | t3.shouldRunAfter ':assemble', twitterServicesUp 38 | t3.dependsOn ':assemble', twitterServicesUp 39 | t3.finalizedBy twitterServicesDown 40 | } 41 | */ 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /twitter-docker/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'twitter-docker' 2 | include 'twitter-docker-backing-services' 3 | include 'twitter-docker-services' 4 | -------------------------------------------------------------------------------- /twitter-docker/twitter-docker-backing-services/src/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2.1" 2 | services: 3 | pg_sql_db: 4 | image: healthcheck/postgres:alpine 5 | volumes: ["pg_sql_db_data_volume:/var/lib/postgresql/data:rw"] 6 | networks: [backing_services] 7 | ports: ["5432:5432"] 8 | environment: 9 | POSTGRES_DB: twitter 10 | POSTGRES_USER: twitter 11 | POSTGRES_PASSWORD: twitter 12 | rabbit_mq: 13 | image: rabbitmq:3.6.6-alpine 14 | volumes: ["rabbit_mq_data_volume:/var/lib/rabbitmq:rw"] 15 | networks: [backing_services] 16 | ports: ["5672:5672"] 17 | environment: 18 | RABBITMQ_DEFAULT_USER: twitter 19 | RABBITMQ_DEFAULT_PASS: twitter 20 | volumes: 21 | pg_sql_db_data_volume: {} 22 | rabbit_mq_data_volume: {} 23 | networks: 24 | backing_services: 25 | driver: bridge 26 | -------------------------------------------------------------------------------- /twitter-docker/twitter-docker-services/src/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2.1" 2 | services: 3 | pg_sql_db: 4 | image: healthcheck/postgres:alpine 5 | volumes: ["pg_sql_db_data_volume:/var/lib/postgresql/data:rw"] 6 | networks: [backing_services] 7 | ports: ["5432:5432"] 8 | environment: 9 | POSTGRES_DB: twitter 10 | POSTGRES_USER: twitter 11 | POSTGRES_PASSWORD: twitter 12 | rabbit_mq: 13 | image: rabbitmq:3.6.6-alpine 14 | volumes: ["rabbit_mq_data_volume:/var/lib/rabbitmq:rw"] 15 | networks: [backing_services] 16 | ports: ["5672:5672"] 17 | environment: 18 | RABBITMQ_DEFAULT_USER: twitter 19 | RABBITMQ_DEFAULT_PASS: twitter 20 | twitter_data_app: 21 | image: openjdk:8u131-jre-alpine 22 | depends_on: 23 | - pg_sql_db 24 | - rabbit_mq 25 | networks: [backing_services] 26 | ports: ["54321:54321"] 27 | volumes: 28 | - "twitter_data_app_data_volume:/var/app" 29 | - "../../../twitter-data/build/libs/twitter-data-0.0.1.jar:/var/app/app.jar:ro" 30 | environment: 31 | SERVER_PORT: 54321 32 | DB_SERVER_HOST: pg_sql_db 33 | MQ_SERVER_HOST: rabbit_mq 34 | JAVA_OPTS: " -Xss228k" 35 | entrypoint: sh -c "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /var/app/app.jar" 36 | twitter_query_app: 37 | image: openjdk:8u131-jre-alpine 38 | depends_on: 39 | - pg_sql_db 40 | - twitter_data_app 41 | ports: ["8882:8882"] 42 | networks: [backing_services] 43 | volumes: 44 | - "twitter_query_app_data_volume:/var/app" 45 | - "../../../twitter-query/build/libs/twitter-query-0.0.1.jar:/var/app/app.jar:ro" 46 | environment: 47 | DB_SERVER_HOST: pg_sql_db 48 | JAVA_OPTS: " -Xss228k" 49 | entrypoint: sh -c "sleep 20 && java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /var/app/app.jar" 50 | twitter_command_app: 51 | image: openjdk:8u131-jre-alpine 52 | depends_on: 53 | - rabbit_mq 54 | - twitter_data_app 55 | ports: ["8881:8881"] 56 | networks: [backing_services] 57 | volumes: 58 | - "twitter_command_app_data_volume:/var/app" 59 | - "../../../twitter-command/build/libs/twitter-command-0.0.1.jar:/var/app/app.jar:ro" 60 | environment: 61 | MQ_SERVER_HOST: rabbit_mq 62 | JAVA_OPTS: "" 63 | entrypoint: sh -c "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /var/app/app.jar" 64 | twitter_api_gateway_app: 65 | image: openjdk:8u131-jre-alpine 66 | depends_on: [rabbit_mq] 67 | ports: ["8883:8883"] 68 | networks: [backing_services] 69 | volumes: 70 | - "twitter_api_gateway_app_data_volume:/var/app" 71 | - "../../../twitter-api-gateway/build/libs/twitter-api-gateway-0.0.1.jar:/var/app/app.jar:ro" 72 | environment: 73 | MQ_SERVER_HOST: rabbit_mq 74 | JAVA_OPTS: " -Xss228k" 75 | entrypoint: sh -c "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /var/app/app.jar" 76 | volumes: 77 | pg_sql_db_data_volume: {} 78 | rabbit_mq_data_volume: {} 79 | twitter_command_app_data_volume: {} 80 | twitter_data_app_data_volume: {} 81 | twitter_query_app_data_volume: {} 82 | twitter_api_gateway_app_data_volume: {} 83 | networks: 84 | backing_services: 85 | driver: bridge 86 | -------------------------------------------------------------------------------- /twitter-query/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(':modules:props-module'), 3 | project(':modules:twitter-domain-module'), 4 | 'org.springframework.boot:spring-boot-starter-web' 5 | } 6 | -------------------------------------------------------------------------------- /twitter-query/src/main/java/daggerok/TwitterQueryApplication.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class TwitterQueryApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(TwitterQueryApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /twitter-query/src/main/java/daggerok/twitter/TwitterResource.java: -------------------------------------------------------------------------------- 1 | package daggerok.twitter; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.transaction.annotation.Transactional; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | import java.util.List; 9 | 10 | @RestController 11 | @RequiredArgsConstructor 12 | @Transactional(readOnly = true) 13 | public class TwitterResource { 14 | 15 | final TwitterRepository twitterRepository; 16 | 17 | @GetMapping("/") 18 | public List get() { 19 | return twitterRepository.findAll(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /twitter-query/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: twitter-query 4 | profiles: 5 | include: > 6 | server, 7 | props, 8 | db 9 | -------------------------------------------------------------------------------- /twitter-query/src/main/resources/config/application-db.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:${db.server.type}://${db.server.host}:${db.server.port}/${db.name} 4 | username: ${db.server.user} 5 | password: ${db.server.pass} 6 | jpa: 7 | hibernate: 8 | ddl-auto: validate 9 | show-sql: true 10 | database: ${db.server.type} 11 | -------------------------------------------------------------------------------- /twitter-query/src/main/resources/config/application-props.yml: -------------------------------------------------------------------------------- 1 | db: 2 | name: ${DB_NAME:twitter} 3 | server: 4 | type: ${DB_SERVER_TYPE:postgresql} 5 | host: ${DB_SERVER_HOST:localhost} 6 | port: ${DB_SERVER_PORT:5432} 7 | user: ${DB_SERVER_USER:twitter} 8 | pass: ${DB_SERVER_PASS:twitter} 9 | -------------------------------------------------------------------------------- /twitter-query/src/main/resources/config/application-server.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8882 3 | -------------------------------------------------------------------------------- /twitter-query/src/test/java/daggerok/TwitterQueryApplicationTests.java: -------------------------------------------------------------------------------- 1 | package daggerok; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 10 | public class TwitterQueryApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() {} 14 | } 15 | --------------------------------------------------------------------------------