├── .DS_Store ├── .gitignore ├── Modern Uygulamalarda Kafka Kullanımı.pptx ├── README.md ├── images ├── add_bucket.png ├── add_bucket_to_cluster.png ├── add_user.png ├── admin_user_settings.png ├── couchbase_ui.png ├── create_index.png ├── created_tables.png ├── data_grip.png ├── db.png ├── docker_desktop.png ├── edit_run_configuration.png ├── kafka_ui.png ├── open_runner.png ├── postman_request.png ├── rebalance.png ├── rebalance_result.png ├── run_ep.png ├── select_spring_boot.png ├── spring_new_instance_settings.png ├── success.png ├── system_architecture.png └── topic_settings.png ├── notification-consumer ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── infra-setup │ └── docker-compose.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── notificationconsumer │ │ │ ├── NotificationConsumerApplication.java │ │ │ ├── config │ │ │ └── couchbase │ │ │ │ └── MyCouchbaseConfig.java │ │ │ ├── consumers │ │ │ ├── configuration │ │ │ │ ├── UserCreatedKafkaConsumerConfiguration.java │ │ │ │ └── properties │ │ │ │ │ └── UserCreatedConsumerProperties.java │ │ │ ├── consumer │ │ │ │ └── UserCreatedEventConsumer.java │ │ │ └── model │ │ │ │ └── UserCreatedEvent.java │ │ │ ├── entity │ │ │ └── Notification.java │ │ │ ├── repository │ │ │ └── NotificationRepository.java │ │ │ └── service │ │ │ └── NotificationService.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── example │ └── notificationconsumer │ └── NotificationConsumerApplicationTests.java ├── postman ├── Kafka-Example.postman_collection.json └── MOCK_DATA.json ├── user-address-service ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── infra-setup │ └── docker-compose.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── useraddressservice │ │ │ ├── UserAddressServiceApplication.java │ │ │ ├── consumers │ │ │ ├── configuration │ │ │ │ ├── UserCreatedKafkaConsumerConfiguration.java │ │ │ │ └── properties │ │ │ │ │ └── UserCreatedConsumerProperties.java │ │ │ ├── consumer │ │ │ │ └── UserCreatedEventConsumer.java │ │ │ └── model │ │ │ │ └── UserCreatedEvent.java │ │ │ ├── controller │ │ │ └── AddressController.java │ │ │ ├── entity │ │ │ └── Address.java │ │ │ ├── repository │ │ │ └── AddressRepository.java │ │ │ └── service │ │ │ └── AddressService.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── example │ └── useraddressservice │ └── UserAddressServiceApplicationTests.java └── user-service ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── infra-setup └── docker-compose.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── example │ │ └── userservice │ │ ├── UserServiceApplication.java │ │ ├── config │ │ └── kafka │ │ │ ├── configuration │ │ │ └── KafkaProducerConfiguration.java │ │ │ ├── producer │ │ │ └── KafkaProducer.java │ │ │ └── properties │ │ │ └── UserCreatedTopicProperties.java │ │ ├── controller │ │ └── UserController.java │ │ ├── dto │ │ ├── AddressResponseDto.java │ │ ├── BaseResponseDto.java │ │ ├── UserCreateRequest.java │ │ ├── UserCreatedPayload.java │ │ └── UserResponse.java │ │ ├── entity │ │ ├── BaseEntity.java │ │ └── User.java │ │ ├── repository │ │ └── UserRepository.java │ │ └── service │ │ └── UserService.java └── resources │ └── application.yml └── test └── java └── com └── example └── userservice └── UserServiceApplicationTests.java /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | .DS_Store 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | 17 | ### IntelliJ IDEA ### 18 | .idea 19 | *.iws 20 | *.iml 21 | *.ipr 22 | 23 | ### NetBeans ### 24 | /nbproject/private/ 25 | /nbbuild/ 26 | /dist/ 27 | /nbdist/ 28 | /.nb-gradle/ 29 | build/ 30 | !**/src/main/**/build/ 31 | !**/src/test/**/build/ 32 | 33 | ### VS Code ### 34 | .vscode/ 35 | -------------------------------------------------------------------------------- /Modern Uygulamalarda Kafka Kullanımı.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/Modern Uygulamalarda Kafka Kullanımı.pptx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kafka-Example 2 | In this project, 3 | - There are 3 microservices, when a user created via user-service that service insert a record onto user table(postgre) 4 | and it produce an event to **user_service.user_created.0** topic. 5 | - Notification-consumer service listen **user_service.user_created.0** topic and simulates the logic of sending 6 | notification after the event it consumes after notification is sending successfully service insert a record onto couchbase 7 | notification bucket. 8 | - User-address-service also listen user_service.user_created.0 topic and it consume events. According to user's address text 9 | information it insert a record onto user-address table(postgre) 10 | 11 | ## System Architechure 12 | ![](images/system_architecture.png) 13 | 14 | ## Requirements 15 | - [Java 11 JDK](https://www.oracle.com/tr/java/technologies/javase/jdk11-archive-downloads.html) 16 | - [Docker](https://www.docker.com/products/docker-desktop/) 17 | - [Data Grip](https://www.jetbrains.com/datagrip/download/#section=mac) or any other database GUIs 18 | - [Postman](https://www.postman.com/downloads/) 19 | 20 | ## Setup 21 | - Before run project you need to start docker desktop 22 | - After docker is up, run the docker-compose.yml (You can find it in the infra-setup folder.) 23 | - After the run docker-compose.yml file you will see docker desktop like this: 24 | ![](images/docker_desktop.png) 25 | - Continue With DB Connection Part 26 | 27 | ## DB Connection 28 | # Postgre Connection: 29 | url: jdbc:postgresql://localhost:5432/kafka_example 30 | username: example 31 | password: example 32 | 33 | * After you successfully connect database, you will see like this in datagrip: 34 | ![](images/data_grip.png) 35 | 36 | # Couchbase Connection & Settings 37 | - #### Open http://localhost:8091/ on your browser 38 | 39 | ![](images/couchbase_ui.png) 40 | 41 | username: Administrator 42 | password: 123456 43 | 44 | - #### Open the buckets tab and click the **ADD BUCKET** 45 | ![](images/add_bucket.png) 46 | 47 | - #### write the bucket name in our example => bucket name is **"notification"** 48 | ![](images/add_bucket_to_cluster.png) 49 | 50 | - #### After that open the query tab on the left side 51 | ![](images/create_index.png) 52 | - #### Run 2 query separately to create index on bucket 53 | 54 | 1) CREATE PRIMARY INDEX `idx_default_primary_notification` ON `notification` 55 | 2) CREATE INDEX `id` ON `notification`(`id`) 56 | - #### Open the Security tab on the left side and click the **ADD USER** 57 | ![](images/add_user.png) 58 | - #### After click the add user you will see a new popup and fill the informations like : 59 | Username: admin 60 | Full Name: admin 61 | Password: 123456 62 | Verify Password: 123456 63 | ![](images/admin_user_settings.png) 64 | 65 | # Running 66 | - #### Run each project application file on your code ide. 67 | - #### After you run 3 application successfully you can check postgre db on your GUI you have to see created 2 tables which names ara **user** and **user_address** 68 | ![](images/created_tables.png) 69 | - #### Check Topic is created or not http://localhost:9090/ (kafka ui) 70 | ![](images/kafka_ui.png) 71 | - #### If you have come this far without any problems, we can open postman and try a sample request. 72 | - #### You can import postman collection which I share in postman_collection folder 73 | ![](images/postman_request.png) 74 | - #### After execute post endpoint and get 200 success message from postman you can see producer and consumer logs on your running terminal also you can check that records are in your databases 75 | ![](images/success.png) 76 | ![](images/db.png) 77 | - #### As you can see our records successfully inserted to our databases 78 | - #### To test batch request use MOCK DATA.json file which it is in postman folder, open the postman runner and select that json file and run. 79 | ![](images/open_runner.png) 80 | ![](images/run_ep.png) 81 | 82 | # Topic Partition Settings 83 | - #### To increase topic partition open http://localhost:9090/ (kafka-ui) and open the topic settings. 84 | ![](images/topic_settings.png) 85 | - #### As you can see I set partition count 4 86 | - #### After set partition count 4, now our consumer's will rebalance because now we have 4 partition so our consumers bind all of partitions 87 | ![](images/rebalance.png) 88 | - #### If you want to run one more consumer app follow these steps: 89 | ![](images/edit_run_configuration.png) 90 | ![](images/select_spring_boot.png) 91 | ![](images/spring_new_instance_settings.png) 92 | - #### Now you can run one more consumer app, it will up randomly port in your computer's free port because we set server.port as 0 in application.yml 93 | ![](images/rebalance_result.png) 94 | - #### As you can see we have 4 partition and we run 4 consumer app (user-address-service) so each consumer app bind 1 partition of user_service.user_created.0 topic 95 | - #### You can run again batch request on postman and you can easily see your consumer apps consume the event corresponding partition 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /images/add_bucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/add_bucket.png -------------------------------------------------------------------------------- /images/add_bucket_to_cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/add_bucket_to_cluster.png -------------------------------------------------------------------------------- /images/add_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/add_user.png -------------------------------------------------------------------------------- /images/admin_user_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/admin_user_settings.png -------------------------------------------------------------------------------- /images/couchbase_ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/couchbase_ui.png -------------------------------------------------------------------------------- /images/create_index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/create_index.png -------------------------------------------------------------------------------- /images/created_tables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/created_tables.png -------------------------------------------------------------------------------- /images/data_grip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/data_grip.png -------------------------------------------------------------------------------- /images/db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/db.png -------------------------------------------------------------------------------- /images/docker_desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/docker_desktop.png -------------------------------------------------------------------------------- /images/edit_run_configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/edit_run_configuration.png -------------------------------------------------------------------------------- /images/kafka_ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/kafka_ui.png -------------------------------------------------------------------------------- /images/open_runner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/open_runner.png -------------------------------------------------------------------------------- /images/postman_request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/postman_request.png -------------------------------------------------------------------------------- /images/rebalance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/rebalance.png -------------------------------------------------------------------------------- /images/rebalance_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/rebalance_result.png -------------------------------------------------------------------------------- /images/run_ep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/run_ep.png -------------------------------------------------------------------------------- /images/select_spring_boot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/select_spring_boot.png -------------------------------------------------------------------------------- /images/spring_new_instance_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/spring_new_instance_settings.png -------------------------------------------------------------------------------- /images/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/success.png -------------------------------------------------------------------------------- /images/system_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/system_architecture.png -------------------------------------------------------------------------------- /images/topic_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/images/topic_settings.png -------------------------------------------------------------------------------- /notification-consumer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /notification-consumer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/notification-consumer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /notification-consumer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /notification-consumer/infra-setup/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Use postgres/example user/password credentials 2 | version: '3.1' 3 | 4 | services: 5 | couchbase-db: 6 | image: couchbase/server:community-aarch64 7 | ports: 8 | - 8091:8091 9 | - 8092:8092 10 | - 8093:8093 11 | - 11210:11210 12 | zookeeper: 13 | image: "docker.io/bitnami/zookeeper:3" 14 | ports: 15 | - "2181:2181" 16 | volumes: 17 | - "zookeeper_data:/bitnami" 18 | environment: 19 | - ALLOW_ANONYMOUS_LOGIN=yes 20 | kafka: 21 | image: "docker.io/bitnami/kafka:2-debian-10" 22 | ports: 23 | - "9092:9092" 24 | expose: 25 | - "9093" 26 | volumes: 27 | - "kafka_data:/bitnami" 28 | environment: 29 | - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 30 | - ALLOW_PLAINTEXT_LISTENER=yes 31 | - KAFKA_ADVERTISED_LISTENERS=INSIDE://kafka:9093,OUTSIDE://localhost:9092 32 | - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT 33 | - KAFKA_LISTENERS=INSIDE://0.0.0.0:9093,OUTSIDE://0.0.0.0:9092 34 | - KAFKA_INTER_BROKER_LISTENER_NAME=INSIDE 35 | - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 36 | depends_on: 37 | - zookeeper 38 | kafka-ui: 39 | image: provectuslabs/kafka-ui 40 | container_name: kafka-ui 41 | ports: 42 | - "9090:8080" 43 | restart: always 44 | environment: 45 | - KAFKA_CLUSTERS_0_NAME=local 46 | - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka:9093 47 | - KAFKA_CLUSTERS_0_ZOOKEEPER=localhost:2181 48 | 49 | volumes: 50 | zookeeper_data: 51 | driver: local 52 | kafka_data: 53 | driver: local -------------------------------------------------------------------------------- /notification-consumer/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /notification-consumer/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /notification-consumer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.5 9 | 10 | 11 | com.example 12 | notification-consumer 13 | 0.0.1-SNAPSHOT 14 | notification-consumer 15 | notification-consumer 16 | 17 | 11 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-couchbase 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | org.springframework.kafka 30 | spring-kafka 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-configuration-processor 36 | true 37 | 38 | 39 | 40 | org.springframework.data 41 | spring-data-couchbase 42 | 43 | 44 | 45 | org.projectlombok 46 | lombok 47 | true 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-test 52 | test 53 | 54 | 55 | org.springframework.kafka 56 | spring-kafka-test 57 | test 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | org.projectlombok 70 | lombok 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/NotificationConsumerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class NotificationConsumerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(NotificationConsumerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/config/couchbase/MyCouchbaseConfig.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer.config.couchbase; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; 6 | 7 | @Configuration 8 | public class MyCouchbaseConfig extends AbstractCouchbaseConfiguration { 9 | 10 | 11 | @Value("${couchbase.notification-service.config.bootstrapHosts}") 12 | private String connectionString; 13 | 14 | @Value("${couchbase.notification-service.config.notificationBucketUsername}") 15 | private String username; 16 | 17 | @Value("${couchbase.notification-service.config.notificationPassword}") 18 | private String password; 19 | 20 | @Value("${couchbase.notification-service.config.notificationBucket}") 21 | private String bucketName; 22 | 23 | @Override 24 | public String getConnectionString() { 25 | return connectionString; 26 | } 27 | 28 | @Override 29 | public String getUserName() { 30 | return username; 31 | } 32 | 33 | @Override 34 | public String getPassword() { 35 | return password; 36 | } 37 | 38 | @Override 39 | public String getBucketName() { 40 | return bucketName; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/consumers/configuration/UserCreatedKafkaConsumerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer.consumers.configuration; 2 | 3 | import org.apache.kafka.common.serialization.StringDeserializer; 4 | import lombok.RequiredArgsConstructor; 5 | import org.apache.kafka.clients.consumer.ConsumerConfig; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 10 | import org.springframework.kafka.core.ConsumerFactory; 11 | import org.springframework.kafka.core.DefaultKafkaConsumerFactory; 12 | import org.springframework.kafka.support.converter.StringJsonMessageConverter; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | @Configuration 18 | @RequiredArgsConstructor 19 | public class UserCreatedKafkaConsumerConfiguration { 20 | 21 | @Value("${kafka.host}") 22 | private String host; 23 | 24 | public ConsumerFactory consumerFactory() { 25 | 26 | // Creating a Map of string-object pairs 27 | Map config = new HashMap<>(); 28 | 29 | // Adding the Configuration 30 | config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, host); 31 | config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 32 | config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 33 | //config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true); 34 | 35 | return new DefaultKafkaConsumerFactory<>(config); 36 | } 37 | 38 | @Bean 39 | // Creating a Listener 40 | public ConcurrentKafkaListenerContainerFactory concurrentKafkaListenerContainerFactory() { 41 | ConcurrentKafkaListenerContainerFactory factory 42 | = new ConcurrentKafkaListenerContainerFactory<>(); 43 | factory.setConsumerFactory(consumerFactory()); 44 | factory.setMessageConverter(new StringJsonMessageConverter()); 45 | return factory; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/consumers/configuration/properties/UserCreatedConsumerProperties.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer.consumers.configuration.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | @ConfigurationProperties(prefix = "kafka.topics.user-created") 10 | @Getter 11 | @Setter 12 | public class UserCreatedConsumerProperties { 13 | private String topic; 14 | private String consumerGroup; 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/consumers/consumer/UserCreatedEventConsumer.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer.consumers.consumer; 2 | 3 | import com.example.notificationconsumer.consumers.model.UserCreatedEvent; 4 | import com.example.notificationconsumer.entity.Notification; 5 | import com.example.notificationconsumer.service.NotificationService; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.apache.kafka.clients.consumer.ConsumerRecord; 9 | import org.springframework.kafka.annotation.KafkaListener; 10 | import org.springframework.messaging.handler.annotation.Headers; 11 | import org.springframework.messaging.handler.annotation.Payload; 12 | import org.springframework.stereotype.Component; 13 | 14 | 15 | @Component 16 | @RequiredArgsConstructor 17 | @Slf4j 18 | public class UserCreatedEventConsumer { 19 | 20 | private final NotificationService notificationService; 21 | 22 | 23 | @KafkaListener(topics = "${kafka.topics.user-created.topic}", 24 | groupId = "${kafka.topics.user-created.consumerGroup}", 25 | containerFactory = "concurrentKafkaListenerContainerFactory" 26 | ) 27 | public void consumeCreatedUserEvent(@Payload UserCreatedEvent eventData, 28 | @Headers ConsumerRecord consumerRecord) { 29 | log.info("UserCreatedEventConsumer.consumeApprovalRequestResultedEvent consumed EVENT :{} " + 30 | "from partition : {} " + 31 | "with offset : {} " + 32 | "thread : {} " + 33 | "for message key: {}", 34 | eventData, consumerRecord.partition(), consumerRecord.offset(), Thread.currentThread().getName(), consumerRecord.key()); 35 | 36 | Notification entity = Notification.EventToNotificationEntity(eventData); 37 | 38 | notificationService.save(entity); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/consumers/model/UserCreatedEvent.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer.consumers.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | import lombok.ToString; 9 | 10 | @Getter 11 | @Setter 12 | @ToString 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Builder 16 | public class UserCreatedEvent { 17 | private Long id; 18 | private String firstName; 19 | private String lastName; 20 | private String email; 21 | private Boolean status; 22 | } 23 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/entity/Notification.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer.entity; 2 | 3 | import com.example.notificationconsumer.consumers.model.UserCreatedEvent; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | import org.springframework.data.annotation.Id; 8 | import org.springframework.data.couchbase.core.mapping.Document; 9 | import org.springframework.data.couchbase.core.mapping.Field; 10 | import org.springframework.data.couchbase.core.mapping.id.GeneratedValue; 11 | 12 | import static org.springframework.data.couchbase.core.mapping.id.GenerationStrategy.UNIQUE; 13 | 14 | @Getter 15 | @Setter 16 | @Document 17 | @Builder 18 | public class Notification { 19 | @Id 20 | @GeneratedValue(strategy = UNIQUE) 21 | private String id; 22 | @Field 23 | private Long userId; 24 | @Field 25 | private String email; 26 | @Field 27 | private Boolean isSend; 28 | 29 | 30 | public static Notification EventToNotificationEntity(UserCreatedEvent event) { 31 | return Notification.builder() 32 | .userId(event.getId()) 33 | .email(event.getEmail()) 34 | .isSend(Boolean.TRUE) 35 | .build(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/repository/NotificationRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer.repository; 2 | 3 | import com.example.notificationconsumer.entity.Notification; 4 | import org.springframework.data.couchbase.repository.CouchbaseRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface NotificationRepository extends CouchbaseRepository { 9 | } 10 | -------------------------------------------------------------------------------- /notification-consumer/src/main/java/com/example/notificationconsumer/service/NotificationService.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer.service; 2 | 3 | import com.example.notificationconsumer.entity.Notification; 4 | import com.example.notificationconsumer.repository.NotificationRepository; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | @RequiredArgsConstructor 11 | @Slf4j 12 | public class NotificationService { 13 | 14 | private final NotificationRepository notificationRepository; 15 | 16 | public void save(Notification notification) { 17 | Notification savedEntity = notificationRepository.save(notification); 18 | log.info("NotificationService.save saved Id: {}", savedEntity.getId()); 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /notification-consumer/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: notification_service 4 | 5 | couchbase: 6 | notification-service: 7 | config: 8 | bootstrapHosts: localhost 9 | notificationBucket: notification 10 | notificationBucketUsername: admin 11 | notificationPassword: 123456 12 | queryTimeout: 300 13 | kvTimeout: 5 14 | connectionTimeout: 10 15 | 16 | server: 17 | port: 0 18 | 19 | kafka: 20 | host: localhost:9092 21 | topics: 22 | user-created: 23 | topic: user_service.user_created.0 24 | consumerGroup: ${spring.application.name}-user-created-consumer 25 | replicationFactor: 1 26 | retentionInMs: 604800000 -------------------------------------------------------------------------------- /notification-consumer/src/test/java/com/example/notificationconsumer/NotificationConsumerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.notificationconsumer; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class NotificationConsumerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /postman/Kafka-Example.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "783b7e7d-0bec-475a-92e7-31cd68f9bfe5", 4 | "name": "Kafka-Example", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "create user", 10 | "request": { 11 | "method": "POST", 12 | "header": [], 13 | "body": { 14 | "mode": "raw", 15 | "raw": "{\n\n \"firstName\": \"Muhammed\",\n \"lastName\": \"Sedef\",\n \"email\": \"muhammetsedef34@gmail.com\",\n \"addressText\": \"Küçükçekmece/İstanbul\"\n}", 16 | "options": { 17 | "raw": { 18 | "language": "json" 19 | } 20 | } 21 | }, 22 | "url": { 23 | "raw": "http://localhost:8000/api/user/", 24 | "protocol": "http", 25 | "host": [ 26 | "localhost" 27 | ], 28 | "port": "8000", 29 | "path": [ 30 | "api", 31 | "user", 32 | "" 33 | ] 34 | } 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "get user detail", 40 | "request": { 41 | "method": "GET", 42 | "header": [], 43 | "url": { 44 | "raw": "http://localhost:8000/api/user/1", 45 | "protocol": "http", 46 | "host": [ 47 | "localhost" 48 | ], 49 | "port": "8000", 50 | "path": [ 51 | "api", 52 | "user", 53 | "1" 54 | ] 55 | } 56 | }, 57 | "response": [] 58 | } 59 | ] 60 | } -------------------------------------------------------------------------------- /user-address-service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /user-address-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/user-address-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /user-address-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /user-address-service/infra-setup/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Use postgres/example user/password credentials 2 | version: '3.1' 3 | 4 | services: 5 | kafka-example-db: 6 | image: postgres 7 | restart: always 8 | container_name: "kafka-example-db" 9 | ports: 10 | - "5432:5432" 11 | environment: 12 | POSTGRES_PASSWORD: example 13 | POSTGRES_USER: example 14 | POSTGRES_DB: kafka_example 15 | zookeeper: 16 | image: "docker.io/bitnami/zookeeper:3" 17 | ports: 18 | - "2181:2181" 19 | volumes: 20 | - "zookeeper_data:/bitnami" 21 | environment: 22 | - ALLOW_ANONYMOUS_LOGIN=yes 23 | kafka: 24 | image: "docker.io/bitnami/kafka:2-debian-10" 25 | ports: 26 | - "9092:9092" 27 | expose: 28 | - "9093" 29 | volumes: 30 | - "kafka_data:/bitnami" 31 | environment: 32 | - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 33 | - ALLOW_PLAINTEXT_LISTENER=yes 34 | - KAFKA_ADVERTISED_LISTENERS=INSIDE://kafka:9093,OUTSIDE://localhost:9092 35 | - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT 36 | - KAFKA_LISTENERS=INSIDE://0.0.0.0:9093,OUTSIDE://0.0.0.0:9092 37 | - KAFKA_INTER_BROKER_LISTENER_NAME=INSIDE 38 | - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 39 | depends_on: 40 | - zookeeper 41 | kafka-ui: 42 | image: provectuslabs/kafka-ui 43 | container_name: kafka-ui 44 | ports: 45 | - "9090:8080" 46 | restart: always 47 | environment: 48 | - KAFKA_CLUSTERS_0_NAME=local 49 | - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka:9093 50 | - KAFKA_CLUSTERS_0_ZOOKEEPER=localhost:2181 51 | 52 | volumes: 53 | zookeeper_data: 54 | driver: local 55 | kafka_data: 56 | driver: local -------------------------------------------------------------------------------- /user-address-service/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /user-address-service/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /user-address-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.5 9 | 10 | 11 | com.example 12 | user-address-service 13 | 0.0.1-SNAPSHOT 14 | user-address-service 15 | user-address-service 16 | 17 | 11 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | org.springframework.kafka 26 | spring-kafka 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-data-jpa 32 | 33 | 34 | org.postgresql 35 | postgresql 36 | runtime 37 | 38 | 39 | org.projectlombok 40 | lombok 41 | true 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-configuration-processor 46 | true 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-test 51 | test 52 | 53 | 54 | org.springframework.kafka 55 | spring-kafka-test 56 | test 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | org.projectlombok 69 | lombok 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/UserAddressServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UserAddressServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UserAddressServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/consumers/configuration/UserCreatedKafkaConsumerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice.consumers.configuration; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.apache.kafka.clients.consumer.ConsumerConfig; 5 | import org.apache.kafka.common.serialization.StringDeserializer; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; 10 | import org.springframework.kafka.core.ConsumerFactory; 11 | import org.springframework.kafka.core.DefaultKafkaConsumerFactory; 12 | import org.springframework.kafka.support.converter.StringJsonMessageConverter; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | @Configuration 18 | @RequiredArgsConstructor 19 | public class UserCreatedKafkaConsumerConfiguration { 20 | 21 | @Value("${kafka.host}") 22 | private String host; 23 | 24 | public ConsumerFactory consumerFactory() { 25 | 26 | // Creating a Map of string-object pairs 27 | Map config = new HashMap<>(); 28 | 29 | // Adding the Configuration 30 | config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, host); 31 | config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 32 | config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); 33 | //config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true); 34 | 35 | return new DefaultKafkaConsumerFactory<>(config); 36 | } 37 | 38 | @Bean 39 | // Creating a Listener 40 | public ConcurrentKafkaListenerContainerFactory concurrentKafkaListenerContainerFactory() { 41 | ConcurrentKafkaListenerContainerFactory factory 42 | = new ConcurrentKafkaListenerContainerFactory<>(); 43 | factory.setConsumerFactory(consumerFactory()); 44 | factory.setMessageConverter(new StringJsonMessageConverter()); 45 | return factory; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/consumers/configuration/properties/UserCreatedConsumerProperties.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice.consumers.configuration.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | @ConfigurationProperties(prefix = "kafka.topics.user-created") 10 | @Getter 11 | @Setter 12 | public class UserCreatedConsumerProperties { 13 | private String topic; 14 | private String consumerGroup; 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/consumers/consumer/UserCreatedEventConsumer.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice.consumers.consumer; 2 | 3 | import com.example.useraddressservice.consumers.model.UserCreatedEvent; 4 | import com.example.useraddressservice.entity.Address; 5 | import com.example.useraddressservice.service.AddressService; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.apache.kafka.clients.consumer.ConsumerRecord; 9 | import org.springframework.kafka.annotation.KafkaListener; 10 | import org.springframework.messaging.handler.annotation.Headers; 11 | import org.springframework.messaging.handler.annotation.Payload; 12 | import org.springframework.stereotype.Component; 13 | 14 | 15 | @Component 16 | @RequiredArgsConstructor 17 | @Slf4j 18 | public class UserCreatedEventConsumer { 19 | 20 | private final AddressService addressService; 21 | 22 | 23 | @KafkaListener(topics = "${kafka.topics.user-created.topic}", 24 | groupId = "${kafka.topics.user-created.consumerGroup}", 25 | containerFactory = "concurrentKafkaListenerContainerFactory" 26 | ) 27 | public void consumeCreatedUserEvent(@Payload UserCreatedEvent eventData, 28 | @Headers ConsumerRecord consumerRecord) { 29 | log.info("UserCreatedEventConsumer.consumeApprovalRequestResultedEvent consumed EVENT :{} " + 30 | "from partition : {} " + 31 | "with offset : {} " + 32 | "thread : {} " + 33 | "for message key: {}", 34 | eventData, consumerRecord.partition(), consumerRecord.offset(), Thread.currentThread().getName(), consumerRecord.key()); 35 | 36 | Address entity = UserCreatedEvent.getAddressEntityFromEvent(eventData); 37 | 38 | addressService.save(entity); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/consumers/model/UserCreatedEvent.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice.consumers.model; 2 | 3 | import com.example.useraddressservice.entity.Address; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | import lombok.ToString; 10 | 11 | @Getter 12 | @Setter 13 | @ToString 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | @Builder 17 | public class UserCreatedEvent { 18 | private Long id; 19 | private String addressText; 20 | 21 | public static Address getAddressEntityFromEvent(UserCreatedEvent event) { 22 | return Address.builder() 23 | .userId(event.getId()) 24 | .addressText(event.getAddressText()) 25 | .build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/controller/AddressController.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice.controller; 2 | 3 | import com.example.useraddressservice.entity.Address; 4 | import com.example.useraddressservice.service.AddressService; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | @RequiredArgsConstructor 13 | @RequestMapping("/api/address") 14 | public class AddressController { 15 | 16 | private final AddressService addressService; 17 | 18 | @GetMapping("/{userId}") 19 | public Address getAddressByUserId(@PathVariable Long userId) { 20 | return addressService.getAddressByUserId(userId); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/entity/Address.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.Entity; 10 | import javax.persistence.GeneratedValue; 11 | import javax.persistence.GenerationType; 12 | import javax.persistence.Id; 13 | import javax.persistence.Table; 14 | 15 | @Entity 16 | @Table(name = "user_address") 17 | @Data 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | @Builder 21 | public class Address { 22 | @Id 23 | @Column(name = "id") 24 | @GeneratedValue(strategy = GenerationType.IDENTITY) 25 | private Long id; 26 | 27 | @Column(name = "user_id") 28 | private Long userId; 29 | 30 | @Column(name = "address_text") 31 | private String addressText; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/repository/AddressRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice.repository; 2 | 3 | import com.example.useraddressservice.entity.Address; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.data.jpa.repository.Query; 6 | import org.springframework.data.repository.query.Param; 7 | import org.springframework.stereotype.Repository; 8 | 9 | @Repository 10 | public interface AddressRepository extends JpaRepository { 11 | 12 | @Query(value = "from Address a where a.userId=:userId") 13 | Address findByUserId(@Param("userId") Long userId); 14 | } 15 | -------------------------------------------------------------------------------- /user-address-service/src/main/java/com/example/useraddressservice/service/AddressService.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice.service; 2 | 3 | import com.example.useraddressservice.entity.Address; 4 | import com.example.useraddressservice.repository.AddressRepository; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | @RequiredArgsConstructor 10 | public class AddressService { 11 | 12 | private final AddressRepository addressRepository; 13 | 14 | public Address save(Address address) { 15 | return addressRepository.save(address); 16 | } 17 | 18 | public Address getAddressByUserId(Long userId) { 19 | return addressRepository.findByUserId(userId); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /user-address-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: address_service 4 | datasource: 5 | username: example 6 | password: example 7 | url: jdbc:postgresql://localhost:5432/kafka_example 8 | jpa: 9 | properties: 10 | hibernate: 11 | dialect: org.hibernate.dialect.PostgreSQLDialect 12 | format_sql: true 13 | show-sql: false 14 | hibernate: 15 | ddl-auto: update 16 | 17 | server: 18 | port: 0 19 | 20 | kafka: 21 | host: localhost:9092 22 | topics: 23 | user-created: 24 | topic: user_service.user_created.0 25 | consumerGroup: ${spring.application.name}-user-created-consumer 26 | replicationFactor: 1 27 | retentionInMs: 604800000 28 | -------------------------------------------------------------------------------- /user-address-service/src/test/java/com/example/useraddressservice/UserAddressServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.useraddressservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class UserAddressServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /user-service/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /user-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedsedef/Kafka-Example/3f0c43cc29d45a14d6c01a410e627dc2b6330cfa/user-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /user-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar 3 | -------------------------------------------------------------------------------- /user-service/infra-setup/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Use postgres/example user/password credentials 2 | version: '3.1' 3 | 4 | services: 5 | kafka-example-db: 6 | image: postgres 7 | restart: always 8 | container_name: "kafka-example-db" 9 | ports: 10 | - "5432:5432" 11 | environment: 12 | POSTGRES_PASSWORD: example 13 | POSTGRES_USER: example 14 | POSTGRES_DB: kafka_example 15 | zookeeper: 16 | image: "docker.io/bitnami/zookeeper:3" 17 | ports: 18 | - "2181:2181" 19 | volumes: 20 | - "zookeeper_data:/bitnami" 21 | environment: 22 | - ALLOW_ANONYMOUS_LOGIN=yes 23 | kafka: 24 | image: "docker.io/bitnami/kafka:2-debian-10" 25 | ports: 26 | - "9092:9092" 27 | expose: 28 | - "9093" 29 | volumes: 30 | - "kafka_data:/bitnami" 31 | environment: 32 | - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 33 | - ALLOW_PLAINTEXT_LISTENER=yes 34 | - KAFKA_ADVERTISED_LISTENERS=INSIDE://kafka:9093,OUTSIDE://localhost:9092 35 | - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT 36 | - KAFKA_LISTENERS=INSIDE://0.0.0.0:9093,OUTSIDE://0.0.0.0:9092 37 | - KAFKA_INTER_BROKER_LISTENER_NAME=INSIDE 38 | - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 39 | depends_on: 40 | - zookeeper 41 | kafka-ui: 42 | image: provectuslabs/kafka-ui 43 | container_name: kafka-ui 44 | ports: 45 | - "9090:8080" 46 | restart: always 47 | environment: 48 | - KAFKA_CLUSTERS_0_NAME=local 49 | - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka:9093 50 | - KAFKA_CLUSTERS_0_ZOOKEEPER=localhost:2181 51 | 52 | volumes: 53 | zookeeper_data: 54 | driver: local 55 | kafka_data: 56 | driver: local -------------------------------------------------------------------------------- /user-service/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /user-service/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /user-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.5 9 | 10 | 11 | com.example 12 | user-service 13 | 0.0.1-SNAPSHOT 14 | user-service 15 | user-service 16 | 17 | 11 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-web 23 | 24 | 25 | org.springframework.kafka 26 | spring-kafka 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-data-jpa 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-configuration-processor 36 | true 37 | 38 | 39 | org.postgresql 40 | postgresql 41 | runtime 42 | 43 | 44 | org.projectlombok 45 | lombok 46 | true 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-test 51 | test 52 | 53 | 54 | org.springframework.kafka 55 | spring-kafka-test 56 | test 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | org.projectlombok 69 | lombok 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/UserServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UserServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UserServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/config/kafka/configuration/KafkaProducerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.config.kafka.configuration; 2 | 3 | import org.apache.kafka.clients.producer.ProducerConfig; 4 | import org.apache.kafka.common.serialization.StringSerializer; 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.kafka.core.DefaultKafkaProducerFactory; 9 | import org.springframework.kafka.core.KafkaTemplate; 10 | import org.springframework.kafka.core.ProducerFactory; 11 | import org.springframework.kafka.support.serializer.JsonSerializer; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | @Configuration 17 | public class KafkaProducerConfiguration { 18 | 19 | @Value("${kafka.host}") 20 | private String kafkaBrokers; 21 | 22 | @Bean 23 | public KafkaTemplate tyKafkaTemplate() { 24 | return new KafkaTemplate<>(producerConfig()); 25 | } 26 | 27 | private ProducerFactory producerConfig() { 28 | Map config = new HashMap<>(); 29 | config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaBrokers); 30 | config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); 31 | config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); 32 | return new DefaultKafkaProducerFactory<>(config); 33 | } 34 | } -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/config/kafka/producer/KafkaProducer.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.config.kafka.producer; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.kafka.core.KafkaTemplate; 6 | import org.springframework.kafka.support.SendResult; 7 | import org.springframework.messaging.support.GenericMessage; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.util.concurrent.ListenableFuture; 10 | import org.springframework.util.concurrent.ListenableFutureCallback; 11 | 12 | import java.util.Objects; 13 | 14 | 15 | @Component 16 | @RequiredArgsConstructor 17 | @Slf4j 18 | public class KafkaProducer { 19 | 20 | private final KafkaTemplate kafkaTemplate; 21 | 22 | public void sendMessage(GenericMessage message) { 23 | final ListenableFuture> listenableResult = kafkaTemplate.send(message); 24 | 25 | listenableResult.addCallback(new ListenableFutureCallback>() { 26 | @Override 27 | public void onSuccess(SendResult result) { 28 | if (Objects.isNull(result)) { 29 | log.info("Empty result on success for message {}", message); 30 | return; 31 | } 32 | log.info("Message :{} published, topic : {}, partition : {} and offset : {}", message.getPayload(), 33 | result.getRecordMetadata().topic(), 34 | result.getRecordMetadata().partition(), 35 | result.getRecordMetadata().offset()); 36 | } 37 | 38 | @Override 39 | public void onFailure(Throwable ex) { 40 | log.error("Unable to deliver message to kafka", ex); 41 | } 42 | }); 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/config/kafka/properties/UserCreatedTopicProperties.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.config.kafka.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | @ConfigurationProperties(prefix = "kafka.topics.user-created") 10 | @Getter 11 | @Setter 12 | public class UserCreatedTopicProperties { 13 | private String topicName; 14 | private int partitionCount; 15 | private short replicationFactor; 16 | private String retentionInMs; 17 | } 18 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.controller; 2 | 3 | import com.example.userservice.dto.AddressResponseDto; 4 | import com.example.userservice.dto.UserCreateRequest; 5 | import com.example.userservice.dto.UserResponse; 6 | import com.example.userservice.entity.User; 7 | import com.example.userservice.service.UserService; 8 | import lombok.RequiredArgsConstructor; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.PathVariable; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestBody; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RestController; 16 | import org.springframework.web.client.RestTemplate; 17 | 18 | @RestController 19 | @RequestMapping("/api/user") 20 | @RequiredArgsConstructor 21 | public class UserController { 22 | private RestTemplate restTemplate = new RestTemplate(); 23 | private final UserService userService; 24 | 25 | @PostMapping 26 | public User create(@RequestBody UserCreateRequest userCreateRequest) { 27 | return userService.create(userCreateRequest); 28 | } 29 | 30 | @GetMapping("/{userId}") 31 | public UserResponse getUserAddress(@PathVariable Long userId) { 32 | // You have to change user-address service port according to running port 33 | String url = String.format("http://localhost:8002/api/address/%s", userId); 34 | ResponseEntity address = restTemplate.getForEntity(url, AddressResponseDto.class); 35 | 36 | User user = userService.getUserById(address.getBody().getUserId()); 37 | return UserResponse.getUserResponseWithAddress(user, address.getBody()); 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/dto/AddressResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | 6 | @Data 7 | @NoArgsConstructor 8 | public class AddressResponseDto { 9 | private Long id; 10 | private Long userId; 11 | private String addressText; 12 | } 13 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/dto/BaseResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.dto; 2 | 3 | import lombok.Data; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | import java.util.Date; 8 | 9 | @Data 10 | @Getter 11 | @Setter 12 | public class BaseResponseDto { 13 | private Long id; 14 | private Date createdAt; 15 | private Date updatedAt; 16 | } 17 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/dto/UserCreateRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class UserCreateRequest { 7 | private String firstName; 8 | private String lastName; 9 | private String email; 10 | private String addressText; 11 | } 12 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/dto/UserCreatedPayload.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.dto; 2 | 3 | import com.example.userservice.entity.User; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | import java.util.Date; 8 | 9 | @Data 10 | @Builder 11 | public class UserCreatedPayload { 12 | 13 | private Long id; 14 | private String firstName; 15 | private String lastName; 16 | private String email; 17 | private String addressText; 18 | private Date createdAt; 19 | private Date updatedAt; 20 | private Boolean status; 21 | 22 | public static UserCreatedPayload GetUserCreatedPayload(User user, String addressText) { 23 | return UserCreatedPayload.builder() 24 | .id(user.getId()) 25 | .firstName(user.getFirstName()) 26 | .lastName(user.getLastName()) 27 | .email(user.getEmail()) 28 | .addressText(addressText) 29 | .createdAt(user.getCreatedAt()) 30 | .updatedAt(user.getUpdatedAt()) 31 | .status(user.getStatus()) 32 | .build(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/dto/UserResponse.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.dto; 2 | 3 | import com.example.userservice.entity.User; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | @Data 10 | @Getter 11 | @Setter 12 | @Builder 13 | public class UserResponse extends BaseResponseDto { 14 | private String firstName; 15 | private String lastName; 16 | private String email; 17 | private AddressResponseDto address; 18 | 19 | public static UserResponse getUserResponseWithAddress(User user, AddressResponseDto address) { 20 | UserResponse response = UserResponse.builder() 21 | .firstName(user.getFirstName()) 22 | .lastName(user.getLastName()) 23 | .email(user.getEmail()) 24 | .address(address) 25 | .build(); 26 | response.setId(user.getId()); 27 | response.setCreatedAt(user.getCreatedAt()); 28 | response.setCreatedAt(user.getCreatedAt()); 29 | return response; 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/entity/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.entity; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.hibernate.annotations.CreationTimestamp; 6 | import org.hibernate.annotations.UpdateTimestamp; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.MappedSuperclass; 10 | import java.util.Date; 11 | 12 | @Getter 13 | @Setter 14 | @MappedSuperclass 15 | public class BaseEntity { 16 | 17 | @Column(name = "created_at") 18 | //@Temporal(TemporalType.TIMESTAMP) 19 | @CreationTimestamp 20 | private Date createdAt; 21 | 22 | @Column(name = "updated_at") 23 | //@Temporal(TemporalType.TIMESTAMP) 24 | @UpdateTimestamp 25 | private Date updatedAt; 26 | 27 | @Column(name = "status") 28 | private Boolean status = true; 29 | } -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.entity; 2 | 3 | 4 | import com.example.userservice.dto.UserCreateRequest; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | 10 | import javax.persistence.Column; 11 | import javax.persistence.Entity; 12 | import javax.persistence.GeneratedValue; 13 | import javax.persistence.GenerationType; 14 | import javax.persistence.Id; 15 | import javax.persistence.Table; 16 | 17 | @Entity 18 | @Table(name = "users") 19 | 20 | @Data 21 | @NoArgsConstructor 22 | @AllArgsConstructor 23 | @Builder 24 | public class User extends BaseEntity { 25 | 26 | @Id 27 | @Column(name = "id") 28 | @GeneratedValue(strategy = GenerationType.IDENTITY) 29 | private Long id; 30 | 31 | @Column(name = "first_name", nullable = false) 32 | private String firstName; 33 | 34 | @Column(name = "last_name", nullable = false) 35 | private String lastName; 36 | 37 | //unique = true, 38 | @Column(name = "email", nullable = false) 39 | private String email; 40 | 41 | public static User getUser(UserCreateRequest userCreateRequest) { 42 | return User.builder() 43 | .firstName(userCreateRequest.getFirstName()) 44 | .lastName(userCreateRequest.getLastName()) 45 | .email(userCreateRequest.getEmail()) 46 | .build(); 47 | } 48 | } -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.repository; 2 | 3 | import com.example.userservice.entity.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface UserRepository extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/example/userservice/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice.service; 2 | 3 | import com.example.userservice.config.kafka.producer.KafkaProducer; 4 | import com.example.userservice.config.kafka.properties.UserCreatedTopicProperties; 5 | import com.example.userservice.dto.UserCreateRequest; 6 | import com.example.userservice.dto.UserCreatedPayload; 7 | import com.example.userservice.entity.User; 8 | import com.example.userservice.repository.UserRepository; 9 | import lombok.RequiredArgsConstructor; 10 | import org.springframework.messaging.support.GenericMessage; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.Optional; 16 | 17 | import static org.springframework.kafka.support.KafkaHeaders.MESSAGE_KEY; 18 | import static org.springframework.kafka.support.KafkaHeaders.TOPIC; 19 | 20 | @Service 21 | @RequiredArgsConstructor 22 | public class UserService { 23 | 24 | private final UserRepository userRepository; 25 | 26 | private final KafkaProducer kafkaProducer; 27 | 28 | private final UserCreatedTopicProperties userCreatedTopicProperties; 29 | 30 | public User create(UserCreateRequest userCreateRequest) { 31 | User user = User.getUser(userCreateRequest); 32 | User savedUser = userRepository.save(user); 33 | 34 | UserCreatedPayload payload = UserCreatedPayload.GetUserCreatedPayload(savedUser, userCreateRequest.getAddressText()); 35 | 36 | Map headers = new HashMap<>(); 37 | headers.put(TOPIC, userCreatedTopicProperties.getTopicName()); 38 | headers.put(MESSAGE_KEY, savedUser.getId().toString()); 39 | 40 | kafkaProducer.sendMessage(new GenericMessage<>(payload, headers)); 41 | return savedUser; 42 | } 43 | 44 | public User getUserById(Long id) { 45 | Optional userOptional = userRepository.findById(id); 46 | if (!userOptional.isPresent()) { 47 | return null; 48 | } 49 | return userOptional.get(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /user-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: user_service 4 | datasource: 5 | username: example 6 | password: example 7 | url: jdbc:postgresql://localhost:5432/kafka_example 8 | jpa: 9 | properties: 10 | hibernate: 11 | dialect: org.hibernate.dialect.PostgreSQLDialect 12 | format_sql: true 13 | show-sql: false 14 | hibernate: 15 | ddl-auto: update 16 | 17 | logging: 18 | level: 19 | root: INFO 20 | #web: DEBUG 21 | 22 | server: 23 | port: 8000 24 | 25 | kafka: 26 | host: localhost:9092 27 | topics: 28 | user-created: 29 | topicName: ${spring.application.name}.user_created.0 30 | partitionCount: 1 31 | replicationFactor: 1 32 | retentionInMs: 604800000 -------------------------------------------------------------------------------- /user-service/src/test/java/com/example/userservice/UserServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.userservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class UserServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------