├── .idea ├── .gitignore ├── SpringBootMicroservices.iml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── dataSources.xml ├── encodings.xml ├── jarRepositories.xml ├── misc.xml ├── modules.xml ├── sqldialects.xml └── vcs.xml ├── .vscode └── settings.json ├── CloudGateway ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── msbeigi │ │ │ └── cloudgateway │ │ │ ├── CloudGatewayApplication.java │ │ │ ├── controller │ │ │ ├── AuthenticationController.java │ │ │ └── FallbackController.java │ │ │ ├── model │ │ │ └── AuthenticationResponse.java │ │ │ └── security │ │ │ └── OktaOAuth2WebSecurity.java │ └── resources │ │ └── application.yaml │ └── test │ └── java │ └── com │ └── msbeigi │ └── cloudgateway │ └── CloudGatewayApplicationTests.java ├── ConfigServer ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── msbeigi │ │ │ └── configserver │ │ │ └── ConfigServerApplication.java │ └── resources │ │ └── application.yaml │ └── test │ └── java │ └── com │ └── msbeigi │ └── configserver │ └── ConfigServerApplicationTests.java ├── OrderService ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── msbeigi │ │ │ └── orderservice │ │ │ ├── OrderServiceApplication.java │ │ │ ├── config │ │ │ └── FeignConfig.java │ │ │ ├── controller │ │ │ └── OrderController.java │ │ │ ├── entity │ │ │ └── Order.java │ │ │ ├── exception │ │ │ ├── CustomException.java │ │ │ └── RestResponseEntityExceptionHandler.java │ │ │ ├── external │ │ │ ├── client │ │ │ │ ├── PaymentService.java │ │ │ │ └── ProductService.java │ │ │ ├── decoder │ │ │ │ └── CustomErrorDecoder.java │ │ │ ├── intercept │ │ │ │ ├── OAuthRequestInterceptor.java │ │ │ │ └── RestTemplateInterceptor.java │ │ │ ├── request │ │ │ │ └── PaymentRequest.java │ │ │ └── response │ │ │ │ ├── ErrorResponse.java │ │ │ │ ├── PaymentResponse.java │ │ │ │ └── ProductResponse.java │ │ │ ├── model │ │ │ ├── OrderRequest.java │ │ │ ├── OrderResponse.java │ │ │ └── PaymentMode.java │ │ │ ├── repository │ │ │ └── OrderRepository.java │ │ │ ├── security │ │ │ └── WebSecurityConfig.java │ │ │ └── services │ │ │ ├── OrderService.java │ │ │ └── OrderServiceImpl.java │ └── resources │ │ └── application.yaml │ └── test │ ├── java │ └── com │ │ └── msbeigi │ │ └── orderservice │ │ ├── OrderServiceApplicationTests.java │ │ ├── OrderServiceConfig.java │ │ ├── TestServiceInstanceListSupplier.java │ │ ├── controller │ │ └── OrderControllerTest.java │ │ └── services │ │ └── OrderServiceImplTest.java │ └── resources │ ├── application.yaml │ └── mock │ ├── GetPayment.json │ └── GetProduct.json ├── PaymentService ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── msbeigi │ │ │ └── paymentservice │ │ │ ├── PaymentServiceApplication.java │ │ │ ├── controller │ │ │ └── PaymentController.java │ │ │ ├── entity │ │ │ └── TransactionDetails.java │ │ │ ├── model │ │ │ ├── PaymentMode.java │ │ │ ├── PaymentRequest.java │ │ │ └── PaymentResponse.java │ │ │ ├── repository │ │ │ └── TransactionsDetailsRepository.java │ │ │ ├── security │ │ │ └── WebSecurityConfig.java │ │ │ └── services │ │ │ ├── PaymentService.java │ │ │ └── PaymentServiceImpl.java │ └── resources │ │ └── application.yaml │ └── test │ └── java │ └── com │ └── msbeigi │ └── paymentservice │ └── PaymentServiceApplicationTests.java ├── ProductService ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── msbeigi │ │ │ └── ProductService │ │ │ ├── ProductServiceApplication.java │ │ │ ├── controller │ │ │ └── ProductController.java │ │ │ ├── entity │ │ │ └── Product.java │ │ │ ├── exception │ │ │ ├── ProductServiceCustomException.java │ │ │ └── RestResponseEntityExceptionHandler.java │ │ │ ├── model │ │ │ ├── ErrorResponse.java │ │ │ ├── ProductRequest.java │ │ │ └── ProductResponse.java │ │ │ ├── repository │ │ │ └── ProductRepository.java │ │ │ ├── security │ │ │ └── WebSecurityConfig.java │ │ │ └── services │ │ │ ├── ProductService.java │ │ │ └── ProductServiceImpl.java │ └── resources │ │ └── application.yaml │ └── test │ └── java │ └── com │ └── msbeigi │ └── ProductService │ └── ProductServiceApplicationTests.java ├── README.md ├── ServiceRegistry ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── msbeigi │ │ │ └── serviceregistry │ │ │ └── ServiceRegistryApplication.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── msbeigi │ └── serviceregistry │ └── ServiceRegistryApplicationTests.java ├── docker-compose.yml ├── k8s-demo ├── deploy.yml └── svc.yml └── k8s ├── cloud-gateway-deployment.yml ├── config-maps.yml ├── config-server-deployment.yml ├── mysql-deployment.yml ├── order-service-deployhment.yml ├── payment-service-deployment.yml ├── product-service-deployment.yml ├── redis-deployment.yml ├── service-registry-statefulset.yml └── zipkin-deployment.yml /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/SpringBootMicroservices.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mysql.8 6 | true 7 | com.mysql.cj.jdbc.Driver 8 | jdbc:mysql://localhost:3306 9 | $ProjectFileDir$ 10 | 11 | 12 | redis 13 | true 14 | jdbc.RedisDriver 15 | jdbc:redis://localhost:6379/0 16 | $ProjectFileDir$ 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/sqldialects.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "yaml.schemas": { 3 | "kubernetes://schema/apps/v1%40deployment": "file:///home/mohsen/Documents/dev/java-projects/SpringBootMicroservices/k8s/payment-service-deployment.yml", 4 | "kubernetes://schema/v1@persistentvolume": "file:///home/mohsen/Documents/dev/java-projects/SpringBootMicroservices/k8s/mysql-deployment.yml" 5 | } 6 | } -------------------------------------------------------------------------------- /CloudGateway/.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 | -------------------------------------------------------------------------------- /CloudGateway/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msbeigiai/spring-boot-microservices/7c41c629c582ed45a45722b1ec1dba5fbe4574b3/CloudGateway/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /CloudGateway/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /CloudGateway/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | 3 | ARG JAR_FILE=target/*.jar 4 | 5 | COPY ${JAR_FILE} cloudgateway.jar 6 | 7 | ENTRYPOINT ["java", "-jar", "/cloudgateway.jar"] 8 | 9 | EXPOSE 9090 10 | 11 | -------------------------------------------------------------------------------- /CloudGateway/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 | -------------------------------------------------------------------------------- /CloudGateway/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 | -------------------------------------------------------------------------------- /CloudGateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.13 9 | 10 | 11 | com.msbeigi 12 | CloudGateway 13 | 0.0.1 14 | CloudGateway 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 2021.0.7 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-actuator 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-webflux 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-sleuth-zipkin 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-starter 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-starter-config 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-starter-gateway 44 | 45 | 46 | org.springframework.cloud 47 | spring-cloud-starter-netflix-eureka-client 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-starter-sleuth 52 | 53 | 54 | org.springframework.cloud 55 | spring-cloud-starter-circuitbreaker-reactor-resilience4j 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-starter-data-redis-reactive 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-starter-security 64 | 65 | 66 | com.okta.spring 67 | okta-spring-boot-starter 68 | 2.1.6 69 | 70 | 71 | org.projectlombok 72 | lombok 73 | true 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-starter-test 78 | test 79 | 80 | 81 | io.projectreactor 82 | reactor-test 83 | test 84 | 85 | 86 | 87 | 88 | 89 | 90 | org.springframework.cloud 91 | spring-cloud-dependencies 92 | ${spring-cloud.version} 93 | pom 94 | import 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | org.springframework.boot 103 | spring-boot-maven-plugin 104 | 105 | 106 | 107 | org.projectlombok 108 | lombok 109 | 110 | 111 | 112 | 113 | 114 | com.google.cloud.tools 115 | jib-maven-plugin 116 | 117 | 118 | openjdk:17 119 | 120 | 121 | registry.hub.docker.com/msbeigiai/cloudgateway 122 | ${project.version} 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /CloudGateway/src/main/java/com/msbeigi/cloudgateway/CloudGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.cloudgateway; 2 | 3 | import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory; 7 | import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder; 8 | import org.springframework.cloud.client.circuitbreaker.Customizer; 9 | import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; 10 | import org.springframework.context.annotation.Bean; 11 | import reactor.core.publisher.Mono; 12 | 13 | @SpringBootApplication 14 | public class CloudGatewayApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(CloudGatewayApplication.class, args); 18 | } 19 | 20 | @Bean 21 | KeyResolver userKeyResolver() { 22 | return exchange -> Mono.just("userKey"); 23 | } 24 | 25 | @Bean 26 | public Customizer defaultCustomizer() { 27 | return factory -> factory.configureDefault( 28 | id -> new Resilience4JConfigBuilder(id) 29 | .circuitBreakerConfig( 30 | CircuitBreakerConfig.ofDefaults() 31 | ).build() 32 | ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /CloudGateway/src/main/java/com/msbeigi/cloudgateway/controller/AuthenticationController.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.cloudgateway.controller; 2 | 3 | import com.msbeigi.cloudgateway.model.AuthenticationResponse; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.security.core.GrantedAuthority; 7 | import org.springframework.security.core.annotation.AuthenticationPrincipal; 8 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; 9 | import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient; 10 | import org.springframework.security.oauth2.core.oidc.user.OidcUser; 11 | import org.springframework.ui.Model; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import java.util.Objects; 17 | import java.util.stream.Collectors; 18 | 19 | @RestController 20 | @RequestMapping("/authenticate") 21 | public class AuthenticationController { 22 | 23 | @GetMapping("/login") 24 | public ResponseEntity login( 25 | @AuthenticationPrincipal OidcUser oidcUser, 26 | Model model, 27 | @RegisteredOAuth2AuthorizedClient("okta") OAuth2AuthorizedClient client 28 | ) { 29 | AuthenticationResponse authenticationResponse = 30 | AuthenticationResponse.builder() 31 | .userId(oidcUser.getEmail()) 32 | .accessToken(client.getAccessToken().getTokenValue()) 33 | .refreshToken(Objects.requireNonNull(client.getRefreshToken()).getTokenValue()) 34 | .expiresAt(Objects.requireNonNull(client.getAccessToken().getExpiresAt()).getEpochSecond()) 35 | .authorityList(oidcUser.getAuthorities() 36 | .stream() 37 | .map(GrantedAuthority::getAuthority) 38 | .collect(Collectors.toList())) 39 | .build(); 40 | return new ResponseEntity<>(authenticationResponse, HttpStatus.OK); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /CloudGateway/src/main/java/com/msbeigi/cloudgateway/controller/FallbackController.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.cloudgateway.controller; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | @RestController 7 | public class FallbackController { 8 | 9 | @GetMapping("/orderServiceFallBack") 10 | public String orderServiceFallBack() { 11 | return "Order service is down!"; 12 | } 13 | 14 | @GetMapping("/paymentServiceFallBack") 15 | public String paymentServiceFallBack() { 16 | return "Payment service is down!"; 17 | } 18 | 19 | @GetMapping("/productServiceFallBack") 20 | public String productServiceFallBack() { 21 | return "Product service is down!"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /CloudGateway/src/main/java/com/msbeigi/cloudgateway/model/AuthenticationResponse.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.cloudgateway.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.Collection; 9 | 10 | @Data 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @Builder 14 | public class AuthenticationResponse { 15 | private String userId; 16 | private String accessToken; 17 | private String refreshToken; 18 | private long expiresAt; 19 | private Collection authorityList; 20 | } 21 | -------------------------------------------------------------------------------- /CloudGateway/src/main/java/com/msbeigi/cloudgateway/security/OktaOAuth2WebSecurity.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.cloudgateway.security; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; 6 | import org.springframework.security.config.web.server.ServerHttpSecurity; 7 | import org.springframework.security.web.server.SecurityWebFilterChain; 8 | 9 | @Configuration 10 | @EnableWebFluxSecurity 11 | public class OktaOAuth2WebSecurity { 12 | 13 | @Bean 14 | public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity httpSecurity) { 15 | httpSecurity.authorizeExchange() 16 | .anyExchange() 17 | .authenticated() 18 | .and() 19 | .oauth2Login() 20 | .and() 21 | .oauth2ResourceServer() 22 | .jwt(); 23 | return httpSecurity.build(); 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /CloudGateway/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9090 3 | 4 | spring: 5 | redis: 6 | host: redis 7 | port: 6379 8 | application: 9 | name: API-GATEWAY 10 | config: 11 | import: configserver:${CONFIG_SERVER_URL:http://localhost:9296} 12 | 13 | cloud: 14 | gateway: 15 | routes: 16 | - id: ORDER-SERVICE 17 | uri: lb://ORDER-SERVICE 18 | predicates: 19 | - Path=/order/** 20 | filters: 21 | - name: CircuitBreaker 22 | args: 23 | name: ORDER-SERVICE 24 | fallbackuri: forward:/orderServiceFallBack 25 | - name: RequestRateLimiter 26 | args: 27 | redis-rate-limiter.replenishRate: 1 28 | redis-rate-limiter.burstCapacity: 1 29 | 30 | - id: PAYMENT-SERVICE 31 | uri: lb://PAYMENT-SERVICE 32 | predicates: 33 | - Path=/payment/** 34 | filters: 35 | - name: CircuitBreaker 36 | args: 37 | name: PAYMENT-SERVICE 38 | fallbackuri: forward:/paymentServiceFallBack 39 | - name: RequestRateLimiter 40 | args: 41 | redis-rate-limiter.replenishRate: 1 42 | redis-rate-limiter.burstCapacity: 1 43 | 44 | - id: PRODUCT-SERVICE 45 | uri: lb://PRODUCT-SERVICE 46 | predicates: 47 | - Path=/product/** 48 | filters: 49 | - name: CircuitBreaker 50 | args: 51 | name: PRODUCT-SERVICE 52 | fallbackuri: forward:/paymentServiceFallBack 53 | - name: RequestRateLimiter 54 | args: 55 | redis-rate-limiter.replenishRate: 1 56 | redis-rate-limiter.burstCapacity: 1 57 | 58 | okta: 59 | oauth2: 60 | issuer: https://dev-64973606.okta.com/oauth2/default 61 | audience: api://default 62 | client-id: 0oaa4cqbuyzWeNFec5d7 63 | client-secret: 1TQczKd2HajEL74KggFBLI5uKHDexYU5-ybSYKms 64 | scopes: openid, email, profile, offline_access 65 | -------------------------------------------------------------------------------- /CloudGateway/src/test/java/com/msbeigi/cloudgateway/CloudGatewayApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.cloudgateway; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class CloudGatewayApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ConfigServer/.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 | -------------------------------------------------------------------------------- /ConfigServer/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msbeigiai/spring-boot-microservices/7c41c629c582ed45a45722b1ec1dba5fbe4574b3/ConfigServer/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /ConfigServer/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /ConfigServer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | 3 | ARG JAR_FILE=target/*.jar 4 | 5 | COPY ${JAR_FILE} configserver.jar 6 | 7 | ENTRYPOINT ["java", "-jar", "/configserver.jar"] 8 | 9 | EXPOSE 9296 10 | 11 | -------------------------------------------------------------------------------- /ConfigServer/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 | -------------------------------------------------------------------------------- /ConfigServer/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 | -------------------------------------------------------------------------------- /ConfigServer/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.13 9 | 10 | 11 | com.msbeigi 12 | ConfigServer 13 | 0.0.1 14 | ConfigServer 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 2021.0.7 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-config-server 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-starter-netflix-eureka-client 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.cloud 40 | spring-cloud-dependencies 41 | ${spring-cloud.version} 42 | pom 43 | import 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | 55 | com.google.cloud.tools 56 | jib-maven-plugin 57 | 58 | 59 | openjdk:17 60 | 61 | 62 | registry.hub.docker.com/msbeigiai/configserver 63 | ${project.version} 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /ConfigServer/src/main/java/com/msbeigi/configserver/ConfigServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.configserver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | @SpringBootApplication 8 | @EnableConfigServer 9 | public class ConfigServerApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ConfigServerApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ConfigServer/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 9296 3 | 4 | spring: 5 | application: 6 | name: CONFIG-SERVER 7 | cloud: 8 | config: 9 | server: 10 | git: 11 | uri: https://github.com/msbeigiai/spring-app-config 12 | clone-on-start: true 13 | 14 | eureka: 15 | instance: 16 | prefer-ip-address: true 17 | client: 18 | fetch-registry: true 19 | register-with-eureka: true 20 | service-url: 21 | defaultZone: ${EUREKA_SERVER_ADDRESS:http://localhost:8761/eureka} 22 | 23 | -------------------------------------------------------------------------------- /ConfigServer/src/test/java/com/msbeigi/configserver/ConfigServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.configserver; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ConfigServerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /OrderService/.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 | -------------------------------------------------------------------------------- /OrderService/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msbeigiai/spring-boot-microservices/7c41c629c582ed45a45722b1ec1dba5fbe4574b3/OrderService/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /OrderService/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /OrderService/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | 3 | ARG JAR_FILE=target/*.jar 4 | 5 | COPY ${JAR_FILE} orderservice.jar 6 | 7 | ENTRYPOINT ["java", "-jar", "/orderservice.jar"] 8 | 9 | EXPOSE 8082 10 | 11 | -------------------------------------------------------------------------------- /OrderService/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 | -------------------------------------------------------------------------------- /OrderService/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.12 9 | 10 | 11 | com.msbeigi 12 | OrderService 13 | 0.0.1 14 | OrderService 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 2021.0.7 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-data-jpa 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-starter-netflix-eureka-client 36 | 37 | 38 | 39 | com.mysql 40 | mysql-connector-j 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 | 55 | org.springframework.cloud 56 | spring-cloud-starter-config 57 | 58 | 59 | 60 | org.springframework.cloud 61 | spring-cloud-starter-openfeign 62 | 63 | 64 | 65 | org.springframework.cloud 66 | spring-cloud-sleuth-zipkin 67 | 68 | 69 | org.springframework.cloud 70 | spring-cloud-starter-sleuth 71 | 72 | 73 | org.springframework.cloud 74 | spring-cloud-starter-circuitbreaker-reactor-resilience4j 75 | 76 | 77 | 78 | org.springframework.boot 79 | spring-boot-starter-oauth2-client 80 | 81 | 82 | org.springframework.boot 83 | spring-boot-starter-security 84 | 85 | 86 | com.okta.spring 87 | okta-spring-boot-starter 88 | 2.1.6 89 | 90 | 91 | com.github.tomakehurst 92 | wiremock-jre8 93 | 2.35.0 94 | test 95 | 96 | 97 | 98 | com.h2database 99 | h2 100 | runtime 101 | 102 | 103 | org.springframework.security 104 | spring-security-test 105 | test 106 | 107 | 108 | 109 | 110 | 111 | org.springframework.cloud 112 | spring-cloud-dependencies 113 | ${spring-cloud.version} 114 | pom 115 | import 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | org.springframework.boot 124 | spring-boot-maven-plugin 125 | 126 | 127 | 128 | org.projectlombok 129 | lombok 130 | 131 | 132 | 133 | 134 | 135 | com.google.cloud.tools 136 | jib-maven-plugin 137 | 138 | 139 | openjdk:17 140 | 141 | 142 | registry.hub.docker.com/msbeigiai/orderservice 143 | ${project.version} 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/OrderServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice; 2 | 3 | import com.msbeigi.orderservice.external.intercept.RestTemplateInterceptor; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 8 | import org.springframework.cloud.openfeign.EnableFeignClients; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; 11 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider; 12 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder; 13 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 14 | import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager; 15 | import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; 16 | import org.springframework.web.client.RestTemplate; 17 | 18 | import java.util.Arrays; 19 | import java.util.List; 20 | 21 | @SpringBootApplication 22 | @EnableFeignClients 23 | public class OrderServiceApplication { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(OrderServiceApplication.class, args); 27 | } 28 | 29 | @Autowired 30 | private ClientRegistrationRepository clientRegistrationRepository; 31 | 32 | @Autowired 33 | private OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository; 34 | 35 | @Bean 36 | @LoadBalanced 37 | public RestTemplate restTemplate() { 38 | RestTemplate restTemplate = new RestTemplate(); 39 | 40 | restTemplate.setInterceptors( 41 | Arrays.asList( 42 | new RestTemplateInterceptor( 43 | clientManager(clientRegistrationRepository, 44 | oAuth2AuthorizedClientRepository) 45 | ) 46 | ) 47 | ); 48 | return restTemplate; 49 | } 50 | 51 | @Bean 52 | public OAuth2AuthorizedClientManager clientManager( 53 | ClientRegistrationRepository clientRegistrationRepository, 54 | OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository 55 | ) { 56 | OAuth2AuthorizedClientProvider oAuth2AuthorizedClientProvider = 57 | OAuth2AuthorizedClientProviderBuilder 58 | .builder() 59 | .clientCredentials() 60 | .build(); 61 | DefaultOAuth2AuthorizedClientManager oAuth2AuthorizedClientManager = 62 | new DefaultOAuth2AuthorizedClientManager( 63 | clientRegistrationRepository, 64 | oAuth2AuthorizedClientRepository 65 | ); 66 | oAuth2AuthorizedClientManager.setAuthorizedClientProvider( 67 | oAuth2AuthorizedClientProvider 68 | ); 69 | 70 | return oAuth2AuthorizedClientManager; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/config/FeignConfig.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.config; 2 | 3 | import com.msbeigi.orderservice.external.decoder.CustomErrorDecoder; 4 | import feign.codec.ErrorDecoder; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class FeignConfig { 10 | 11 | @Bean 12 | ErrorDecoder errorDecoder() { 13 | return new CustomErrorDecoder(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/controller/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.controller; 2 | 3 | import com.msbeigi.orderservice.model.OrderRequest; 4 | import com.msbeigi.orderservice.model.OrderResponse; 5 | import com.msbeigi.orderservice.services.OrderService; 6 | import lombok.extern.log4j.Log4j2; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.security.access.prepost.PreAuthorize; 11 | import org.springframework.web.bind.annotation.*; 12 | 13 | @RestController 14 | @RequestMapping("/order") 15 | @Log4j2 16 | public class OrderController { 17 | 18 | @Autowired 19 | private OrderService orderService; 20 | 21 | @PreAuthorize("hasAuthority('Customer')") 22 | @PostMapping("/placeOrder") 23 | public ResponseEntity placeOrder(@RequestBody OrderRequest orderRequest) { 24 | long orderId = orderService.placeOrder(orderRequest); 25 | log.info("Order id has been submitted: {}", orderId); 26 | return new ResponseEntity<>(orderId, HttpStatus.OK); 27 | } 28 | 29 | @PreAuthorize("hasAuthority('Admin') || hasAuthority('Customer')") 30 | @GetMapping("/{orderId}") 31 | public ResponseEntity getOrderDetailsById(@PathVariable long orderId) { 32 | OrderResponse orderResponse = 33 | orderService.getOrderDetailsById(orderId); 34 | 35 | return new ResponseEntity<>(orderResponse, HttpStatus.OK); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/entity/Order.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.entity; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.persistence.*; 10 | import java.time.Instant; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Builder 16 | @Entity 17 | @Table(name = "order_details") 18 | public class Order { 19 | 20 | @Id 21 | @GeneratedValue(strategy = GenerationType.AUTO) 22 | private long id; 23 | 24 | @Column(name = "product_id") 25 | private long productId; 26 | 27 | @Column(name = "quantity") 28 | private long quantity; 29 | 30 | @Column(name = "order_date") 31 | private Instant orderDate; 32 | 33 | @Column(name = "status") 34 | private String orderStatus; 35 | 36 | @Column(name = "total_amount") 37 | private long amount; 38 | } 39 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/exception/CustomException.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.exception; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class CustomException extends RuntimeException { 7 | 8 | private String errorCode; 9 | private int status; 10 | 11 | public CustomException(String message, String errorCode, int status) { 12 | super(message); 13 | this.errorCode = errorCode; 14 | this.status = status; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/exception/RestResponseEntityExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.exception; 2 | 3 | 4 | import com.msbeigi.orderservice.external.response.ErrorResponse; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 10 | 11 | @ControllerAdvice 12 | public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { 13 | 14 | @ExceptionHandler(CustomException.class) 15 | public ResponseEntity handleCustomException(CustomException exception) { 16 | return new ResponseEntity<>(ErrorResponse.builder() 17 | .errorMessage(exception.getMessage()) 18 | .errorCode(exception.getErrorCode()) 19 | .build(), 20 | HttpStatus.valueOf(exception.getStatus())); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/client/PaymentService.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.client; 2 | 3 | import com.msbeigi.orderservice.exception.CustomException; 4 | import com.msbeigi.orderservice.external.request.PaymentRequest; 5 | import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; 6 | import org.springframework.cloud.openfeign.FeignClient; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | 11 | @CircuitBreaker(name = "external", fallbackMethod = "fallback") 12 | @FeignClient(name = "PAYMENT-SERVICE/payment") 13 | public interface PaymentService { 14 | @PostMapping 15 | ResponseEntity doPayment(@RequestBody PaymentRequest paymentRequest); 16 | 17 | default ResponseEntity fallback(Exception e) { 18 | throw new CustomException("Payment service is not available ", "UNAVAILABLE", 500); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/client/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.client; 2 | 3 | import com.msbeigi.orderservice.exception.CustomException; 4 | import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; 5 | import org.springframework.cloud.openfeign.FeignClient; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.PutMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | 11 | 12 | @CircuitBreaker(name = "external", fallbackMethod = "fallback") 13 | @FeignClient(name = "PRODUCT-SERVICE/product") 14 | public interface ProductService { 15 | 16 | @PutMapping("/reduceQuantity/{id}") 17 | ResponseEntity reduceQuantity( 18 | @PathVariable("id") long productId, 19 | @RequestParam long quantity); 20 | 21 | default ResponseEntity fallback(Exception e) { 22 | throw new CustomException("Product service is not available ", "UNAVAILABLE", 500); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/decoder/CustomErrorDecoder.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.decoder; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.msbeigi.orderservice.exception.CustomException; 5 | import com.msbeigi.orderservice.external.response.ErrorResponse; 6 | import feign.Response; 7 | import feign.codec.ErrorDecoder; 8 | import lombok.extern.log4j.Log4j2; 9 | 10 | import java.io.IOException; 11 | 12 | @Log4j2 13 | public class CustomErrorDecoder implements ErrorDecoder { 14 | 15 | @Override 16 | public Exception decode(String s, Response response) { 17 | ObjectMapper objectMapper = new ObjectMapper(); 18 | 19 | log.info("::{}", response.request().url()); 20 | log.info("::{}", response.request().headers()); 21 | 22 | try { 23 | ErrorResponse errorResponse = 24 | objectMapper.readValue(response.body().asInputStream(), 25 | ErrorResponse.class); 26 | return new CustomException(errorResponse.getErrorMessage(), 27 | errorResponse.getErrorCode(), response.status()); 28 | } catch (IOException e) { 29 | throw new CustomException("Internal Server Error", 30 | "INTERNAL_SERVER_ERROR", 500); 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/intercept/OAuthRequestInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.intercept; 2 | 3 | import feign.RequestInterceptor; 4 | import feign.RequestTemplate; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; 8 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; 9 | 10 | @Configuration 11 | public class OAuthRequestInterceptor implements RequestInterceptor { 12 | 13 | @Autowired 14 | private OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager; 15 | 16 | @Override 17 | public void apply(RequestTemplate template) { 18 | template.header("Authorization", "Bearer " + 19 | oAuth2AuthorizedClientManager 20 | .authorize(OAuth2AuthorizeRequest 21 | .withClientRegistrationId("internal-client") 22 | .principal("internal") 23 | .build()) 24 | .getAccessToken().getTokenValue()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/intercept/RestTemplateInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.intercept; 2 | 3 | import org.springframework.http.HttpRequest; 4 | import org.springframework.http.client.ClientHttpRequestExecution; 5 | import org.springframework.http.client.ClientHttpRequestInterceptor; 6 | import org.springframework.http.client.ClientHttpResponse; 7 | import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest; 8 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; 9 | 10 | import java.io.IOException; 11 | 12 | public class RestTemplateInterceptor implements ClientHttpRequestInterceptor { 13 | 14 | private OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager; 15 | 16 | public RestTemplateInterceptor(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) { 17 | this.oAuth2AuthorizedClientManager = oAuth2AuthorizedClientManager; 18 | } 19 | 20 | @Override 21 | public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { 22 | request.getHeaders() 23 | .add("Authorization", "Bearer " + 24 | oAuth2AuthorizedClientManager 25 | .authorize(OAuth2AuthorizeRequest 26 | .withClientRegistrationId("internal-client") 27 | .principal("internal") 28 | .build()) 29 | .getAccessToken() 30 | .getTokenValue()); 31 | return execution.execute(request, body); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/request/PaymentRequest.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.request; 2 | 3 | import com.msbeigi.orderservice.model.PaymentMode; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Data 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @Builder 13 | public class PaymentRequest { 14 | 15 | private long orderId; 16 | private long amount; 17 | private String referenceNumber; 18 | private PaymentMode paymentMode; 19 | } 20 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/response/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.response; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Builder 12 | public class ErrorResponse { 13 | 14 | private String errorMessage; 15 | private String errorCode; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/response/PaymentResponse.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.response; 2 | 3 | import com.msbeigi.orderservice.model.PaymentMode; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.time.Instant; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @Builder 15 | public class PaymentResponse { 16 | private long paymentId; 17 | private String status; 18 | private PaymentMode paymentMode; 19 | private long amount; 20 | private Instant paymentDate; 21 | private long orderId; 22 | } 23 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/external/response/ProductResponse.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.external.response; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Builder 12 | public class ProductResponse { 13 | private long productId; 14 | private String productName; 15 | private long quantity; 16 | private long price; 17 | } 18 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/model/OrderRequest.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.model; 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 java.time.Instant; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @Builder 15 | public class OrderRequest { 16 | private long productId; 17 | private long totalAmount; 18 | private long quantity; 19 | private PaymentMode paymentMode; 20 | } 21 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/model/OrderResponse.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.Instant; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @Builder 14 | public class OrderResponse { 15 | private long orderId; 16 | private Instant orderDate; 17 | private String orderStatus; 18 | private long amount; 19 | private ProductDetails productDetails; 20 | private PaymentDetails paymentDetails; 21 | 22 | @Data 23 | @AllArgsConstructor 24 | @NoArgsConstructor 25 | @Builder 26 | public static class ProductDetails { 27 | private long productId; 28 | private String productName; 29 | private long quantity; 30 | private long price; 31 | } 32 | 33 | @Data 34 | @AllArgsConstructor 35 | @NoArgsConstructor 36 | @Builder 37 | public static class PaymentDetails { 38 | private long paymentId; 39 | private PaymentMode paymentMode; 40 | private String paymentStatus; 41 | private Instant paymentDate; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/model/PaymentMode.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.model; 2 | 3 | public enum PaymentMode { 4 | CASH, 5 | PAYPAL, 6 | DEBIT_CARD, 7 | CREDIT_CARD, 8 | APPLE_PAY 9 | } 10 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.repository; 2 | 3 | import com.msbeigi.orderservice.entity.Order; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface OrderRepository extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/security/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.security; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 8 | import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; 9 | import org.springframework.security.web.SecurityFilterChain; 10 | 11 | @Configuration 12 | @EnableWebSecurity 13 | @EnableGlobalMethodSecurity(prePostEnabled = true) 14 | public class WebSecurityConfig { 15 | 16 | @Bean 17 | public SecurityFilterChain securityWebFilterChain(HttpSecurity httpSecurity) throws Exception { 18 | httpSecurity 19 | .authorizeRequests(authorizeRequest -> authorizeRequest 20 | .anyRequest() 21 | .authenticated() 22 | ) 23 | .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); 24 | 25 | return httpSecurity.build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/services/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.services; 2 | 3 | import com.msbeigi.orderservice.model.OrderRequest; 4 | import com.msbeigi.orderservice.model.OrderResponse; 5 | 6 | public interface OrderService { 7 | long placeOrder(OrderRequest orderRequest); 8 | 9 | OrderResponse getOrderDetailsById(long orderId); 10 | } 11 | -------------------------------------------------------------------------------- /OrderService/src/main/java/com/msbeigi/orderservice/services/OrderServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.services; 2 | 3 | import com.msbeigi.orderservice.entity.Order; 4 | import com.msbeigi.orderservice.exception.CustomException; 5 | import com.msbeigi.orderservice.external.client.PaymentService; 6 | import com.msbeigi.orderservice.external.client.ProductService; 7 | import com.msbeigi.orderservice.external.request.PaymentRequest; 8 | import com.msbeigi.orderservice.external.response.PaymentResponse; 9 | import com.msbeigi.orderservice.model.OrderRequest; 10 | import com.msbeigi.orderservice.model.OrderResponse; 11 | import com.msbeigi.orderservice.external.response.ProductResponse; 12 | import com.msbeigi.orderservice.repository.OrderRepository; 13 | import lombok.extern.log4j.Log4j2; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.http.HttpStatus; 16 | import org.springframework.stereotype.Service; 17 | import org.springframework.web.client.RestTemplate; 18 | 19 | import java.time.Instant; 20 | 21 | @Service 22 | @Log4j2 23 | public class OrderServiceImpl implements OrderService { 24 | 25 | @Autowired 26 | private OrderRepository orderRepository; 27 | 28 | @Autowired 29 | private ProductService productService; 30 | 31 | @Autowired 32 | private PaymentService paymentService; 33 | 34 | @Autowired 35 | private RestTemplate restTemplate; 36 | 37 | @Override 38 | public long placeOrder(OrderRequest orderRequest) { 39 | 40 | log.info("Placing order request: {}", orderRequest); 41 | 42 | productService.reduceQuantity(orderRequest.getProductId(), orderRequest.getQuantity()); 43 | 44 | log.info("Creating order with status CREATED!"); 45 | Order order = Order.builder() 46 | .amount(orderRequest.getTotalAmount()) 47 | .orderStatus("CREATED") 48 | .productId(orderRequest.getProductId()) 49 | .orderDate(Instant.now()) 50 | .quantity(orderRequest.getQuantity()) 51 | .build(); 52 | order = orderRepository.save(order); 53 | 54 | log.info("Calling payment service to complete the payment!"); 55 | 56 | PaymentRequest paymentRequest = 57 | PaymentRequest.builder() 58 | .orderId(order.getId()) 59 | .paymentMode(orderRequest.getPaymentMode()) 60 | .amount(orderRequest.getTotalAmount()) 61 | .build(); 62 | 63 | String orderStatus = null; 64 | 65 | try { 66 | paymentService.doPayment(paymentRequest); 67 | log.info("Payment done successfully, Changing order status!"); 68 | orderStatus = "PLACED"; 69 | } catch (Exception e) { 70 | log.error("Error occured in payment. Changing order status to PAYMENT_FAILED"); 71 | orderStatus = "PAYMENT_FAILED"; 72 | } 73 | 74 | order.setOrderStatus(orderStatus); 75 | orderRepository.save(order); 76 | 77 | log.info("Order places successfully with order id: {}", order.getId()); 78 | 79 | //BeanUtils.copyProperties(orderRequest, ); 80 | return order.getId(); 81 | } 82 | 83 | @Override 84 | public OrderResponse getOrderDetailsById(long orderId) { 85 | 86 | log.info("Get order details for order id {}", orderId); 87 | 88 | Order order = orderRepository.findById(orderId) 89 | .orElseThrow(() -> 90 | new CustomException("Order with id " + orderId + 91 | " not found!", "NOT_FOUND", HttpStatus.NOT_FOUND.value())); 92 | 93 | log.info("Invoking product service to fetch the product id: {}", order.getProductId()); 94 | ProductResponse productResponse = 95 | restTemplate.getForObject("http://PRODUCT-SERVICE/product/" + order.getProductId(), 96 | ProductResponse.class); 97 | 98 | OrderResponse.ProductDetails productDetails = 99 | OrderResponse.ProductDetails 100 | .builder() 101 | .productName(productResponse.getProductName()) 102 | .productId(productResponse.getProductId()) 103 | .build(); 104 | 105 | log.info("Getting payment information from payment service"); 106 | PaymentResponse paymentResponse = 107 | restTemplate.getForObject("http://PAYMENT-SERVICE/payment/order/" + order.getId(), 108 | PaymentResponse.class); 109 | OrderResponse.PaymentDetails paymentDetails = 110 | OrderResponse.PaymentDetails 111 | .builder() 112 | .paymentId(paymentResponse.getPaymentId()) 113 | .paymentStatus(paymentResponse.getStatus()) 114 | .paymentDate(paymentResponse.getPaymentDate()) 115 | .paymentMode(paymentResponse.getPaymentMode()) 116 | .build(); 117 | 118 | 119 | log.info("Getting order details for order id {}", orderId); 120 | 121 | return OrderResponse.builder() 122 | .orderStatus(order.getOrderStatus()) 123 | .orderDate(order.getOrderDate()) 124 | .orderId(order.getId()) 125 | .amount(order.getAmount()) 126 | .productDetails(productDetails) 127 | .paymentDetails(paymentDetails) 128 | .build(); 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /OrderService/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8082 3 | 4 | spring: 5 | datasource: 6 | url: jdbc:mysql://${DB_HOST:localhost}:3306/order_db 7 | username: root 8 | password: root 9 | driverClassName: com.mysql.cj.jdbc.Driver 10 | jpa: 11 | database-platform: org.hibernate.dialect.MySQL57InnoDBDialect 12 | hibernate: 13 | ddl-auto: update 14 | application: 15 | name: ORDER-SERVICE 16 | 17 | config: 18 | import: configserver:${CONFIG_SERVER_URL:http://localhost:9296} 19 | 20 | security: 21 | oauth2: 22 | resourceserver: 23 | jwt: 24 | issuer-uri: https://dev-64973606.okta.com/oauth2/default 25 | client: 26 | registration: 27 | internal-client: 28 | provider: okta 29 | authorization-grant-type: client_credentials 30 | scope: internal 31 | client-id: 0oaa4cqbuyzWeNFec5d7 32 | client-secret: 1TQczKd2HajEL74KggFBLI5uKHDexYU5-ybSYKms 33 | provider: 34 | okta: 35 | issuer-uri: https://dev-64973606.okta.com/oauth2/default 36 | 37 | resilience4j: 38 | circuitbreaker: 39 | instances: 40 | external: 41 | event-consumer-buffer-size: 10 42 | failure-rate-threshold: 50 43 | minimum-number-of-calls: 5 44 | automatic-transition-from-open-to-half-open-enabled: true 45 | wait-duration-in-open-state: 5s 46 | permitted-number-of-calls-in-half-open-state: 3 47 | sliding-window-size: 10 48 | sliding-window-type: COUNT_BASED 49 | 50 | #eureka: 51 | # instance: 52 | # prefer-ip-address: true 53 | # client: 54 | # fetch-registry: true 55 | # register-with-eureka: true 56 | # service-url: 57 | # defaultZone: ${EUREKA_SERVER_ADDRESS:http://localhost:8761/eureka} 58 | -------------------------------------------------------------------------------- /OrderService/src/test/java/com/msbeigi/orderservice/OrderServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class OrderServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /OrderService/src/test/java/com/msbeigi/orderservice/OrderServiceConfig.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice; 2 | 3 | import org.springframework.boot.test.context.TestConfiguration; 4 | import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; 5 | import org.springframework.context.annotation.Bean; 6 | 7 | @TestConfiguration 8 | public class OrderServiceConfig { 9 | 10 | @Bean 11 | public ServiceInstanceListSupplier supplier() { 12 | return new TestServiceInstanceListSupplier(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /OrderService/src/test/java/com/msbeigi/orderservice/TestServiceInstanceListSupplier.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice; 2 | 3 | import org.springframework.cloud.client.DefaultServiceInstance; 4 | import org.springframework.cloud.client.ServiceInstance; 5 | import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; 6 | import reactor.core.publisher.Flux; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class TestServiceInstanceListSupplier implements ServiceInstanceListSupplier { 12 | @Override 13 | public String getServiceId() { 14 | return null; 15 | } 16 | 17 | @Override 18 | public Flux> get() { 19 | List result = new ArrayList<>(); 20 | result.add(new DefaultServiceInstance( 21 | "PAYMENT-SERVICE", 22 | "PAYMENT-SERVICE", 23 | "localhost", 24 | 8088, 25 | false 26 | )); 27 | result.add(new DefaultServiceInstance( 28 | "PRODUCT-SERVICE", 29 | "PRODUCT-SERVICE", 30 | "localhost", 31 | 8088, 32 | false 33 | )); 34 | 35 | return Flux.just(result); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /OrderService/src/test/java/com/msbeigi/orderservice/controller/OrderControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.controller; 2 | 3 | 4 | import com.fasterxml.jackson.databind.DeserializationFeature; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.SerializationFeature; 7 | import com.github.tomakehurst.wiremock.core.WireMockConfiguration; 8 | import com.github.tomakehurst.wiremock.junit5.WireMockExtension; 9 | import com.msbeigi.orderservice.OrderServiceConfig; 10 | import com.msbeigi.orderservice.entity.Order; 11 | import com.msbeigi.orderservice.model.OrderRequest; 12 | import com.msbeigi.orderservice.model.OrderResponse; 13 | import com.msbeigi.orderservice.model.PaymentMode; 14 | import com.msbeigi.orderservice.repository.OrderRepository; 15 | import com.msbeigi.orderservice.services.OrderService; 16 | import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; 17 | import org.junit.jupiter.api.BeforeEach; 18 | import org.junit.jupiter.api.Test; 19 | import org.junit.jupiter.api.extension.RegisterExtension; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 22 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | import org.springframework.http.HttpStatus; 25 | import org.springframework.http.MediaType; 26 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 27 | import org.springframework.test.context.ContextConfiguration; 28 | import org.springframework.test.web.servlet.MockMvc; 29 | import org.springframework.test.web.servlet.MvcResult; 30 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 31 | import org.springframework.test.web.servlet.result.MockMvcResultMatchers; 32 | 33 | import java.io.IOException; 34 | import java.util.Optional; 35 | 36 | import static com.github.tomakehurst.wiremock.client.WireMock.*; 37 | import static java.nio.charset.Charset.defaultCharset; 38 | import static org.junit.jupiter.api.Assertions.assertEquals; 39 | import static org.junit.jupiter.api.Assertions.assertTrue; 40 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt; 41 | import static org.springframework.util.StreamUtils.copyToString; 42 | 43 | @SpringBootTest({"server.port=0"}) 44 | @EnableConfigurationProperties 45 | @AutoConfigureMockMvc 46 | @ContextConfiguration(classes = {OrderServiceConfig.class}) 47 | public class OrderControllerTest { 48 | 49 | @Autowired 50 | private OrderService orderService; 51 | 52 | @Autowired 53 | private OrderRepository orderRepository; 54 | 55 | @Autowired 56 | private MockMvc mockMvc; 57 | 58 | @Autowired 59 | private CircuitBreakerRegistry circuitBreakerRegistry; 60 | 61 | @RegisterExtension 62 | static WireMockExtension wireMockServer 63 | = WireMockExtension.newInstance() 64 | .options(WireMockConfiguration 65 | .wireMockConfig() 66 | .port(8088)) 67 | .build(); 68 | 69 | private ObjectMapper objectMapper 70 | = new ObjectMapper() 71 | .findAndRegisterModules() 72 | .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) 73 | .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 74 | 75 | 76 | @BeforeEach 77 | void setup() throws IOException { 78 | getProductDetailsResponse(); 79 | doPayment(); 80 | getPaymentDetails(); 81 | reduceQuantity(); 82 | } 83 | 84 | private void reduceQuantity() { 85 | circuitBreakerRegistry.circuitBreaker("external").reset(); 86 | wireMockServer.stubFor(put(urlMatching("/product/reduceQuantity/.*")) 87 | .willReturn(aResponse() 88 | .withStatus(HttpStatus.OK.value()) 89 | .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE))); 90 | } 91 | 92 | private void getPaymentDetails() throws IOException { 93 | circuitBreakerRegistry.circuitBreaker("external").reset(); 94 | wireMockServer.stubFor(get(urlMatching("/payment/.*")) 95 | .willReturn(aResponse() 96 | .withStatus(HttpStatus.OK.value()) 97 | .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) 98 | .withBody( 99 | copyToString( 100 | OrderControllerTest.class 101 | .getClassLoader() 102 | .getResourceAsStream("mock/GetPayment.json"), 103 | defaultCharset() 104 | ) 105 | ))); 106 | } 107 | 108 | private void doPayment() { 109 | wireMockServer.stubFor(post(urlEqualTo("/payment")) 110 | .willReturn(aResponse() 111 | .withStatus(HttpStatus.OK.value()) 112 | .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE))); 113 | } 114 | 115 | private void getProductDetailsResponse() throws IOException { 116 | // GET /product/1 117 | wireMockServer.stubFor(get("/product/1") 118 | .willReturn(aResponse() 119 | .withStatus(HttpStatus.OK.value()) 120 | .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) 121 | .withBody(copyToString( 122 | OrderControllerTest.class 123 | .getClassLoader() 124 | .getResourceAsStream("mock/GetProduct.json"), 125 | defaultCharset() 126 | )))); 127 | 128 | 129 | } 130 | 131 | 132 | private OrderRequest getMockOrderRequest() { 133 | return OrderRequest.builder() 134 | .productId(1) 135 | .paymentMode(PaymentMode.CASH) 136 | .quantity(10) 137 | .totalAmount(200) 138 | .build(); 139 | } 140 | 141 | @Test 142 | public void test_WhenPlaceOrder_DoPayment_Success() throws Exception { 143 | //First Place Order 144 | // Get Order by Order Id from Db and check 145 | //Check Output 146 | 147 | OrderRequest orderRequest = getMockOrderRequest(); 148 | MvcResult mvcResult 149 | = mockMvc.perform(MockMvcRequestBuilders.post("/order/placeOrder") 150 | .with(jwt().authorities(new SimpleGrantedAuthority("Customer"))) 151 | .contentType(MediaType.APPLICATION_JSON_VALUE) 152 | .content(objectMapper.writeValueAsString(orderRequest)) 153 | ).andExpect(MockMvcResultMatchers.status().isOk()) 154 | .andReturn(); 155 | 156 | String orderId = mvcResult.getResponse().getContentAsString(); 157 | 158 | Optional order = orderRepository.findById(Long.valueOf(orderId)); 159 | assertTrue(order.isPresent()); 160 | 161 | Order o = order.get(); 162 | 163 | assertEquals(Long.parseLong(orderId), o.getId()); 164 | assertEquals("PLACED", o.getOrderStatus()); 165 | assertEquals(orderRequest.getTotalAmount(), o.getAmount()); 166 | assertEquals(orderRequest.getQuantity(), o.getQuantity()); 167 | 168 | } 169 | 170 | @Test 171 | public void test_WhenPlaceOrderWithWrongAccess_thenThrow403() throws Exception { 172 | OrderRequest orderRequest = getMockOrderRequest(); 173 | MvcResult mvcResult 174 | = mockMvc.perform(MockMvcRequestBuilders.post("/order/placeOrder") 175 | .with(jwt().authorities(new SimpleGrantedAuthority("Admin"))) 176 | .contentType(MediaType.APPLICATION_JSON_VALUE) 177 | .content(objectMapper.writeValueAsString(orderRequest)) 178 | ).andExpect(MockMvcResultMatchers.status().isForbidden()) 179 | .andReturn(); 180 | } 181 | 182 | 183 | /*@Test 184 | public void test_WhenGetOrder_Success() throws Exception { 185 | MvcResult mvcResult 186 | = mockMvc.perform(MockMvcRequestBuilders.get("/order/1") 187 | .with(jwt().authorities(new SimpleGrantedAuthority("Admin"))) 188 | .contentType(MediaType.APPLICATION_JSON_VALUE)) 189 | .andExpect(MockMvcResultMatchers.status().isOk()) 190 | .andReturn(); 191 | 192 | String actualResponse = mvcResult.getResponse().getContentAsString(); 193 | Order order = orderRepository.findById(1L).get(); 194 | String expectedResponse = getOrderResponse(order); 195 | 196 | 197 | assertEquals(expectedResponse, actualResponse); 198 | }*/ 199 | 200 | @Test 201 | public void testWhen_GetOrder_Order_Not_Found() throws Exception { 202 | MvcResult mvcResult 203 | = mockMvc.perform(MockMvcRequestBuilders.get("/order/100") 204 | .with(jwt().authorities(new SimpleGrantedAuthority("Admin"))) 205 | .contentType(MediaType.APPLICATION_JSON_VALUE)) 206 | .andExpect(MockMvcResultMatchers.status().isNotFound()) 207 | .andReturn(); 208 | } 209 | 210 | private String getOrderResponse(Order order) throws IOException { 211 | OrderResponse.PaymentDetails paymentDetails 212 | = objectMapper.readValue( 213 | copyToString( 214 | OrderControllerTest.class.getClassLoader() 215 | .getResourceAsStream("mock/GetPayment.json" 216 | ), 217 | defaultCharset() 218 | ), OrderResponse.PaymentDetails.class 219 | ); 220 | paymentDetails.setPaymentStatus("SUCCESS"); 221 | 222 | OrderResponse.ProductDetails productDetails 223 | = objectMapper.readValue( 224 | copyToString( 225 | OrderControllerTest.class.getClassLoader() 226 | .getResourceAsStream("mock/GetProduct.json"), 227 | defaultCharset() 228 | ), OrderResponse.ProductDetails.class 229 | ); 230 | 231 | OrderResponse orderResponse 232 | = OrderResponse.builder() 233 | .paymentDetails(paymentDetails) 234 | .productDetails(productDetails) 235 | .orderStatus(order.getOrderStatus()) 236 | .orderDate(order.getOrderDate()) 237 | .amount(order.getAmount()) 238 | .orderId(order.getId()) 239 | .build(); 240 | return objectMapper.writeValueAsString(orderResponse); 241 | } 242 | 243 | } 244 | -------------------------------------------------------------------------------- /OrderService/src/test/java/com/msbeigi/orderservice/services/OrderServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.orderservice.services; 2 | 3 | import com.msbeigi.orderservice.entity.Order; 4 | import com.msbeigi.orderservice.exception.CustomException; 5 | import com.msbeigi.orderservice.external.client.PaymentService; 6 | import com.msbeigi.orderservice.external.client.ProductService; 7 | import com.msbeigi.orderservice.external.request.PaymentRequest; 8 | import com.msbeigi.orderservice.external.response.PaymentResponse; 9 | import com.msbeigi.orderservice.external.response.ProductResponse; 10 | import com.msbeigi.orderservice.model.OrderRequest; 11 | import com.msbeigi.orderservice.model.OrderResponse; 12 | import com.msbeigi.orderservice.model.PaymentMode; 13 | import com.msbeigi.orderservice.repository.OrderRepository; 14 | import org.junit.jupiter.api.Assertions; 15 | import org.junit.jupiter.api.DisplayName; 16 | import org.junit.jupiter.api.Test; 17 | import org.mockito.ArgumentMatchers; 18 | import org.mockito.InjectMocks; 19 | import org.mockito.Mock; 20 | import org.mockito.Mockito; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.boot.test.context.SpringBootTest; 23 | import org.springframework.http.HttpStatus; 24 | import org.springframework.http.ResponseEntity; 25 | import org.springframework.web.client.RestTemplate; 26 | 27 | import java.time.Instant; 28 | import java.util.Optional; 29 | 30 | import static org.junit.jupiter.api.Assertions.*; 31 | import static org.mockito.ArgumentMatchers.*; 32 | import static org.mockito.Mockito.*; 33 | 34 | @SpringBootTest 35 | public class OrderServiceImplTest { 36 | 37 | @Mock 38 | private OrderRepository orderRepository; 39 | 40 | @Mock 41 | private ProductService productService; 42 | 43 | @Mock 44 | private PaymentService paymentService; 45 | 46 | @Mock 47 | private RestTemplate restTemplate; 48 | 49 | @InjectMocks 50 | OrderService orderService = new OrderServiceImpl(); 51 | 52 | 53 | @DisplayName("Get Order - Success Scenario") 54 | @Test 55 | void test_When_Order_Success() { 56 | //Mocking 57 | Order order = getMockOrder(); 58 | when(orderRepository.findById(anyLong())) 59 | .thenReturn(Optional.of(order)); 60 | 61 | when(restTemplate.getForObject( 62 | "http://PRODUCT-SERVICE/product/" + order.getProductId(), 63 | ProductResponse.class 64 | )).thenReturn(getMockProductResponse()); 65 | 66 | when(restTemplate.getForObject( 67 | "http://PAYMENT-SERVICE/payment/order/" + order.getId(), 68 | PaymentResponse.class 69 | )).thenReturn(getMockPaymentResponse()); 70 | 71 | //Actual 72 | OrderResponse orderResponse = orderService.getOrderDetailsById(1); 73 | 74 | //Verification 75 | verify(orderRepository, times(1)).findById(anyLong()); 76 | verify(restTemplate, times(1)).getForObject( 77 | "http://PRODUCT-SERVICE/product/" + order.getProductId(), 78 | ProductResponse.class); 79 | verify(restTemplate, times(1)).getForObject( 80 | "http://PAYMENT-SERVICE/payment/order/" + order.getId(), 81 | PaymentResponse.class); 82 | 83 | 84 | //Assert 85 | assertNotNull(orderResponse); 86 | assertEquals(order.getId(), orderResponse.getOrderId()); 87 | } 88 | 89 | @DisplayName("Get Orders - Failure Scenario") 90 | @Test 91 | void test_When_Get_Order_NOT_FOUND_then_Not_Found() { 92 | 93 | when(orderRepository.findById(anyLong())) 94 | .thenReturn(Optional.ofNullable(null)); 95 | 96 | CustomException exception = 97 | assertThrows(CustomException.class, 98 | () -> orderService.getOrderDetailsById(1)); 99 | assertEquals("NOT_FOUND", exception.getErrorCode()); 100 | assertEquals(404, exception.getStatus()); 101 | 102 | verify(orderRepository, times(1)) 103 | .findById(anyLong()); 104 | } 105 | 106 | @DisplayName("Place Order - Success Scenario") 107 | @Test 108 | void test_When_Place_Order_Success() { 109 | Order order = getMockOrder(); 110 | OrderRequest orderRequest = getMockOrderRequest(); 111 | 112 | when(orderRepository.save(any(Order.class))) 113 | .thenReturn(order); 114 | when(productService.reduceQuantity(anyLong(),anyLong())) 115 | .thenReturn(new ResponseEntity(HttpStatus.OK)); 116 | when(paymentService.doPayment(any(PaymentRequest.class))) 117 | .thenReturn(new ResponseEntity(1L,HttpStatus.OK)); 118 | 119 | long orderId = orderService.placeOrder(orderRequest); 120 | 121 | verify(orderRepository, times(2)) 122 | .save(any()); 123 | verify(productService, times(1)) 124 | .reduceQuantity(anyLong(),anyLong()); 125 | verify(paymentService, times(1)) 126 | .doPayment(any(PaymentRequest.class)); 127 | 128 | assertEquals(order.getId(), orderId); 129 | } 130 | 131 | @DisplayName("Place Order - Payment Failed Scenario") 132 | @Test 133 | void test_when_Place_Order_Payment_Fails_then_Order_Placed() { 134 | 135 | Order order = getMockOrder(); 136 | OrderRequest orderRequest = getMockOrderRequest(); 137 | 138 | when(orderRepository.save(any(Order.class))) 139 | .thenReturn(order); 140 | when(productService.reduceQuantity(anyLong(),anyLong())) 141 | .thenReturn(new ResponseEntity(HttpStatus.OK)); 142 | when(paymentService.doPayment(any(PaymentRequest.class))) 143 | .thenThrow(new RuntimeException()); 144 | 145 | long orderId = orderService.placeOrder(orderRequest); 146 | 147 | verify(orderRepository, times(2)) 148 | .save(any()); 149 | verify(productService, times(1)) 150 | .reduceQuantity(anyLong(),anyLong()); 151 | verify(paymentService, times(1)) 152 | .doPayment(any(PaymentRequest.class)); 153 | 154 | assertEquals(order.getId(), orderId); 155 | } 156 | 157 | private OrderRequest getMockOrderRequest() { 158 | return OrderRequest.builder() 159 | .productId(1) 160 | .quantity(10) 161 | .paymentMode(PaymentMode.CASH) 162 | .totalAmount(100) 163 | .build(); 164 | } 165 | 166 | private PaymentResponse getMockPaymentResponse() { 167 | return PaymentResponse.builder() 168 | .paymentId(1) 169 | .paymentDate(Instant.now()) 170 | .paymentMode(PaymentMode.CASH) 171 | .amount(200) 172 | .orderId(1) 173 | .status("ACCEPTED") 174 | .build(); 175 | } 176 | 177 | private ProductResponse getMockProductResponse() { 178 | return ProductResponse.builder() 179 | .productId(2) 180 | .productName("iPhone") 181 | .price(100) 182 | .quantity(200) 183 | .build(); 184 | } 185 | 186 | private Order getMockOrder() { 187 | return Order.builder() 188 | .orderStatus("PLACED") 189 | .orderDate(Instant.now()) 190 | .id(1) 191 | .amount(100) 192 | .quantity(200) 193 | .productId(2) 194 | .build(); 195 | } 196 | 197 | } 198 | -------------------------------------------------------------------------------- /OrderService/src/test/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:order 4 | username: sa 5 | password: password 6 | driverClassName: org.h2.Driver 7 | jpa: 8 | database-platform: org.hibernate.dialect.H2Dialect 9 | config: 10 | import: optional:configserver:http://localhost:9296 11 | security: 12 | oauth2: 13 | resourceserver: 14 | jwt: 15 | issuer-uri: https://dev-64973606.okta.com/oauth2/default 16 | client: 17 | registration: 18 | internal-client: 19 | provider: okta 20 | authorization-grant-type: client_credentials 21 | scope: internal 22 | client-id: 0oaa4cqbuyzWeNFec5d7 23 | client-secret: 1TQczKd2HajEL74KggFBLI5uKHDexYU5-ybSYKms 24 | provider: 25 | okta: 26 | issuer-uri: https://dev-64973606.okta.com/oauth2/default 27 | 28 | eureka: 29 | client: 30 | enabled: false 31 | -------------------------------------------------------------------------------- /OrderService/src/test/resources/mock/GetPayment.json: -------------------------------------------------------------------------------- 1 | { 2 | "paymentId": 1, 3 | "paymentMode": "CASH", 4 | "status": "SUCCESS", 5 | "amount": 500, 6 | "paymentDate": "2022-03-20T10:06:10.060802Z", 7 | "orderId": 1 8 | } 9 | -------------------------------------------------------------------------------- /OrderService/src/test/resources/mock/GetProduct.json: -------------------------------------------------------------------------------- 1 | { 2 | "productId": 1, 3 | "productName": "iPhone", 4 | "quantity": 370, 5 | "price": 200 6 | } 7 | -------------------------------------------------------------------------------- /PaymentService/.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 | -------------------------------------------------------------------------------- /PaymentService/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msbeigiai/spring-boot-microservices/7c41c629c582ed45a45722b1ec1dba5fbe4574b3/PaymentService/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /PaymentService/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /PaymentService/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | 3 | ARG JAR_FILE=target/*.jar 4 | 5 | COPY ${JAR_FILE} paymentservice.jar 6 | 7 | ENTRYPOINT ["java", "-jar", "/paymentservice.jar"] 8 | 9 | EXPOSE 8082 10 | 11 | -------------------------------------------------------------------------------- /PaymentService/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 | -------------------------------------------------------------------------------- /PaymentService/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.13 9 | 10 | 11 | com.msbeigi 12 | PaymentService 13 | 0.0.1 14 | PaymentService 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 2021.0.7 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-data-jpa 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-sleuth-zipkin 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-starter-sleuth 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-starter 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-starter-config 44 | 45 | 46 | org.springframework.cloud 47 | spring-cloud-starter-netflix-eureka-client 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-security 52 | 53 | 54 | com.okta.spring 55 | okta-spring-boot-starter 56 | 2.1.6 57 | 58 | 59 | 60 | com.mysql 61 | mysql-connector-j 62 | runtime 63 | 64 | 65 | org.projectlombok 66 | lombok 67 | true 68 | 69 | 70 | org.springframework.boot 71 | spring-boot-starter-test 72 | test 73 | 74 | 75 | 76 | 77 | 78 | org.springframework.cloud 79 | spring-cloud-dependencies 80 | ${spring-cloud.version} 81 | pom 82 | import 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | org.springframework.boot 91 | spring-boot-maven-plugin 92 | 93 | 94 | 95 | org.projectlombok 96 | lombok 97 | 98 | 99 | 100 | 101 | 102 | com.google.cloud.tools 103 | jib-maven-plugin 104 | 105 | 106 | openjdk:17 107 | 108 | 109 | registry.hub.docker.com/msbeigiai/paymentservice 110 | ${project.version} 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/PaymentServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PaymentServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PaymentServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/controller/PaymentController.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.controller; 2 | 3 | import com.msbeigi.paymentservice.model.PaymentRequest; 4 | import com.msbeigi.paymentservice.model.PaymentResponse; 5 | import com.msbeigi.paymentservice.services.PaymentService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | @RestController 12 | @RequestMapping("/payment") 13 | public class PaymentController { 14 | 15 | @Autowired 16 | private PaymentService paymentService; 17 | 18 | @PostMapping 19 | public ResponseEntity doPayment(@RequestBody PaymentRequest paymentRequest) { 20 | return new ResponseEntity<>( 21 | paymentService.doPayment(paymentRequest), 22 | HttpStatus.CREATED 23 | ); 24 | } 25 | 26 | @GetMapping("/order/{orderId}") 27 | public ResponseEntity getPaymentDetailsByOrderId(@PathVariable String orderId) { 28 | return new ResponseEntity<>( 29 | paymentService.getPaymentDetailsByOrderId(orderId), 30 | HttpStatus.OK 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/entity/TransactionDetails.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.persistence.*; 9 | import java.time.Instant; 10 | 11 | @Entity 12 | @Table(name = "transaction_details") 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | @Builder 17 | public class TransactionDetails { 18 | 19 | @Id 20 | @GeneratedValue(strategy = GenerationType.AUTO) 21 | private long id; 22 | 23 | @Column(name = "order_id") 24 | private long orderId; 25 | 26 | @Column(name = "mode") 27 | private String paymentMode; 28 | 29 | @Column(name = "reference_number") 30 | private String referenceNumber; 31 | 32 | @Column(name = "payment_date") 33 | private Instant paymentDate; 34 | 35 | @Column(name = "status") 36 | private String paymentStatus; 37 | 38 | @Column(name = "amount") 39 | private long amount; 40 | } 41 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/model/PaymentMode.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.model; 2 | 3 | public enum PaymentMode { 4 | CASH, 5 | PAYPAL, 6 | DEBIT_CARD, 7 | CREDIT_CARD, 8 | APPLE_PAY 9 | } 10 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/model/PaymentRequest.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @Builder 12 | public class PaymentRequest { 13 | 14 | private long orderId; 15 | private long amount; 16 | private String referenceNumber; 17 | private PaymentMode paymentMode; 18 | } 19 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/model/PaymentResponse.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.time.Instant; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @Builder 14 | public class PaymentResponse { 15 | private long paymentId; 16 | private String status; 17 | private PaymentMode paymentMode; 18 | private long amount; 19 | private Instant paymentDate; 20 | private long orderId; 21 | } 22 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/repository/TransactionsDetailsRepository.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.repository; 2 | 3 | import com.msbeigi.paymentservice.entity.TransactionDetails; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface TransactionsDetailsRepository extends JpaRepository { 9 | 10 | TransactionDetails findByOrderId(long orderId); 11 | } 12 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/security/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.security; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 7 | import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; 8 | import org.springframework.security.web.SecurityFilterChain; 9 | 10 | @Configuration 11 | @EnableWebSecurity 12 | public class WebSecurityConfig { 13 | 14 | @Bean 15 | SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { 16 | http.authorizeHttpRequests(authorizedRequest -> 17 | authorizedRequest 18 | .antMatchers("/payment/**") 19 | .hasAuthority("SCOPE_internal") 20 | .anyRequest() 21 | .authenticated() 22 | ) 23 | .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); 24 | 25 | return http.build(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/services/PaymentService.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.services; 2 | 3 | import com.msbeigi.paymentservice.model.PaymentRequest; 4 | import com.msbeigi.paymentservice.model.PaymentResponse; 5 | import org.springframework.stereotype.Service; 6 | 7 | public interface PaymentService { 8 | long doPayment(PaymentRequest paymentRequest); 9 | 10 | PaymentResponse getPaymentDetailsByOrderId(String orderId); 11 | } 12 | -------------------------------------------------------------------------------- /PaymentService/src/main/java/com/msbeigi/paymentservice/services/PaymentServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice.services; 2 | 3 | import com.msbeigi.paymentservice.entity.TransactionDetails; 4 | import com.msbeigi.paymentservice.model.PaymentMode; 5 | import com.msbeigi.paymentservice.model.PaymentRequest; 6 | import com.msbeigi.paymentservice.model.PaymentResponse; 7 | import com.msbeigi.paymentservice.repository.TransactionsDetailsRepository; 8 | import lombok.extern.log4j.Log4j2; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.time.Instant; 13 | 14 | @Service 15 | @Log4j2 16 | public class PaymentServiceImpl implements PaymentService { 17 | 18 | @Autowired 19 | private TransactionsDetailsRepository transactionsDetailsRepository; 20 | 21 | @Override 22 | public long doPayment(PaymentRequest paymentRequest) { 23 | log.info("Recording Payment Details: {}", paymentRequest); 24 | 25 | TransactionDetails transactionDetails = 26 | TransactionDetails.builder() 27 | .referenceNumber(paymentRequest.getReferenceNumber()) 28 | .paymentDate(Instant.now()) 29 | .paymentMode(paymentRequest.getPaymentMode().name()) 30 | .amount(paymentRequest.getAmount()) 31 | .orderId(paymentRequest.getOrderId()) 32 | .paymentStatus("SUCCESS") 33 | .build(); 34 | transactionsDetailsRepository.save(transactionDetails); 35 | 36 | log.info("Transaction completed with Id: {}", transactionDetails.getId()); 37 | return transactionDetails.getId(); 38 | } 39 | 40 | @Override 41 | public PaymentResponse getPaymentDetailsByOrderId(String orderId) { 42 | log.info("Getting payment details for the order id: {}", orderId); 43 | 44 | TransactionDetails transactionDetails = 45 | transactionsDetailsRepository.findByOrderId(Long.parseLong(orderId)); 46 | 47 | return PaymentResponse 48 | .builder() 49 | .paymentId(transactionDetails.getId()) 50 | .paymentMode(PaymentMode.valueOf(transactionDetails.getPaymentMode())) 51 | .paymentDate(transactionDetails.getPaymentDate()) 52 | .orderId(transactionDetails.getOrderId()) 53 | .status(transactionDetails.getPaymentStatus()) 54 | .amount(transactionDetails.getAmount()) 55 | .build(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /PaymentService/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8081 3 | 4 | spring: 5 | datasource: 6 | url: jdbc:mysql://${DB_HOST:localhost}:3306/payment_db 7 | username: root 8 | password: root 9 | driver-class-name: com.mysql.cj.jdbc.Driver 10 | jpa: 11 | database-platform: org.hibernate.dialect.MySQL57InnoDBDialect 12 | hibernate: 13 | ddl-auto: update 14 | 15 | application: 16 | name: PAYMENT-SERVICE 17 | 18 | config: 19 | import: configserver:${CONFIG_SERVER_URL:http://localhost:9296} 20 | 21 | -------------------------------------------------------------------------------- /PaymentService/src/test/java/com/msbeigi/paymentservice/PaymentServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.paymentservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class PaymentServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ProductService/.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 | -------------------------------------------------------------------------------- /ProductService/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msbeigiai/spring-boot-microservices/7c41c629c582ed45a45722b1ec1dba5fbe4574b3/ProductService/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /ProductService/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /ProductService/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | 3 | ARG JAR_FILE=target/*.jar 4 | 5 | COPY ${JAR_FILE} productservice.jar 6 | 7 | ENTRYPOINT ["java", "-jar", "/productservice.jar"] 8 | 9 | EXPOSE 8082 10 | 11 | -------------------------------------------------------------------------------- /ProductService/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 | -------------------------------------------------------------------------------- /ProductService/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.12 9 | 10 | 11 | com.msbeigi 12 | ProductService 13 | 0.0.1 14 | ProductService 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 2021.0.7 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-data-jpa 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter 32 | 33 | 34 | 35 | com.mysql 36 | mysql-connector-j 37 | runtime 38 | 39 | 40 | org.projectlombok 41 | lombok 42 | true 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-test 47 | test 48 | 49 | 50 | 51 | org.springframework.cloud 52 | spring-cloud-starter-netflix-eureka-client 53 | 54 | 55 | 56 | org.springframework.cloud 57 | spring-cloud-starter-config 58 | 59 | 60 | 61 | org.springframework.cloud 62 | spring-cloud-sleuth-zipkin 63 | 64 | 65 | org.springframework.cloud 66 | spring-cloud-starter-sleuth 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-starter-security 71 | 72 | 73 | com.okta.spring 74 | okta-spring-boot-starter 75 | 2.1.6 76 | 77 | 78 | 79 | 80 | 81 | org.springframework.cloud 82 | spring-cloud-dependencies 83 | ${spring-cloud.version} 84 | pom 85 | import 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.springframework.boot 94 | spring-boot-maven-plugin 95 | 96 | 97 | 98 | org.projectlombok 99 | lombok 100 | 101 | 102 | 103 | 104 | 105 | com.google.cloud.tools 106 | jib-maven-plugin 107 | 108 | 109 | openjdk:17 110 | 111 | 112 | registry.hub.docker.com/msbeigiai/productservice 113 | ${project.version} 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/ProductServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ProductServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ProductServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/controller/ProductController.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.controller; 2 | 3 | import com.msbeigi.ProductService.model.ProductRequest; 4 | import com.msbeigi.ProductService.model.ProductResponse; 5 | import com.msbeigi.ProductService.services.ProductService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.security.access.prepost.PreAuthorize; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | @RestController 13 | @RequestMapping("/product") 14 | public class ProductController { 15 | 16 | @Autowired 17 | private ProductService productService; 18 | 19 | @PreAuthorize("hasAuthority('Admin')") 20 | @PostMapping 21 | public ResponseEntity addProduct(@RequestBody ProductRequest productRequest) { 22 | long productId = productService.addProduct(productRequest); 23 | return new ResponseEntity<>(productId, HttpStatus.CREATED); 24 | } 25 | 26 | @PreAuthorize("hasAuthority('Admin') || hasAuthority('Customer') || hasAuthority('SCOPE_internal')") 27 | @GetMapping("/{id}") 28 | public ResponseEntity getProductById(@PathVariable("id") long productId) { 29 | ProductResponse productResponse = 30 | productService.getProductById(productId); 31 | return new ResponseEntity<>(productResponse, HttpStatus.OK); 32 | } 33 | 34 | @PutMapping("/reduceQuantity/{id}") 35 | public ResponseEntity reduceQuantity( 36 | @PathVariable("id") long productId, 37 | @RequestParam long quantity) { 38 | productService.reduceQuantity(productId, quantity); 39 | return new ResponseEntity<>(HttpStatus.OK); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/entity/Product.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.persistence.*; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @Builder 14 | @Entity 15 | @Table(name = "product") 16 | public class Product { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.AUTO) 20 | private long productId; 21 | 22 | @Column(name = "product_name") 23 | private String productName; 24 | 25 | @Column(name = "price") 26 | private long price; 27 | 28 | @Column(name = "quantity") 29 | private long quantity; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/exception/ProductServiceCustomException.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.exception; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ProductServiceCustomException extends RuntimeException { 7 | private String errorCode; 8 | 9 | public ProductServiceCustomException(String message, String errorCode) { 10 | super(message); 11 | this.errorCode = errorCode; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/exception/RestResponseEntityExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.exception; 2 | 3 | import com.msbeigi.ProductService.model.ErrorResponse; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 9 | 10 | @ControllerAdvice 11 | public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { 12 | 13 | @ExceptionHandler(ProductServiceCustomException.class) 14 | public ResponseEntity handleProductServiceException(ProductServiceCustomException exception) { 15 | return new ResponseEntity<>(ErrorResponse.builder() 16 | .errorMessage(exception.getMessage()) 17 | .errorCode(exception.getErrorCode()) 18 | .build(), 19 | HttpStatus.NOT_FOUND); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/model/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Builder 12 | public class ErrorResponse { 13 | 14 | private String errorMessage; 15 | private String errorCode; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/model/ProductRequest.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ProductRequest { 7 | private String name; 8 | private long price; 9 | private long quantity; 10 | } 11 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/model/ProductResponse.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Builder 12 | public class ProductResponse { 13 | private long productId; 14 | private String productName; 15 | private long quantity; 16 | private long price; 17 | } 18 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.repository; 2 | 3 | import com.msbeigi.ProductService.entity.Product; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface ProductRepository extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/security/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.security; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 8 | import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; 9 | import org.springframework.security.web.SecurityFilterChain; 10 | 11 | @Configuration 12 | @EnableWebSecurity 13 | @EnableGlobalMethodSecurity(prePostEnabled = true) 14 | public class WebSecurityConfig { 15 | @Bean 16 | public SecurityFilterChain securityWebFilterChain(HttpSecurity httpSecurity) throws Exception { 17 | httpSecurity 18 | .authorizeRequests(authorizeRequest -> authorizeRequest 19 | .anyRequest() 20 | .authenticated() 21 | ) 22 | .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); 23 | 24 | return httpSecurity.build(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/services/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.services; 2 | 3 | import com.msbeigi.ProductService.model.ProductRequest; 4 | import com.msbeigi.ProductService.model.ProductResponse; 5 | 6 | public interface ProductService { 7 | long addProduct(ProductRequest productRequest); 8 | 9 | ProductResponse getProductById(long productId); 10 | 11 | void reduceQuantity(long productId, long quantity); 12 | } 13 | -------------------------------------------------------------------------------- /ProductService/src/main/java/com/msbeigi/ProductService/services/ProductServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService.services; 2 | 3 | import com.msbeigi.ProductService.entity.Product; 4 | import com.msbeigi.ProductService.exception.ProductServiceCustomException; 5 | import com.msbeigi.ProductService.model.ProductRequest; 6 | import com.msbeigi.ProductService.model.ProductResponse; 7 | import com.msbeigi.ProductService.repository.ProductRepository; 8 | import lombok.extern.log4j.Log4j2; 9 | import org.springframework.beans.BeanUtils; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | @Service 14 | @Log4j2 15 | public class ProductServiceImpl implements ProductService { 16 | 17 | @Autowired 18 | private ProductRepository productRepository; 19 | 20 | @Override 21 | public long addProduct(ProductRequest productRequest) { 22 | log.info("Adding product..."); 23 | Product product = 24 | Product.builder() 25 | .productName(productRequest.getName()) 26 | .price(productRequest.getPrice()) 27 | .quantity(productRequest.getQuantity()) 28 | .build(); 29 | 30 | productRepository.save(product); 31 | 32 | log.info("Product with id: {} created.", product.getProductId()); 33 | return product.getProductId(); 34 | } 35 | 36 | @Override 37 | public ProductResponse getProductById(long productId) { 38 | log.info("Get the product for product id: {}", productId); 39 | Product product = productRepository.findById(productId).orElseThrow( 40 | () -> new ProductServiceCustomException("Product with id: " + 41 | productId + " is not exists.", "PRODUCT_NOT_FOUND")); 42 | 43 | ProductResponse productResponse = new ProductResponse(); 44 | BeanUtils.copyProperties(product, productResponse); 45 | 46 | return productResponse; 47 | } 48 | 49 | @Override 50 | public void reduceQuantity(long productId, long quantity) { 51 | log.info("Reduce quantity {} for Id {}", quantity, productId); 52 | 53 | Product product = productRepository.findById(productId).orElseThrow( 54 | () -> new ProductServiceCustomException( 55 | "No product with id " + productId + " was found!", 56 | "NOT_FOUND")); 57 | if (product.getQuantity() < quantity) { 58 | throw new ProductServiceCustomException( 59 | "Product does not have sufficient quantity", 60 | "INSUFFICIENT_QUANTITY"); 61 | } 62 | 63 | product.setQuantity(product.getQuantity() - quantity); 64 | productRepository.save(product); 65 | 66 | log.info("Product quantity updated successfully"); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ProductService/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | 4 | spring: 5 | datasource: 6 | url: jdbc:mysql://${DB_HOST:localhost}:3306/product_db 7 | username: root 8 | password: root 9 | driver-class-name: com.mysql.cj.jdbc.Driver 10 | jpa: 11 | database-platform: org.hibernate.dialect.MySQL57InnoDBDialect 12 | hibernate: 13 | ddl-auto: update 14 | 15 | application: 16 | name: PRODUCT-SERVICE 17 | 18 | config: 19 | import: configserver:${CONFIG_SERVER_URL:http://localhost:9296} 20 | 21 | #eureka: 22 | # instance: 23 | # prefer-ip-address: true 24 | # client: 25 | # fetch-registry: true 26 | # register-with-eureka: true 27 | # service-url: 28 | # defaultZone: ${EUREKA_SERVER_ADDRESS:http://localhost:8761/eureka} 29 | -------------------------------------------------------------------------------- /ProductService/src/test/java/com/msbeigi/ProductService/ProductServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.ProductService; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ProductServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## An usefull repository for educational puposes in the concept of Spring Boot microservices. 2 | ### Fill free to contribute to the project. 3 | -------------------------------------------------------------------------------- /ServiceRegistry/.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 | -------------------------------------------------------------------------------- /ServiceRegistry/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msbeigiai/spring-boot-microservices/7c41c629c582ed45a45722b1ec1dba5fbe4574b3/ServiceRegistry/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /ServiceRegistry/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip 18 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar 19 | -------------------------------------------------------------------------------- /ServiceRegistry/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:17 2 | 3 | ARG JAR_FILE=target/*.jar 4 | 5 | COPY ${JAR_FILE} serviceregistry.jar 6 | 7 | ENTRYPOINT ["java", "-jar", "/serviceregistry.jar"] 8 | 9 | EXPOSE 8761 10 | 11 | -------------------------------------------------------------------------------- /ServiceRegistry/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 | -------------------------------------------------------------------------------- /ServiceRegistry/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.7.12 9 | 10 | 11 | com.msbeigi 12 | ServiceRegistry 13 | 0.0.1 14 | ServiceRegistry 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 2021.0.7 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-starter 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-starter-netflix-eureka-server 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-test 33 | test 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.cloud 40 | spring-cloud-dependencies 41 | ${spring-cloud.version} 42 | pom 43 | import 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-maven-plugin 53 | 54 | 55 | com.google.cloud.tools 56 | jib-maven-plugin 57 | 58 | 59 | openjdk:17 60 | 61 | 62 | registry.hub.docker.com/msbeigiai/serviceregistry 63 | ${project.version} 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /ServiceRegistry/src/main/java/com/msbeigi/serviceregistry/ServiceRegistryApplication.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.serviceregistry; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class ServiceRegistryApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ServiceRegistryApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ServiceRegistry/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8761 3 | 4 | eureka: 5 | instance: 6 | hostname: "${HOSTNAME:localhost}.eureka" 7 | client: 8 | register-with-eureka: false 9 | fetch-registry: false 10 | -------------------------------------------------------------------------------- /ServiceRegistry/src/test/java/com/msbeigi/serviceregistry/ServiceRegistryApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.msbeigi.serviceregistry; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ServiceRegistryApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | serviceregistry: 4 | image: 'msbeigiai/serviceregistry:0.0.1' 5 | container_name: serviceregistry 6 | ports: 7 | - '8761:8761' 8 | 9 | configserver: 10 | image: 'msbeigiai/configserver:0.0.1' 11 | container_name: configserver 12 | ports: 13 | - '9296:9296' 14 | healthcheck: 15 | test: ["CMD", "curl", "-f", "http://configserver:9296/actuator/health"] 16 | interval: 15s 17 | timeout: 10s 18 | retries: 5 19 | depends_on: 20 | - serviceregistry 21 | environment: 22 | - EUREKA_SERVER_ADDRESS=http://serviceregistry:8761/eureka 23 | 24 | cloudgateway: 25 | image: 'msbeigiai/cloudgateway:0.0.1' 26 | container_name: cloudgateway 27 | ports: 28 | - '9090:9090' 29 | depends_on: 30 | configserver: 31 | condition: service_healthy 32 | environment: 33 | - EUREKA_SERVER_ADDRESS=http://serviceregistry:8761/eureka 34 | - CONFIG_SERVER_URL=configserver -------------------------------------------------------------------------------- /k8s-demo/deploy.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: service-registry 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: service-registry 9 | template: 10 | metadata: 11 | labels: 12 | app: service-registry 13 | spec: 14 | containers: 15 | - name: service-registry 16 | image: msbeigiai/serviceregistry:0.0.1 17 | imagePullPolicy: Always 18 | ports: 19 | - containerPort: 8761 20 | -------------------------------------------------------------------------------- /k8s-demo/svc.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: serrvice-registry-svc 5 | spec: 6 | selector: 7 | app: service-registry 8 | ports: 9 | - port: 80 10 | targetPort: 8761 11 | -------------------------------------------------------------------------------- /k8s/cloud-gateway-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: cloud-gateway-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: cloud-gateway-app 9 | template: 10 | metadata: 11 | labels: 12 | app: cloud-gateway-app 13 | spec: 14 | containers: 15 | - name: cloud-gateway-app 16 | image: msbeigiai/cloudgateway:latest 17 | ports: 18 | - containerPort: 9090 19 | env: 20 | - name: EUREKA_SERVER_ADDRESS 21 | valueFrom: 22 | configMapKeyRef: 23 | key: eureka_service_address 24 | name: eureka-cm 25 | - name: CONFIG_SERVER_URL 26 | valueFrom: 27 | configMapKeyRef: 28 | key: config_url 29 | name: config-cm 30 | --- 31 | 32 | apiVersion: v1 33 | kind: Service 34 | metadata: 35 | name: cloud-gateway-svc 36 | spec: 37 | type: LoadBalancer 38 | selector: 39 | app: cloud-gateway-app 40 | ports: 41 | - port: 80 42 | targetPort: 9090 43 | 44 | -------------------------------------------------------------------------------- /k8s/config-maps.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: eureka-cm 5 | data: 6 | eureka_service_address: "http://eureka-0.eureka:8761/eureka" 7 | 8 | --- 9 | 10 | apiVersion: v1 11 | kind: ConfigMap 12 | metadata: 13 | name: config-cm 14 | data: 15 | config_url: "http://config-server-svc" 16 | 17 | --- 18 | 19 | apiVersion: v1 20 | kind: ConfigMap 21 | metadata: 22 | name: mysql-cm 23 | data: 24 | hostname: "mysql-0.mysql" 25 | 26 | 27 | -------------------------------------------------------------------------------- /k8s/config-server-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: config-server-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: config-server-app 9 | template: 10 | metadata: 11 | labels: 12 | app: config-server-app 13 | spec: 14 | containers: 15 | - name: config-server-app 16 | image: msbeigiai/configserver 17 | ports: 18 | - containerPort: 9296 19 | env: 20 | - name: EUREKA_SERVER_ADDRESS 21 | valueFrom: 22 | configMapKeyRef: 23 | name: eureka-cm 24 | key: eureka_service_address 25 | 26 | --- 27 | 28 | apiVersion: v1 29 | kind: Service 30 | metadata: 31 | name: config-server-svc 32 | spec: 33 | selector: 34 | app: config-server-app 35 | ports: 36 | - port: 80 37 | targetPort: 9296 38 | 39 | -------------------------------------------------------------------------------- /k8s/mysql-deployment.yml: -------------------------------------------------------------------------------- 1 | # PV 2 | apiVersion: v1 3 | kind: PersistentVolume 4 | metadata: 5 | name: mysql-pv 6 | spec: 7 | capacity: 8 | storage: 1Gi 9 | accessModes: 10 | - ReadWriteOnce 11 | storageClassName: manual 12 | hostPath: 13 | path: "/mnt/data" 14 | type: DirectoryOrCreate 15 | --- 16 | 17 | # PVC 18 | apiVersion: v1 19 | kind: PersistentVolumeClaim 20 | metadata: 21 | name: mysql-pvc 22 | spec: 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | storageClassName: manual 27 | accessModes: 28 | - ReadWriteOnce 29 | --- 30 | 31 | #StatefulSet - MySQL 32 | apiVersion: apps/v1 33 | kind: StatefulSet 34 | metadata: 35 | name: mysql 36 | spec: 37 | selector: 38 | matchLabels: 39 | app: mysql 40 | serviceName: mysql 41 | replicas: 1 42 | template: 43 | metadata: 44 | labels: 45 | app: mysql 46 | spec: 47 | containers: 48 | - name: mysql 49 | image: mysql:8.0 50 | ports: 51 | - containerPort: 3306 52 | name: mysql 53 | env: 54 | - name: MYSQL_ROOT_PASSWORD 55 | value: root 56 | volumeMounts: 57 | - name: mysql-initdb 58 | mountPath: /docker-entrypoint-initdb.d 59 | - name: mysql-persistent-storage 60 | mountPath: /var/lib/mysql 61 | volumes: 62 | - name: mysql-initdb 63 | configMap: 64 | name: mysql-initdb-cm 65 | - name: mysql-persistent-storage 66 | persistentVolumeClaim: 67 | claimName: mysql-pvc 68 | --- 69 | 70 | # Config 71 | apiVersion: v1 72 | kind: ConfigMap 73 | metadata: 74 | name: mysql-initdb-cm 75 | data: 76 | init.sql: | 77 | CREATE DATABASE IF NOT EXISTS order_db; 78 | CREATE DATABASE IF NOT EXISTS product_db; 79 | CREATE DATABASE IF NOT EXISTS payment_db; 80 | 81 | 82 | --- 83 | 84 | # Headless 85 | apiVersion: v1 86 | kind: Service 87 | metadata: 88 | name: mysql 89 | spec: 90 | clusterIP: None 91 | selector: 92 | app: mysql 93 | ports: 94 | - port: 3306 95 | -------------------------------------------------------------------------------- /k8s/order-service-deployhment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: order-service-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: order-service-app 9 | template: 10 | metadata: 11 | labels: 12 | app: order-service-app 13 | spec: 14 | containers: 15 | - name: order-service-app 16 | image: msbeigiai/orderservice:latest 17 | ports: 18 | - containerPort: 8082 19 | env: 20 | - name: EUREKA_SERVER_ADDRESS 21 | valueFrom: 22 | configMapKeyRef: 23 | key: eureka_service_address 24 | name: eureka-cm 25 | - name: CONFIG_SERVER_URL 26 | valueFrom: 27 | configMapKeyRef: 28 | key: config_url 29 | name: config-cm 30 | - name: DB_HOST 31 | valueFrom: 32 | configMapKeyRef: 33 | key: hostname 34 | name: mysql-cm 35 | 36 | --- 37 | 38 | apiVersion: v1 39 | kind: Service 40 | metadata: 41 | name: order-service-svc 42 | spec: 43 | selector: 44 | app: order-service-app 45 | ports: 46 | - port: 80 47 | targetPort: 8082 48 | -------------------------------------------------------------------------------- /k8s/payment-service-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: payment-service-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: payment-service-app 9 | template: 10 | metadata: 11 | labels: 12 | app: payment-service-app 13 | spec: 14 | containers: 15 | - name: payment-service-app 16 | image: msbeigiai/paymentservice:latest 17 | ports: 18 | - containerPort: 8081 19 | env: 20 | - name: EUREKA_SERVER_ADDRESS 21 | valueFrom: 22 | configMapKeyRef: 23 | key: eureka_service_address 24 | name: eureka-cm 25 | - name: CONFIG_SERVER_URL 26 | valueFrom: 27 | configMapKeyRef: 28 | key: config_url 29 | name: config-cm 30 | - name: DB_HOST 31 | valueFrom: 32 | configMapKeyRef: 33 | key: hostname 34 | name: mysql-cm 35 | --- 36 | 37 | apiVersion: v1 38 | kind: Service 39 | metadata: 40 | name: payment-service-svc 41 | spec: 42 | selector: 43 | app: payment-service-app 44 | ports: 45 | - port: 80 46 | targetPort: 8081 47 | 48 | -------------------------------------------------------------------------------- /k8s/product-service-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: product-service-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: product-service-app 9 | template: 10 | metadata: 11 | labels: 12 | app: product-service-app 13 | spec: 14 | containers: 15 | - name: product-service-app 16 | image: msbeigiai/productservice:latest 17 | ports: 18 | - containerPort: 8080 19 | env: 20 | - name: EUREKA_SERVER_ADDRESS 21 | valueFrom: 22 | configMapKeyRef: 23 | key: eureka_service_address 24 | name: eureka-cm 25 | - name: CONFIG_SERVER_URL 26 | valueFrom: 27 | configMapKeyRef: 28 | key: config_url 29 | name: config-cm 30 | - name: DB_HOST 31 | valueFrom: 32 | configMapKeyRef: 33 | key: hostname 34 | name: mysql-cm 35 | --- 36 | 37 | apiVersion: v1 38 | kind: Service 39 | metadata: 40 | name: product-service-svc 41 | spec: 42 | selector: 43 | app: product-service-app 44 | ports: 45 | - port: 80 46 | targetPort: 8080 47 | 48 | 49 | -------------------------------------------------------------------------------- /k8s/redis-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: redis-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: redis-app 9 | template: 10 | metadata: 11 | labels: 12 | app: redis-app 13 | spec: 14 | containers: 15 | - name: redis-app 16 | image: redis:7.0.4 17 | ports: 18 | - containerPort: 6379 19 | command: 20 | - "redis-server" 21 | args: 22 | - "--protected-mode" 23 | - "no" 24 | --- 25 | 26 | apiVersion: v1 27 | kind: Service 28 | metadata: 29 | name: redis 30 | spec: 31 | selector: 32 | app: redis-app 33 | ports: 34 | - port: 6379 35 | targetPort: 6379 36 | 37 | -------------------------------------------------------------------------------- /k8s/service-registry-statefulset.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: eureka 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: eureka 9 | serviceName: eureka 10 | replicas: 1 11 | template: 12 | metadata: 13 | labels: 14 | app: eureka 15 | spec: 16 | containers: 17 | - name: eureka 18 | image: msbeigiai/serviceregistry:latest 19 | ports: 20 | - containerPort: 8761 21 | 22 | --- 23 | 24 | apiVersion: v1 25 | kind: Service 26 | metadata: 27 | name: eureak 28 | spec: 29 | clusterIP: None 30 | selector: 31 | app: eureka 32 | ports: 33 | - port: 8761 34 | name: eureka 35 | 36 | --- 37 | 38 | apiVersion: v1 39 | kind: Service 40 | metadata: 41 | name: eureak-lb 42 | spec: 43 | type: NodePort 44 | selector: 45 | app: eureak 46 | ports: 47 | - port: 80 48 | targetPort: 8761 49 | 50 | 51 | -------------------------------------------------------------------------------- /k8s/zipkin-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: zipkin 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: zipkin 9 | template: 10 | metadata: 11 | labels: 12 | app: zipkin 13 | spec: 14 | containers: 15 | - name: zipkin 16 | image: openzipkin/zipkin 17 | ports: 18 | - containerPort: 9411 19 | --- 20 | 21 | apiVersion: v1 22 | kind: Service 23 | metadata: 24 | name: zipkin-svc 25 | spec: 26 | selector: 27 | app: zipkin 28 | ports: 29 | - port: 9411 30 | targetPort: 9411 31 | --- 32 | 33 | apiVersion: v1 34 | kind: Service 35 | metadata: 36 | name: zipkin-lb-svc 37 | spec: 38 | type: LoadBalancer 39 | selector: 40 | app: zipkin 41 | ports: 42 | - port: 9411 43 | targetPort: 9411 44 | 45 | --------------------------------------------------------------------------------