├── .gitignore ├── 01.framework-introductions ├── jpa-in-10-steps │ ├── .gitignore │ ├── .mvn │ │ └── wrapper │ │ │ ├── maven-wrapper.jar │ │ │ └── maven-wrapper.properties │ ├── code-21July2017.zip │ ├── jpa-in-10-steps-all-code.md │ ├── mvnw │ ├── mvnw.cmd │ ├── notes.txt │ ├── pom.xml │ ├── readme.md │ ├── src │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── in28minutes │ │ │ │ │ └── learning │ │ │ │ │ └── jpa │ │ │ │ │ └── jpain10steps │ │ │ │ │ ├── JpaIn10StepsApplication.java │ │ │ │ │ ├── UserDaoServiceCommandLineRunner.java │ │ │ │ │ ├── UserRepositoryCommandLineRunner.java │ │ │ │ │ ├── entity │ │ │ │ │ └── User.java │ │ │ │ │ └── service │ │ │ │ │ ├── UserDAOService.java │ │ │ │ │ └── UserRepository.java │ │ │ └── resources │ │ │ │ └── application.properties │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── in28minutes │ │ │ └── learning │ │ │ └── jpa │ │ │ └── jpain10steps │ │ │ └── JpaIn10StepsApplicationTests.java │ ├── step-completed.sh │ ├── step21.md │ ├── step21.zip │ ├── step22.md │ ├── step22.zip │ ├── step23.md │ ├── step23.zip │ └── take-step-backup.sh └── springboot-in-10-steps │ ├── .gitignore │ ├── 1.md │ ├── 2.md │ ├── HELP.md │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── learnspringboot │ │ │ ├── LearnSpringBootApplication.java │ │ │ └── courses │ │ │ ├── bean │ │ │ └── Course.java │ │ │ ├── controller │ │ │ └── CourseController.java │ │ │ └── repository │ │ │ └── CourseRepository.java │ └── resources │ │ ├── application.properties │ │ └── data.sql │ └── test │ └── java │ └── com │ └── in28minutes │ └── learnspringboot │ └── LearnSpringBootApplicationTests.java ├── 02.restful-web-services ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── 2.3.1.RELEASE-upgrade.md ├── 2.3.1.RELEASE-upgrade.zip ├── 2.5.0-UPGRADE.md ├── backup01-after-creating-project.md ├── backup01-after-creating-project.zip ├── backup02-after-hello-world-path-param.md ├── backup02-after-hello-world-path-param.zip ├── backup03-after-two-retrieve-user-services.md ├── backup03-after-two-retrieve-user-services.zip ├── backup04-basic-create-service.md ├── backup04-basic-create-service.zip ├── backup05-after-creating-delete-method-on-user-resource.md ├── backup05-after-creating-delete-method-on-user-resource.zip ├── backup06-after-implementing-validation.md ├── backup06-after-implementing-validation.zip ├── backup06-z-content-negotiation.md ├── backup07-improving-documentation-with-swagger.md ├── backup07-improving-documentation-with-swagger.zip ├── backup08-completed-filtering.md ├── backup08-completed-filtering.zip ├── backup09-completed-versioning.md ├── backup09-completed-versioning.zip ├── backup09-z-completed-security.md ├── backup09-z-completed-security.zip ├── backup10-configure-jpa-and-repository.md ├── backup10-configure-jpa-and-repository.zip ├── backup11-added-create-post-resource.md ├── backup11-added-create-post-resource.zip ├── backup12-migrated-to-jpa.md ├── backup12-migrated-to-jpa.zip ├── code-21July2017.zip ├── mvnw ├── mvnw.cmd ├── notes.md ├── pom.xml ├── readme.md └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── in28minutes │ │ │ └── rest │ │ │ └── webservices │ │ │ └── restfulwebservices │ │ │ ├── RestfulWebServicesApplication.java │ │ │ ├── exception │ │ │ ├── CustomizedResponseEntityExceptionHandler.java │ │ │ └── ExceptionResponse.java │ │ │ ├── filtering │ │ │ ├── FilteringController.java │ │ │ └── SomeBean.java │ │ │ ├── helloworld │ │ │ ├── HelloWorldBean.java │ │ │ └── HelloWorldController.java │ │ │ ├── user │ │ │ ├── Post.java │ │ │ ├── PostRepository.java │ │ │ ├── User.java │ │ │ ├── UserDaoService.java │ │ │ ├── UserJPAResource.java │ │ │ ├── UserNotFoundException.java │ │ │ ├── UserRepository.java │ │ │ └── UserResource.java │ │ │ └── versioning │ │ │ ├── Name.java │ │ │ ├── PersonV1.java │ │ │ ├── PersonV2.java │ │ │ └── PersonVersioningController.java │ └── resources │ │ ├── application.properties │ │ ├── data.sql │ │ ├── messages.properties │ │ ├── messages_fr.properties │ │ └── messages_nl.properties │ └── test │ └── java │ └── com │ └── in28minutes │ └── rest │ └── webservices │ └── restfulwebservices │ └── RestfulWebServicesApplicationTests.java ├── 03.microservices ├── 2.3.1.RELEASE-upgrade.md ├── 2.3.1.RELEASE-upgrade.zip ├── currency-conversion-service │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── in28minutes │ │ │ │ └── microservices │ │ │ │ └── currencyconversionservice │ │ │ │ ├── CurrencyConversionBean.java │ │ │ │ ├── CurrencyConversionController.java │ │ │ │ ├── CurrencyConversionServiceApplication.java │ │ │ │ └── CurrencyExchangeServiceProxy.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── in28minutes │ │ └── microservices │ │ └── currencyconversionservice │ │ └── CurrencyConversionServiceApplicationTests.java ├── currency-exchange-service │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── in28minutes │ │ │ │ └── microservices │ │ │ │ └── currencyexchangeservice │ │ │ │ ├── CurrencyExchangeController.java │ │ │ │ ├── CurrencyExchangeServiceApplication.java │ │ │ │ ├── ExchangeValue.java │ │ │ │ └── ExchangeValueRepository.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── data.sql │ │ └── test │ │ └── java │ │ └── com │ │ └── in28minutes │ │ └── microservices │ │ └── currencyexchangeservice │ │ └── CurrencyExchangeServiceApplicationTests.java ├── limits-service │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── in28minutes │ │ │ │ └── microservices │ │ │ │ └── limitsservice │ │ │ │ ├── Configuration.java │ │ │ │ ├── LimitsConfigurationController.java │ │ │ │ ├── LimitsServiceApplication.java │ │ │ │ └── bean │ │ │ │ └── LimitConfiguration.java │ │ └── resources │ │ │ └── bootstrap.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── in28minutes │ │ └── microservices │ │ └── limitsservice │ │ └── LimitsServiceApplicationTests.java ├── netflix-eureka-naming-server │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── in28minutes │ │ │ │ └── microservices │ │ │ │ └── netflixeurekanamingserver │ │ │ │ └── NetflixEurekaNamingServerApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── in28minutes │ │ └── microservices │ │ └── netflixeurekanamingserver │ │ └── NetflixEurekaNamingServerApplicationTests.java ├── netflix-zuul-api-gateway-server │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── in28minutes │ │ │ │ └── microservices │ │ │ │ └── netflixzuulapigatewayserver │ │ │ │ ├── NetflixZuulApiGatewayServerApplication.java │ │ │ │ └── ZuulLoggingFilter.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── in28minutes │ │ └── microservices │ │ └── netflixzuulapigatewayserver │ │ └── NetflixZuulApiGatewayServerApplicationTests.java ├── readme.md ├── spring-cloud-config-server │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── in28minutes │ │ │ │ └── microservices │ │ │ │ └── springcloudconfigserver │ │ │ │ └── SpringCloudConfigServerApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── in28minutes │ │ └── microservices │ │ └── springcloudconfigserver │ │ └── SpringCloudConfigServerApplicationTests.java ├── step01.md ├── step01.zip ├── step03.md ├── step03.zip ├── step08.md ├── step08.zip ├── step09.md ├── step09.zip ├── step11.md ├── step11.zip ├── step17.md ├── step17.zip ├── step20.md ├── step20.zip ├── step23.md ├── step23.zip ├── step25.md ├── step25.zip ├── step29.md ├── step29.zip ├── step34.md ├── step34.zip ├── step41.md ├── step41.zip ├── step42.md ├── step42.zip ├── step43.md ├── step43.zip ├── step44.md └── step44.zip ├── 2.5.0-upgrade-faq.md ├── LICENSE ├── README.md ├── notes.md ├── spring-boot-2-0-0-Upgrade-notes.md ├── spring-boot-2-0-0-Upgrade-notes.pdf ├── spring-microservices-presentation.pdf └── zipkin-server-2.12.9-exec.jar /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | *.cmd 21 | *.classpath 22 | *.settings 23 | *.project 24 | *.mvn 25 | mvnw 26 | target 27 | *.DS_Store 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* 31 | bin 32 | 33 | # Ignore Mac system file 34 | .DS_Store 35 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/01.framework-introductions/jpa-in-10-steps/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip 2 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/code-21July2017.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/01.framework-introductions/jpa-in-10-steps/code-21July2017.zip -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/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 | # http://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 | # Maven2 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 /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/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 http://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 Maven2 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 key stroke 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 enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/notes.txt: -------------------------------------------------------------------------------- 1 | Questions 2 | - Where is the database created? 3 | - What schema is used to create the tables? 4 | - Where are the tables created? 5 | - Can I see the data in the database? 6 | - Where is Hibernate coming in from? 7 | - How is a datasource created? 8 | 9 | Magic of Spring Boot and in Memory Database 10 | - Zero project setup or infrastructure 11 | - Zero Configuration 12 | - Zero Maintainance 13 | - Easy to use for Learning and Unit Tests 14 | - Simple Configuration to switch to a real database 15 | 16 | # Restrictions of using in-memory database 17 | - Data is not persisted between restarts 18 | 19 | Spring Boot chooses a default value for you based on whether it thinks your database is embedded (default create-drop) or not (default none). 20 | 21 | HibernateJpaAutoConfiguration matched: 22 | - @ConditionalOnClass found required classes 'org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean', 'javax.persistence.EntityManager'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition) 23 | - HibernateEntityManager found class 'org.hibernate.ejb.HibernateEntityManager' (HibernateJpaAutoConfiguration.HibernateEntityManagerCondition) 24 | 25 | DataSourceAutoConfiguration matched: 26 | - @ConditionalOnClass found required classes 'javax.sql.DataSource', 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition) 27 | 28 | JpaBaseConfiguration#entityManagerFactory matched: 29 | - @ConditionalOnMissingBean (types: org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean,javax.persistence.EntityManagerFactory; SearchStrategy: all) did not find any beans (OnBeanCondition) 30 | 31 | JpaBaseConfiguration#transactionManager matched: 32 | - @ConditionalOnMissingBean (types: org.springframework.transaction.PlatformTransactionManager; SearchStrategy: all) did not find any beans (OnBeanCondition) 33 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.in28minutes.learning.jpa 7 | jpa-in-10-steps 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | jpa-in-10-steps 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 9 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-data-jpa 32 | 33 | 34 | 35 | 36 | javax.transaction 37 | javax.transaction-api 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-web 43 | 44 | 45 | 46 | com.h2database 47 | h2 48 | runtime 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-test 54 | test 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-maven-plugin 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-surefire-plugin 67 | 68 | --add-modules java.base 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | spring-snapshots 77 | Spring Snapshots 78 | https://repo.spring.io/snapshot 79 | 80 | true 81 | 82 | 83 | 84 | spring-milestones 85 | Spring Milestones 86 | https://repo.spring.io/milestone 87 | 88 | false 89 | 90 | 91 | 92 | 93 | 94 | 95 | spring-snapshots 96 | Spring Snapshots 97 | https://repo.spring.io/snapshot 98 | 99 | true 100 | 101 | 102 | 103 | spring-milestones 104 | Spring Milestones 105 | https://repo.spring.io/milestone 106 | 107 | false 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/src/main/java/com/in28minutes/learning/jpa/jpain10steps/JpaIn10StepsApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learning.jpa.jpain10steps; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JpaIn10StepsApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JpaIn10StepsApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/src/main/java/com/in28minutes/learning/jpa/jpain10steps/UserDaoServiceCommandLineRunner.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learning.jpa.jpain10steps; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.CommandLineRunner; 7 | import org.springframework.stereotype.Component; 8 | 9 | import com.in28minutes.learning.jpa.jpain10steps.entity.User; 10 | import com.in28minutes.learning.jpa.jpain10steps.service.UserDAOService; 11 | 12 | @Component 13 | public class UserDaoServiceCommandLineRunner implements CommandLineRunner{ 14 | 15 | private static final Logger log = 16 | LoggerFactory.getLogger(UserDaoServiceCommandLineRunner.class); 17 | 18 | @Autowired 19 | private UserDAOService userDaoService; 20 | 21 | @Override 22 | public void run(String... arg0) throws Exception { 23 | User user = new User("Jack", "Admin"); 24 | //New User is created : User [id=1, name=Jack, role=Admin] 25 | long insert = userDaoService.insert(user); 26 | log.info("New User is created : " + user); 27 | } 28 | } -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/src/main/java/com/in28minutes/learning/jpa/jpain10steps/UserRepositoryCommandLineRunner.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learning.jpa.jpain10steps; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.CommandLineRunner; 10 | import org.springframework.stereotype.Component; 11 | 12 | import com.in28minutes.learning.jpa.jpain10steps.entity.User; 13 | import com.in28minutes.learning.jpa.jpain10steps.service.UserRepository; 14 | 15 | @Component 16 | public class UserRepositoryCommandLineRunner implements CommandLineRunner{ 17 | 18 | private static final Logger log = 19 | LoggerFactory.getLogger(UserRepositoryCommandLineRunner.class); 20 | 21 | @Autowired 22 | private UserRepository userRepository; 23 | 24 | @Override 25 | public void run(String... arg0) throws Exception { 26 | User user = new User("Jill", "Admin"); 27 | userRepository.save(user); 28 | log.info("New User is created : " + user); 29 | 30 | Optional userWithIdOne = userRepository.findById(1L); 31 | log.info("User is retrived : " + userWithIdOne); 32 | 33 | List users = userRepository.findAll(); 34 | log.info("All Users : " + users); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/src/main/java/com/in28minutes/learning/jpa/jpain10steps/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learning.jpa.jpain10steps.entity; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | 7 | //Table - User 8 | @Entity 9 | public class User { 10 | 11 | @Id 12 | @GeneratedValue 13 | private long id; 14 | 15 | private String name; 16 | 17 | private String role; 18 | 19 | protected User() { 20 | 21 | } 22 | 23 | public User(String name, String role) { 24 | super(); 25 | this.name = name; 26 | this.role = role; 27 | } 28 | 29 | public long getId() { 30 | return id; 31 | } 32 | 33 | public String getName() { 34 | return name; 35 | } 36 | 37 | public String getRole() { 38 | return role; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return String.format("User [id=%s, name=%s, role=%s]", id, name, role); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/src/main/java/com/in28minutes/learning/jpa/jpain10steps/service/UserDAOService.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learning.jpa.jpain10steps.service; 2 | 3 | import javax.persistence.EntityManager; 4 | import javax.persistence.PersistenceContext; 5 | import javax.transaction.Transactional; 6 | 7 | import org.springframework.stereotype.Repository; 8 | 9 | import com.in28minutes.learning.jpa.jpain10steps.entity.User; 10 | 11 | @Repository 12 | @Transactional 13 | public class UserDAOService { 14 | 15 | @PersistenceContext 16 | private EntityManager entityManager; 17 | 18 | public long insert(User user){ 19 | entityManager.persist(user); 20 | return user.getId(); 21 | } 22 | } 23 | 24 | /* 25 | * Spring Data JPA 26 | * 27 | * 28 | * 29 | */ 30 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/src/main/java/com/in28minutes/learning/jpa/jpain10steps/service/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learning.jpa.jpain10steps.service; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import com.in28minutes.learning.jpa.jpain10steps.entity.User; 6 | 7 | public interface UserRepository extends JpaRepository{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.show-sql=true 2 | spring.h2.console.enabled=true 3 | logging.level.org.springframework=debug -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/src/test/java/com/in28minutes/learning/jpa/jpain10steps/JpaIn10StepsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learning.jpa.jpain10steps; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class JpaIn10StepsApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/step-completed.sh: -------------------------------------------------------------------------------- 1 | java -cp /ProgrammingExcellence/Workspaces/Rithus.com/ListDirectoryContentInGitFormat/bin test.ListDirectoryContentInGitFormat $PWD >> $1.md 2 | zip -r $1.zip . -x "target/*" -x ".*/*" -x ".*" -x "*.md" -x "mvn*" -x "*.zip" 3 | git add *; git commit -m "$1"; git push; 4 | -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/step21.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/01.framework-introductions/jpa-in-10-steps/step21.zip -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/step22.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/01.framework-introductions/jpa-in-10-steps/step22.zip -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/step23.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/01.framework-introductions/jpa-in-10-steps/step23.zip -------------------------------------------------------------------------------- /01.framework-introductions/jpa-in-10-steps/take-step-backup.sh: -------------------------------------------------------------------------------- 1 | java -cp /ProgrammingExcellence/Workspaces/Rithus.com/ListDirectoryContentInGitFormat/bin test.ListDirectoryContentInGitFormat $PWD >> $1.md 2 | zip -r $1.zip . -x "target/*" -x ".*/*" -x ".*" -x "*.md" -x "mvn*" -x "*.zip" -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/1.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Complete Code Example 6 | 7 | 8 | ### /pom.xml 9 | 10 | ```xml 11 | 12 | 14 | 4.0.0 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.4.4 19 | 20 | 21 | com.in28minutes 22 | learn-spring-boot 23 | 0.0.1-SNAPSHOT 24 | learn-spring-boot 25 | Demo project for Spring Boot 26 | 27 | 11 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | 42 | com.h2database 43 | h2 44 | runtime 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-actuator 50 | 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-devtools 55 | runtime 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-starter-test 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | 72 | 73 | 74 | 75 | 76 | ``` 77 | --- 78 | 79 | ### /src/test/java/com/in28minutes/learnspringboot/LearnSpringBootApplicationTests.java 80 | 81 | ```java 82 | package com.in28minutes.learnspringboot; 83 | 84 | import org.junit.jupiter.api.Test; 85 | import org.springframework.boot.test.context.SpringBootTest; 86 | 87 | @SpringBootTest 88 | class LearnSpringBootApplicationTests { 89 | 90 | @Test 91 | void contextLoads() { 92 | } 93 | 94 | } 95 | ``` 96 | --- 97 | 98 | ### /src/main/resources/data.sql 99 | 100 | ``` 101 | insert into COURSE (ID, AUTHOR, NAME) 102 | values (100001, 'in28minutes', 'Learn Microservices'); 103 | insert into COURSE (ID, AUTHOR, NAME) 104 | values (100002, 'in28minutes', 'Learn FullStack with React and Angular'); 105 | insert into COURSE (ID, AUTHOR, NAME) 106 | values (100003, 'in28minutes', 'Learn AWS, GCP and Azure'); 107 | ``` 108 | --- 109 | 110 | ### /src/main/resources/application.properties 111 | 112 | ```properties 113 | #logging.level.org.springframework=DEBUG 114 | #management.endpoints.web.exposure.include=* 115 | management.endpoints.web.exposure.include=health,metrics 116 | spring.datasource.url=jdbc:h2:mem:testdb 117 | ``` 118 | --- 119 | 120 | ### /src/main/java/com/in28minutes/learnspringboot/LearnSpringBootApplication.java 121 | 122 | ```java 123 | package com.in28minutes.learnspringboot; 124 | 125 | import org.springframework.boot.SpringApplication; 126 | import org.springframework.boot.autoconfigure.SpringBootApplication; 127 | 128 | @SpringBootApplication 129 | //@SpringBootConfiguration 130 | //@EnableAutoConfiguration 131 | //@ComponentScan 132 | public class LearnSpringBootApplication { 133 | 134 | public static void main(String[] args) { 135 | SpringApplication.run(LearnSpringBootApplication.class, args); 136 | } 137 | 138 | } 139 | ``` 140 | --- 141 | 142 | ### /src/main/java/com/in28minutes/learnspringboot/courses/repository/CourseRepository.java 143 | 144 | ```java 145 | package com.in28minutes.learnspringboot.courses.repository; 146 | 147 | import org.springframework.data.jpa.repository.JpaRepository; 148 | 149 | import com.in28minutes.learnspringboot.courses.bean.Course; 150 | 151 | public interface CourseRepository extends JpaRepository { 152 | 153 | } 154 | ``` 155 | --- 156 | 157 | ### /src/main/java/com/in28minutes/learnspringboot/courses/bean/Course.java 158 | 159 | ```java 160 | package com.in28minutes.learnspringboot.courses.bean; 161 | 162 | import javax.persistence.Column; 163 | import javax.persistence.Entity; 164 | import javax.persistence.GeneratedValue; 165 | import javax.persistence.Id; 166 | 167 | @Entity 168 | public class Course { 169 | 170 | @Id 171 | @GeneratedValue 172 | private long id; 173 | 174 | //@Column(name="course_name") 175 | private String name; 176 | 177 | private String author; 178 | 179 | public Course() { 180 | } 181 | 182 | public Course(long id, String name, String author) { 183 | super(); 184 | this.id = id; 185 | this.name = name; 186 | this.author = author; 187 | } 188 | 189 | public long getId() { 190 | return id; 191 | } 192 | 193 | public String getName() { 194 | return name; 195 | } 196 | 197 | public String getAuthor() { 198 | return author; 199 | } 200 | 201 | @Override 202 | public String toString() { 203 | return "Course [id=" + id + ", name=" + name + ", author=" + author + "]"; 204 | } 205 | 206 | } 207 | ``` 208 | --- 209 | 210 | ### /src/main/java/com/in28minutes/learnspringboot/courses/controller/CourseController.java 211 | 212 | ```java 213 | package com.in28minutes.learnspringboot.courses.controller; 214 | 215 | import java.util.List; 216 | import java.util.Optional; 217 | 218 | import org.springframework.beans.factory.annotation.Autowired; 219 | import org.springframework.web.bind.annotation.DeleteMapping; 220 | import org.springframework.web.bind.annotation.GetMapping; 221 | import org.springframework.web.bind.annotation.PathVariable; 222 | import org.springframework.web.bind.annotation.PostMapping; 223 | import org.springframework.web.bind.annotation.PutMapping; 224 | import org.springframework.web.bind.annotation.RequestBody; 225 | import org.springframework.web.bind.annotation.RestController; 226 | 227 | import com.in28minutes.learnspringboot.courses.bean.Course; 228 | import com.in28minutes.learnspringboot.courses.repository.CourseRepository; 229 | 230 | @RestController 231 | public class CourseController { 232 | 233 | @Autowired 234 | private CourseRepository repository; 235 | 236 | // http://localhost:8080/courses 237 | @GetMapping("/courses") 238 | public List getAllCourses() { 239 | return repository.findAll(); 240 | } 241 | 242 | //// http://localhost:8080/courses/1 243 | @GetMapping("/courses/{id}") 244 | public Course getCourseDetails(@PathVariable long id) { 245 | 246 | Optional course = repository.findById(id); 247 | 248 | if(course.isEmpty()) { 249 | throw new RuntimeException("Course not found with id " + id); 250 | } 251 | 252 | return course.get(); 253 | } 254 | 255 | /* 256 | POST http://localhost:8080/courses 257 | { 258 | "name": "Learn DevOps", 259 | "author": "in28minutes" 260 | }*/ 261 | 262 | //POST - Create a new resource (/courses) 263 | @PostMapping("/courses") 264 | public void createCourse(@RequestBody Course course){ 265 | repository.save(course); 266 | } 267 | 268 | /* 269 | PUT - http://localhost:8080/courses/100001 270 | { 271 | "id": 100001, 272 | "name": "Learn Microservices 2", 273 | "author": "in28minutes" 274 | } 275 | */ 276 | 277 | //PUT - Update/Replace a resource (/courses/1) 278 | @PutMapping("/courses/{id}") 279 | public void updateCourse(@PathVariable long id, @RequestBody Course course){ 280 | repository.save(course); 281 | } 282 | 283 | 284 | //DELETE - Delete a resource (/courses/1) 285 | @DeleteMapping("/courses/{id}") 286 | public void deleteCourse(@PathVariable long id){ 287 | repository.deleteById(id); 288 | } 289 | 290 | 291 | // docker run --detach 292 | // --env MYSQL_ROOT_PASSWORD=dummypassword 293 | // --env MYSQL_USER=courses-user 294 | // --env MYSQL_PASSWORD=dummycourses 295 | // --env MYSQL_DATABASE=courses 296 | // --name mysql 297 | // --publish 3306:3306 mysql:5.7 298 | } 299 | ``` 300 | --- 301 | -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/2.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | ## Complete Code Example 6 | 7 | 8 | ### /pom.xml 9 | 10 | ```xml 11 | 12 | 14 | 4.0.0 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.4.4 19 | 20 | 21 | com.in28minutes 22 | learn-spring-boot 23 | 0.0.1-SNAPSHOT 24 | learn-spring-boot 25 | Demo project for Spring Boot 26 | 27 | 11 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | 47 | 48 | 49 | mysql 50 | mysql-connector-java 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-actuator 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-devtools 61 | runtime 62 | 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-test 68 | test 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.springframework.boot 76 | spring-boot-maven-plugin 77 | 78 | 79 | 80 | 81 | 82 | ``` 83 | --- 84 | 85 | ### /src/test/java/com/in28minutes/learnspringboot/LearnSpringBootApplicationTests.java 86 | 87 | ```java 88 | package com.in28minutes.learnspringboot; 89 | 90 | import org.junit.jupiter.api.Test; 91 | import org.springframework.boot.test.context.SpringBootTest; 92 | 93 | @SpringBootTest 94 | class LearnSpringBootApplicationTests { 95 | 96 | @Test 97 | void contextLoads() { 98 | } 99 | 100 | } 101 | ``` 102 | --- 103 | 104 | ### /src/main/resources/data.sql 105 | 106 | ``` 107 | insert into COURSE (ID, AUTHOR, NAME) 108 | values (100001, 'in28minutes', 'Learn Microservices'); 109 | insert into COURSE (ID, AUTHOR, NAME) 110 | values (100002, 'in28minutes', 'Learn FullStack with React and Angular'); 111 | insert into COURSE (ID, AUTHOR, NAME) 112 | values (100003, 'in28minutes', 'Learn AWS, GCP and Azure'); 113 | ``` 114 | --- 115 | 116 | ### /src/main/resources/application.properties 117 | 118 | ```properties 119 | #logging.level.org.springframework=DEBUG 120 | #management.endpoints.web.exposure.include=* 121 | management.endpoints.web.exposure.include=health,metrics 122 | #spring.datasource.url=jdbc:h2:mem:testdb 123 | 124 | spring.jpa.hibernate.ddl-auto=update 125 | spring.datasource.url=jdbc:mysql://localhost:3306/courses 126 | spring.datasource.username=courses-user 127 | spring.datasource.password=dummycourses 128 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect 129 | 130 | #courses-user@localhost:3306 131 | ``` 132 | --- 133 | 134 | ### /src/main/java/com/in28minutes/learnspringboot/LearnSpringBootApplication.java 135 | 136 | ```java 137 | package com.in28minutes.learnspringboot; 138 | 139 | import org.springframework.boot.SpringApplication; 140 | import org.springframework.boot.autoconfigure.SpringBootApplication; 141 | 142 | @SpringBootApplication 143 | //@SpringBootConfiguration 144 | //@EnableAutoConfiguration 145 | //@ComponentScan 146 | public class LearnSpringBootApplication { 147 | 148 | public static void main(String[] args) { 149 | SpringApplication.run(LearnSpringBootApplication.class, args); 150 | } 151 | 152 | } 153 | ``` 154 | --- 155 | 156 | ### /src/main/java/com/in28minutes/learnspringboot/courses/repository/CourseRepository.java 157 | 158 | ```java 159 | package com.in28minutes.learnspringboot.courses.repository; 160 | 161 | import org.springframework.data.jpa.repository.JpaRepository; 162 | 163 | import com.in28minutes.learnspringboot.courses.bean.Course; 164 | 165 | public interface CourseRepository extends JpaRepository { 166 | 167 | } 168 | ``` 169 | --- 170 | 171 | ### /src/main/java/com/in28minutes/learnspringboot/courses/bean/Course.java 172 | 173 | ```java 174 | package com.in28minutes.learnspringboot.courses.bean; 175 | 176 | import javax.persistence.Column; 177 | import javax.persistence.Entity; 178 | import javax.persistence.GeneratedValue; 179 | import javax.persistence.Id; 180 | 181 | @Entity 182 | public class Course { 183 | 184 | @Id 185 | @GeneratedValue 186 | private long id; 187 | 188 | //@Column(name="course_name") 189 | private String name; 190 | 191 | private String author; 192 | 193 | public Course() { 194 | } 195 | 196 | public Course(long id, String name, String author) { 197 | super(); 198 | this.id = id; 199 | this.name = name; 200 | this.author = author; 201 | } 202 | 203 | public long getId() { 204 | return id; 205 | } 206 | 207 | public String getName() { 208 | return name; 209 | } 210 | 211 | public String getAuthor() { 212 | return author; 213 | } 214 | 215 | @Override 216 | public String toString() { 217 | return "Course [id=" + id + ", name=" + name + ", author=" + author + "]"; 218 | } 219 | 220 | } 221 | ``` 222 | --- 223 | 224 | ### /src/main/java/com/in28minutes/learnspringboot/courses/controller/CourseController.java 225 | 226 | ```java 227 | package com.in28minutes.learnspringboot.courses.controller; 228 | 229 | import java.util.List; 230 | import java.util.Optional; 231 | 232 | import org.springframework.beans.factory.annotation.Autowired; 233 | import org.springframework.web.bind.annotation.DeleteMapping; 234 | import org.springframework.web.bind.annotation.GetMapping; 235 | import org.springframework.web.bind.annotation.PathVariable; 236 | import org.springframework.web.bind.annotation.PostMapping; 237 | import org.springframework.web.bind.annotation.PutMapping; 238 | import org.springframework.web.bind.annotation.RequestBody; 239 | import org.springframework.web.bind.annotation.RestController; 240 | 241 | import com.in28minutes.learnspringboot.courses.bean.Course; 242 | import com.in28minutes.learnspringboot.courses.repository.CourseRepository; 243 | 244 | @RestController 245 | public class CourseController { 246 | 247 | @Autowired 248 | private CourseRepository repository; 249 | 250 | // http://localhost:8080/courses 251 | @GetMapping("/courses") 252 | public List getAllCourses() { 253 | return repository.findAll(); 254 | } 255 | 256 | //// http://localhost:8080/courses/1 257 | @GetMapping("/courses/{id}") 258 | public Course getCourseDetails(@PathVariable long id) { 259 | 260 | Optional course = repository.findById(id); 261 | 262 | if(course.isEmpty()) { 263 | throw new RuntimeException("Course not found with id " + id); 264 | } 265 | 266 | return course.get(); 267 | } 268 | 269 | /* 270 | POST http://localhost:8080/courses 271 | { 272 | "name": "Learn DevOps", 273 | "author": "in28minutes" 274 | }*/ 275 | 276 | //POST - Create a new resource (/courses) 277 | @PostMapping("/courses") 278 | public void createCourse(@RequestBody Course course){ 279 | repository.save(course); 280 | } 281 | 282 | /* 283 | PUT - http://localhost:8080/courses/100001 284 | { 285 | "id": 100001, 286 | "name": "Learn Microservices 2", 287 | "author": "in28minutes" 288 | } 289 | */ 290 | 291 | //PUT - Update/Replace a resource (/courses/1) 292 | @PutMapping("/courses/{id}") 293 | public void updateCourse(@PathVariable long id, @RequestBody Course course){ 294 | repository.save(course); 295 | } 296 | 297 | 298 | //DELETE - Delete a resource (/courses/1) 299 | @DeleteMapping("/courses/{id}") 300 | public void deleteCourse(@PathVariable long id){ 301 | repository.deleteById(id); 302 | } 303 | 304 | 305 | // docker run --detach 306 | // --env MYSQL_ROOT_PASSWORD=dummypassword 307 | // --env MYSQL_USER=courses-user 308 | // --env MYSQL_PASSWORD=dummycourses 309 | // --env MYSQL_DATABASE=courses 310 | // --name mysql 311 | // --publish 3306:3306 mysql:5.7 312 | } 313 | ``` 314 | --- 315 | -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/HELP.md: -------------------------------------------------------------------------------- 1 | # Read Me First 2 | The following was discovered as part of building this project: 3 | 4 | * The original package name 'com.in28minutes.learn-spring-boot' is invalid and this project uses 'com.in28minutes.learnspringboot' instead. 5 | 6 | # Getting Started 7 | 8 | ### Reference Documentation 9 | For further reference, please consider the following sections: 10 | 11 | * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) 12 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.4.4/maven-plugin/reference/html/) 13 | * [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.4.4/maven-plugin/reference/html/#build-image) 14 | * [Spring Web](https://docs.spring.io/spring-boot/docs/2.4.4/reference/htmlsingle/#boot-features-developing-web-applications) 15 | 16 | ### Guides 17 | The following guides illustrate how to use some features concretely: 18 | 19 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 20 | * [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) 21 | * [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/) 22 | 23 | -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.4.4 9 | 10 | 11 | com.in28minutes 12 | learn-spring-boot 13 | 0.0.1-SNAPSHOT 14 | learn-spring-boot 15 | Demo project for Spring Boot 16 | 17 | 11 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-data-jpa 29 | 30 | 31 | 37 | 38 | 39 | mysql 40 | mysql-connector-java 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-actuator 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-devtools 51 | runtime 52 | 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-starter-test 58 | test 59 | 60 | 61 | 62 | 63 | 64 | 65 | org.springframework.boot 66 | spring-boot-maven-plugin 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/src/main/java/com/in28minutes/learnspringboot/LearnSpringBootApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learnspringboot; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | //@SpringBootConfiguration 8 | //@EnableAutoConfiguration 9 | //@ComponentScan 10 | public class LearnSpringBootApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(LearnSpringBootApplication.class, args); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/src/main/java/com/in28minutes/learnspringboot/courses/bean/Course.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learnspringboot.courses.bean; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | 8 | @Entity 9 | public class Course { 10 | 11 | @Id 12 | @GeneratedValue 13 | private long id; 14 | 15 | //@Column(name="course_name") 16 | private String name; 17 | 18 | private String author; 19 | 20 | public Course() { 21 | } 22 | 23 | public Course(long id, String name, String author) { 24 | super(); 25 | this.id = id; 26 | this.name = name; 27 | this.author = author; 28 | } 29 | 30 | public long getId() { 31 | return id; 32 | } 33 | 34 | public String getName() { 35 | return name; 36 | } 37 | 38 | public String getAuthor() { 39 | return author; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "Course [id=" + id + ", name=" + name + ", author=" + author + "]"; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/src/main/java/com/in28minutes/learnspringboot/courses/controller/CourseController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learnspringboot.courses.controller; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.DeleteMapping; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.PutMapping; 12 | import org.springframework.web.bind.annotation.RequestBody; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import com.in28minutes.learnspringboot.courses.bean.Course; 16 | import com.in28minutes.learnspringboot.courses.repository.CourseRepository; 17 | 18 | @RestController 19 | public class CourseController { 20 | 21 | @Autowired 22 | private CourseRepository repository; 23 | 24 | // http://localhost:8080/courses 25 | @GetMapping("/courses") 26 | public List getAllCourses() { 27 | return repository.findAll(); 28 | } 29 | 30 | //// http://localhost:8080/courses/1 31 | @GetMapping("/courses/{id}") 32 | public Course getCourseDetails(@PathVariable long id) { 33 | 34 | Optional course = repository.findById(id); 35 | 36 | if(course.isEmpty()) { 37 | throw new RuntimeException("Course not found with id " + id); 38 | } 39 | 40 | return course.get(); 41 | } 42 | 43 | /* 44 | POST http://localhost:8080/courses 45 | { 46 | "name": "Learn DevOps", 47 | "author": "in28minutes" 48 | }*/ 49 | 50 | //POST - Create a new resource (/courses) 51 | @PostMapping("/courses") 52 | public void createCourse(@RequestBody Course course){ 53 | repository.save(course); 54 | } 55 | 56 | /* 57 | PUT - http://localhost:8080/courses/100001 58 | { 59 | "id": 100001, 60 | "name": "Learn Microservices 2", 61 | "author": "in28minutes" 62 | } 63 | */ 64 | 65 | //PUT - Update/Replace a resource (/courses/1) 66 | @PutMapping("/courses/{id}") 67 | public void updateCourse(@PathVariable long id, @RequestBody Course course){ 68 | repository.save(course); 69 | } 70 | 71 | 72 | //DELETE - Delete a resource (/courses/1) 73 | @DeleteMapping("/courses/{id}") 74 | public void deleteCourse(@PathVariable long id){ 75 | repository.deleteById(id); 76 | } 77 | 78 | 79 | // docker run --detach 80 | // --env MYSQL_ROOT_PASSWORD=dummypassword 81 | // --env MYSQL_USER=courses-user 82 | // --env MYSQL_PASSWORD=dummycourses 83 | // --env MYSQL_DATABASE=courses 84 | // --name mysql 85 | // --publish 3306:3306 mysql:5.7 86 | } 87 | -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/src/main/java/com/in28minutes/learnspringboot/courses/repository/CourseRepository.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learnspringboot.courses.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import com.in28minutes.learnspringboot.courses.bean.Course; 6 | 7 | public interface CourseRepository extends JpaRepository { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #logging.level.org.springframework=DEBUG 2 | #management.endpoints.web.exposure.include=* 3 | management.endpoints.web.exposure.include=health,metrics 4 | #spring.datasource.url=jdbc:h2:mem:testdb 5 | 6 | spring.jpa.hibernate.ddl-auto=update 7 | spring.datasource.url=jdbc:mysql://localhost:3306/courses 8 | spring.datasource.username=courses-user 9 | spring.datasource.password=dummycourses 10 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect 11 | 12 | #courses-user@localhost:3306 -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into COURSE (ID, AUTHOR, NAME) 2 | values (100001, 'in28minutes', 'Learn Microservices'); 3 | insert into COURSE (ID, AUTHOR, NAME) 4 | values (100002, 'in28minutes', 'Learn FullStack with React and Angular'); 5 | insert into COURSE (ID, AUTHOR, NAME) 6 | values (100003, 'in28minutes', 'Learn AWS, GCP and Azure'); -------------------------------------------------------------------------------- /01.framework-introductions/springboot-in-10-steps/src/test/java/com/in28minutes/learnspringboot/LearnSpringBootApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.learnspringboot; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class LearnSpringBootApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /02.restful-web-services/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /02.restful-web-services/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /02.restful-web-services/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip 2 | -------------------------------------------------------------------------------- /02.restful-web-services/2.3.1.RELEASE-upgrade.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/2.3.1.RELEASE-upgrade.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup01-after-creating-project.md: -------------------------------------------------------------------------------- 1 | 2 | ## Complete Code Example 3 | 4 | 5 | ### /pom.xml 6 | 7 | ```xml 8 | 9 | 11 | 4.0.0 12 | 13 | com.in28minutes.rest.webservices 14 | restful-web-services 15 | 0.0.1-SNAPSHOT 16 | jar 17 | 18 | restful-web-services 19 | Demo project for Spring Boot 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-parent 24 | 2.0.0.RELEASE 25 | 26 | 27 | 28 | 29 | UTF-8 30 | UTF-8 31 | 1.8 32 | 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-data-jpa 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-web 42 | 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-devtools 47 | runtime 48 | 49 | 50 | com.h2database 51 | h2 52 | runtime 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-test 57 | test 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | 70 | 71 | 72 | spring-snapshots 73 | Spring Snapshots 74 | https://repo.spring.io/snapshot 75 | 76 | true 77 | 78 | 79 | 80 | spring-milestones 81 | Spring Milestones 82 | https://repo.spring.io/milestone 83 | 84 | false 85 | 86 | 87 | 88 | 89 | 90 | 91 | spring-snapshots 92 | Spring Snapshots 93 | https://repo.spring.io/snapshot 94 | 95 | true 96 | 97 | 98 | 99 | spring-milestones 100 | Spring Milestones 101 | https://repo.spring.io/milestone 102 | 103 | false 104 | 105 | 106 | 107 | 108 | 109 | 110 | ``` 111 | --- 112 | 113 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java 114 | 115 | ```java 116 | package com.in28minutes.rest.webservices.restfulwebservices; 117 | 118 | import org.springframework.boot.SpringApplication; 119 | import org.springframework.boot.autoconfigure.SpringBootApplication; 120 | 121 | @SpringBootApplication 122 | public class RestfulWebServicesApplication { 123 | 124 | public static void main(String[] args) { 125 | SpringApplication.run(RestfulWebServicesApplication.class, args); 126 | } 127 | } 128 | ``` 129 | --- 130 | 131 | ### /src/main/resources/application.properties 132 | 133 | ```properties 134 | ``` 135 | --- 136 | 137 | ### /src/test/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplicationTests.java 138 | 139 | ```java 140 | package com.in28minutes.rest.webservices.restfulwebservices; 141 | 142 | import org.junit.Test; 143 | import org.junit.runner.RunWith; 144 | import org.springframework.boot.test.context.SpringBootTest; 145 | import org.springframework.test.context.junit4.SpringRunner; 146 | 147 | @RunWith(SpringRunner.class) 148 | @SpringBootTest 149 | public class RestfulWebServicesApplicationTests { 150 | 151 | @Test 152 | public void contextLoads() { 153 | } 154 | 155 | } 156 | ``` 157 | --- 158 | -------------------------------------------------------------------------------- /02.restful-web-services/backup01-after-creating-project.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup01-after-creating-project.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup02-after-hello-world-path-param.md: -------------------------------------------------------------------------------- 1 | 2 | ## Complete Code Example 3 | 4 | 5 | ### /pom.xml 6 | 7 | ```xml 8 | 9 | 11 | 4.0.0 12 | 13 | com.in28minutes.rest.webservices 14 | restful-web-services 15 | 0.0.1-SNAPSHOT 16 | jar 17 | 18 | restful-web-services 19 | Demo project for Spring Boot 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-parent 24 | 2.0.0.RELEASE 25 | 26 | 27 | 28 | 29 | UTF-8 30 | UTF-8 31 | 1.8 32 | 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-web 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-devtools 49 | runtime 50 | 51 | 52 | 53 | com.h2database 54 | h2 55 | runtime 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-test 61 | test 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | 73 | 74 | 75 | 76 | spring-snapshots 77 | Spring Snapshots 78 | https://repo.spring.io/snapshot 79 | 80 | true 81 | 82 | 83 | 84 | spring-milestones 85 | Spring Milestones 86 | https://repo.spring.io/milestone 87 | 88 | false 89 | 90 | 91 | 92 | 93 | 94 | 95 | spring-snapshots 96 | Spring Snapshots 97 | https://repo.spring.io/snapshot 98 | 99 | true 100 | 101 | 102 | 103 | spring-milestones 104 | Spring Milestones 105 | https://repo.spring.io/milestone 106 | 107 | false 108 | 109 | 110 | 111 | 112 | 113 | 114 | ``` 115 | --- 116 | 117 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldBean.java 118 | 119 | ```java 120 | package com.in28minutes.rest.webservices.restfulwebservices; 121 | 122 | public class HelloWorldBean { 123 | 124 | private String message; 125 | 126 | public HelloWorldBean(String message) { 127 | this.message = message; 128 | } 129 | 130 | public String getMessage() { 131 | return message; 132 | } 133 | 134 | public void setMessage(String message) { 135 | this.message = message; 136 | } 137 | 138 | @Override 139 | public String toString() { 140 | return String.format("HelloWorldBean [message=%s]", message); 141 | } 142 | 143 | } 144 | ``` 145 | --- 146 | 147 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/HelloWorldController.java 148 | 149 | ```java 150 | package com.in28minutes.rest.webservices.restfulwebservices; 151 | 152 | import org.springframework.web.bind.annotation.GetMapping; 153 | import org.springframework.web.bind.annotation.PathVariable; 154 | import org.springframework.web.bind.annotation.RestController; 155 | 156 | //Controller 157 | @RestController 158 | public class HelloWorldController { 159 | 160 | @GetMapping(path = "/hello-world") 161 | public String helloWorld() { 162 | return "Hello World"; 163 | } 164 | 165 | @GetMapping(path = "/hello-world-bean") 166 | public HelloWorldBean helloWorldBean() { 167 | return new HelloWorldBean("Hello World"); 168 | } 169 | 170 | ///hello-world/path-variable/in28minutes 171 | @GetMapping(path = "/hello-world/path-variable/{name}") 172 | public HelloWorldBean helloWorldPathVariable(@PathVariable String name) { 173 | return new HelloWorldBean(String.format("Hello World, %s", name)); 174 | } 175 | 176 | } 177 | ``` 178 | --- 179 | 180 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java 181 | 182 | ```java 183 | package com.in28minutes.rest.webservices.restfulwebservices; 184 | 185 | import org.springframework.boot.SpringApplication; 186 | import org.springframework.boot.autoconfigure.SpringBootApplication; 187 | 188 | @SpringBootApplication 189 | public class RestfulWebServicesApplication { 190 | 191 | public static void main(String[] args) { 192 | SpringApplication.run(RestfulWebServicesApplication.class, args); 193 | } 194 | } 195 | ``` 196 | --- 197 | 198 | ### /src/main/resources/application.properties 199 | 200 | ```properties 201 | logging.level.org.springframework = info 202 | ``` 203 | --- 204 | 205 | ### /src/test/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplicationTests.java 206 | 207 | ```java 208 | package com.in28minutes.rest.webservices.restfulwebservices; 209 | 210 | import org.junit.Test; 211 | import org.junit.runner.RunWith; 212 | import org.springframework.boot.test.context.SpringBootTest; 213 | import org.springframework.test.context.junit4.SpringRunner; 214 | 215 | @RunWith(SpringRunner.class) 216 | @SpringBootTest 217 | public class RestfulWebServicesApplicationTests { 218 | 219 | @Test 220 | public void contextLoads() { 221 | } 222 | 223 | } 224 | ``` 225 | --- 226 | -------------------------------------------------------------------------------- /02.restful-web-services/backup02-after-hello-world-path-param.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup02-after-hello-world-path-param.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup03-after-two-retrieve-user-services.md: -------------------------------------------------------------------------------- 1 | 2 | ## Complete Code Example 3 | 4 | 5 | ### /pom.xml 6 | 7 | ```xml 8 | 9 | 11 | 4.0.0 12 | 13 | com.in28minutes.rest.webservices 14 | restful-web-services 15 | 0.0.1-SNAPSHOT 16 | jar 17 | 18 | restful-web-services 19 | Demo project for Spring Boot 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-parent 24 | 2.0.0.RELEASE 25 | 26 | 27 | 28 | 29 | UTF-8 30 | UTF-8 31 | 1.8 32 | 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-web 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-devtools 49 | runtime 50 | 51 | 52 | 53 | com.h2database 54 | h2 55 | runtime 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-test 61 | test 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | 73 | 74 | 75 | 76 | spring-snapshots 77 | Spring Snapshots 78 | https://repo.spring.io/snapshot 79 | 80 | true 81 | 82 | 83 | 84 | spring-milestones 85 | Spring Milestones 86 | https://repo.spring.io/milestone 87 | 88 | false 89 | 90 | 91 | 92 | 93 | 94 | 95 | spring-snapshots 96 | Spring Snapshots 97 | https://repo.spring.io/snapshot 98 | 99 | true 100 | 101 | 102 | 103 | spring-milestones 104 | Spring Milestones 105 | https://repo.spring.io/milestone 106 | 107 | false 108 | 109 | 110 | 111 | 112 | 113 | 114 | ``` 115 | --- 116 | 117 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/helloworld/HelloWorldBean.java 118 | 119 | ```java 120 | package com.in28minutes.rest.webservices.restfulwebservices.helloworld; 121 | 122 | public class HelloWorldBean { 123 | 124 | private String message; 125 | 126 | public HelloWorldBean(String message) { 127 | this.message = message; 128 | } 129 | 130 | public String getMessage() { 131 | return message; 132 | } 133 | 134 | public void setMessage(String message) { 135 | this.message = message; 136 | } 137 | 138 | @Override 139 | public String toString() { 140 | return String.format("HelloWorldBean [message=%s]", message); 141 | } 142 | 143 | } 144 | ``` 145 | --- 146 | 147 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/helloworld/HelloWorldController.java 148 | 149 | ```java 150 | package com.in28minutes.rest.webservices.restfulwebservices.helloworld; 151 | 152 | import org.springframework.web.bind.annotation.GetMapping; 153 | import org.springframework.web.bind.annotation.PathVariable; 154 | import org.springframework.web.bind.annotation.RestController; 155 | 156 | //Controller 157 | @RestController 158 | public class HelloWorldController { 159 | 160 | @GetMapping(path = "/hello-world") 161 | public String helloWorld() { 162 | return "Hello World"; 163 | } 164 | 165 | @GetMapping(path = "/hello-world-bean") 166 | public HelloWorldBean helloWorldBean() { 167 | return new HelloWorldBean("Hello World"); 168 | } 169 | 170 | ///hello-world/path-variable/in28minutes 171 | @GetMapping(path = "/hello-world/path-variable/{name}") 172 | public HelloWorldBean helloWorldPathVariable(@PathVariable String name) { 173 | return new HelloWorldBean(String.format("Hello World, %s", name)); 174 | } 175 | 176 | } 177 | ``` 178 | --- 179 | 180 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java 181 | 182 | ```java 183 | package com.in28minutes.rest.webservices.restfulwebservices; 184 | 185 | import org.springframework.boot.SpringApplication; 186 | import org.springframework.boot.autoconfigure.SpringBootApplication; 187 | 188 | @SpringBootApplication 189 | public class RestfulWebServicesApplication { 190 | 191 | public static void main(String[] args) { 192 | SpringApplication.run(RestfulWebServicesApplication.class, args); 193 | } 194 | } 195 | ``` 196 | --- 197 | 198 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/User.java 199 | 200 | ```java 201 | 202 | package com.in28minutes.rest.webservices.restfulwebservices.user; 203 | 204 | import java.util.Date; 205 | 206 | public class User { 207 | 208 | private Integer id; 209 | 210 | private String name; 211 | 212 | private Date birthDate; 213 | 214 | public User(Integer id, String name, Date birthDate) { 215 | super(); 216 | this.id = id; 217 | this.name = name; 218 | this.birthDate = birthDate; 219 | } 220 | 221 | public Integer getId() { 222 | return id; 223 | } 224 | 225 | public void setId(Integer id) { 226 | this.id = id; 227 | } 228 | 229 | public String getName() { 230 | return name; 231 | } 232 | 233 | public void setName(String name) { 234 | this.name = name; 235 | } 236 | 237 | public Date getBirthDate() { 238 | return birthDate; 239 | } 240 | 241 | public void setBirthDate(Date birthDate) { 242 | this.birthDate = birthDate; 243 | } 244 | 245 | @Override 246 | public String toString() { 247 | return String.format("User [id=%s, name=%s, birthDate=%s]", id, name, birthDate); 248 | } 249 | 250 | } 251 | ``` 252 | --- 253 | 254 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/UserDaoService.java 255 | 256 | ```java 257 | package com.in28minutes.rest.webservices.restfulwebservices.user; 258 | 259 | import java.util.ArrayList; 260 | import java.util.Date; 261 | import java.util.List; 262 | 263 | import org.springframework.stereotype.Component; 264 | 265 | @Component 266 | public class UserDaoService { 267 | private static List users = new ArrayList<>(); 268 | 269 | private static int usersCount = 3; 270 | 271 | static { 272 | users.add(new User(1, "Adam", new Date())); 273 | users.add(new User(2, "Eve", new Date())); 274 | users.add(new User(3, "Jack", new Date())); 275 | } 276 | 277 | public List findAll() { 278 | return users; 279 | } 280 | 281 | public User save(User user) { 282 | if (user.getId() == null) { 283 | user.setId(++usersCount); 284 | } 285 | users.add(user); 286 | return user; 287 | } 288 | 289 | public User findOne(int id) { 290 | for (User user : users) { 291 | if (user.getId() == id) { 292 | return user; 293 | } 294 | } 295 | return null; 296 | } 297 | 298 | } 299 | ``` 300 | --- 301 | 302 | ### /src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/UserResource.java 303 | 304 | ```java 305 | package com.in28minutes.rest.webservices.restfulwebservices.user; 306 | 307 | import java.util.List; 308 | 309 | import org.springframework.beans.factory.annotation.Autowired; 310 | import org.springframework.web.bind.annotation.GetMapping; 311 | import org.springframework.web.bind.annotation.PathVariable; 312 | import org.springframework.web.bind.annotation.RestController; 313 | 314 | @RestController 315 | public class UserResource { 316 | 317 | @Autowired 318 | private UserDaoService service; 319 | 320 | @GetMapping("/users") 321 | public List retrieveAllUsers() { 322 | return service.findAll(); 323 | } 324 | 325 | @GetMapping("/users/{id}") 326 | public User retrieveUser(@PathVariable int id) { 327 | return service.findOne(id); 328 | } 329 | 330 | } 331 | ``` 332 | --- 333 | 334 | ### /src/main/resources/application.properties 335 | 336 | ```properties 337 | logging.level.org.springframework = info 338 | #This is not really needed as this is the default after 2.0.0.RELEASE 339 | spring.jackson.serialization.write-dates-as-timestamps=false 340 | spring.messages.basename=messages 341 | ``` 342 | --- 343 | 344 | ### /src/test/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplicationTests.java 345 | 346 | ```java 347 | package com.in28minutes.rest.webservices.restfulwebservices; 348 | 349 | import org.junit.Test; 350 | import org.junit.runner.RunWith; 351 | import org.springframework.boot.test.context.SpringBootTest; 352 | import org.springframework.test.context.junit4.SpringRunner; 353 | 354 | @RunWith(SpringRunner.class) 355 | @SpringBootTest 356 | public class RestfulWebServicesApplicationTests { 357 | 358 | @Test 359 | public void contextLoads() { 360 | } 361 | 362 | } 363 | ``` 364 | --- 365 | -------------------------------------------------------------------------------- /02.restful-web-services/backup03-after-two-retrieve-user-services.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup03-after-two-retrieve-user-services.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup04-basic-create-service.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup04-basic-create-service.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup05-after-creating-delete-method-on-user-resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup05-after-creating-delete-method-on-user-resource.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup06-after-implementing-validation.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup06-after-implementing-validation.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup07-improving-documentation-with-swagger.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup07-improving-documentation-with-swagger.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup08-completed-filtering.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup08-completed-filtering.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup09-completed-versioning.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup09-completed-versioning.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup09-z-completed-security.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup09-z-completed-security.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup10-configure-jpa-and-repository.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup10-configure-jpa-and-repository.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup11-added-create-post-resource.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup11-added-create-post-resource.zip -------------------------------------------------------------------------------- /02.restful-web-services/backup12-migrated-to-jpa.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/backup12-migrated-to-jpa.zip -------------------------------------------------------------------------------- /02.restful-web-services/code-21July2017.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/02.restful-web-services/code-21July2017.zip -------------------------------------------------------------------------------- /02.restful-web-services/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 | # http://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 | # Maven2 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 /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /02.restful-web-services/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 http://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 Maven2 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 key stroke 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 enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /02.restful-web-services/notes.md: -------------------------------------------------------------------------------- 1 | 2 | # RESTful Web Services 3 | 4 | ## Social Media Application Resource Mappings 5 | 6 | ### User -> Posts 7 | 8 | - Retrieve all Users - GET /users 9 | - Create a User - POST /users 10 | - Retrieve one User - GET /users/{id} -> /users/1 11 | - Delete a User - DELETE /users/{id} -> /users/1 12 | 13 | - Retrieve all posts for a User - GET /users/{id}/posts 14 | - Create a posts for a User - POST /users/{id}/posts 15 | - Retrieve details of a post - GET /users/{id}/posts/{post_id} 16 | 17 | ## Error in the Log 18 | ``` 19 | Resolved exception caused by Handler execution: 20 | org.springframework.http.converter.HttpMessageNotWritableException: 21 | No converter found for return value of type: 22 | class com.in28minutes.rest.webservices.restfulwebservices.HelloWorldBean 23 | ``` 24 | - This happened because there were no getters in HelloWorldBean class 25 | 26 | ## Questions to Answer 27 | 28 | - What is dispatcher servlet? 29 | - Who is configuring dispatcher servlet? 30 | - What does dispatcher servlet do? 31 | - How does the HelloWorldBean object get converted to JSON? 32 | - Who is configuring the error mapping? 33 | 34 | - Mapping servlet: 'dispatcherServlet' to [/] 35 | 36 | - Mapped "{[/hello-world],methods=[GET]}" onto 37 | public java.lang.String com.in28minutes.rest.webservices.restfulwebservices.HelloWorldController.helloWorld() 38 | - Mapped "{[/hello-world-bean],methods=[GET]}" onto 39 | public com.in28minutes.rest.webservices.restfulwebservices.HelloWorldBean com.in28minutes.rest.webservices.restfulwebservices.HelloWorldController.helloWorldBean() 40 | - Mapped "{[/error]}" onto 41 | public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 42 | - Mapped "{[/error],produces=[text/html]}" onto 43 | public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 44 | 45 | ### Example Requests 46 | 47 | #### GET http://localhost:8080/users 48 | ```json 49 | [ 50 | { 51 | "id": 1, 52 | "name": "Adam", 53 | "birthDate": "2017-07-19T04:40:20.796+0000" 54 | }, 55 | { 56 | "id": 2, 57 | "name": "Eve", 58 | "birthDate": "2017-07-19T04:40:20.796+0000" 59 | }, 60 | { 61 | "id": 3, 62 | "name": "Jack", 63 | "birthDate": "2017-07-19T04:40:20.796+0000" 64 | } 65 | ] 66 | ``` 67 | #### GET http://localhost:8080/users/1 68 | ```json 69 | { 70 | "id": 1, 71 | "name": "Adam", 72 | "birthDate": "2017-07-19T04:40:20.796+0000" 73 | } 74 | ``` 75 | #### POST http://localhost:8080/users 76 | ```json 77 | { 78 | "name": "Ranga", 79 | "birthDate": "2000-07-19T04:29:24.054+0000" 80 | } 81 | ``` 82 | 83 | #### GET http://localhost:8080/users/1000 84 | - Get request to a non existing resource. 85 | - The response shows default error message structure auto configured by Spring Boot. 86 | 87 | ```json 88 | { 89 | "timestamp": "2017-07-19T05:28:37.534+0000", 90 | "status": 404, 91 | "error": "Not Found", 92 | "message": "id-500", 93 | "path": "/users/500" 94 | } 95 | ``` 96 | 97 | #### GET http://localhost:8080/users/1000 98 | - Get request to a non existing resource. 99 | - The response shows a Customized Message Structure 100 | ```json 101 | { 102 | "timestamp": "2017-07-19T05:31:01.961+0000", 103 | "message": "id-500", 104 | "details": "Any details you would want to add" 105 | } 106 | ``` 107 | 108 | #### POST http://localhost:8080/users with Validation Errors 109 | 110 | ##### Request 111 | ```json 112 | { 113 | "name": "R", 114 | "birthDate": "2000-07-19T04:29:24.054+0000" 115 | } 116 | ``` 117 | ##### Response - 400 Bad Request 118 | ```json 119 | { 120 | "timestamp": "2017-07-19T09:00:27.912+0000", 121 | "message": "Validation Failed", 122 | "details": "org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object 'user' on field 'name': rejected value [R]; codes [Size.user.name,Size.name,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name],2147483647,2]; default message [Name should have atleast 2 characters]" 123 | } 124 | ``` 125 | #### GET http://localhost:8080/users/1 with HATEOAS 126 | ```json 127 | { 128 | "id": 1, 129 | "name": "Adam", 130 | "birthDate": "2017-07-19T09:26:18.337+0000", 131 | "_links": { 132 | "all-users": { 133 | "href": "http://localhost:8080/users" 134 | } 135 | } 136 | } 137 | ``` 138 | #### Internationalization 139 | 140 | ##### Configuration 141 | - LocaleResolver 142 | - Default Locale - Locale.US 143 | - ResourceBundleMessageSource 144 | 145 | ##### Usage 146 | - Autowire MessageSource 147 | - @RequestHeader(value = "Accept-Language", required = false) Locale locale 148 | - messageSource.getMessage("helloWorld.message", null, locale) 149 | 150 | ### XML Representation of Resources 151 | 152 | #### GET http://localhost:8080/users 153 | - Accept application/xml 154 | ```xml 155 | 156 | 157 | 2 158 | Eve 159 | 2017-07-19T10:25:20.450+0000 160 | 161 | 162 | 3 163 | Jack 164 | 2017-07-19T10:25:20.450+0000 165 | 166 | 167 | 4 168 | Ranga 169 | 2017-07-19T10:25:20.450+0000 170 | 171 | 172 | ``` 173 | 174 | #### POST http://localhost:8080/users 175 | - Accept : application/xml 176 | - Content-Type : application/xml 177 | 178 | Request 179 | ```xml 180 | 181 | Ranga 182 | 2017-07-19T10:25:20.450+0000 183 | 184 | ``` 185 | 186 | Response 187 | - Status - 201 Created 188 | 189 | ## Generating Swagger Documentation 190 | 191 | 192 | ```java 193 | public static final Contact DEFAULT_CONTACT = new Contact( 194 | "Ranga Karanam", "http://www.in28minutes.com", "in28minutes@gmail.com"); 195 | 196 | public static final ApiInfo DEFAULT_API_INFO = new ApiInfo( 197 | "Awesome API Title", "Awesome API Description", "1.0", 198 | "urn:tos", DEFAULT_CONTACT, 199 | "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0"); 200 | 201 | private static final Set DEFAULT_PRODUCES_AND_CONSUMES = 202 | new HashSet(Arrays.asList("application/json", 203 | "application/xml")); 204 | 205 | @Bean 206 | public Docket api() { 207 | return new Docket(DocumentationType.SWAGGER_2) 208 | .apiInfo(DEFAULT_API_INFO) 209 | .produces(DEFAULT_PRODUCES_AND_CONSUMES) 210 | .consumes(DEFAULT_PRODUCES_AND_CONSUMES); 211 | } 212 | 213 | ``` 214 | 215 | ### Resource Method description 216 | ```java 217 | @GetMapping("/users/{id}") 218 | @ApiOperation(value = "Finds Users by id", 219 | notes = "Also returns a link to retrieve all users with rel - all-users") 220 | public Resource retrieveUser(@PathVariable int id) { 221 | ``` 222 | 223 | ### API Model 224 | ```java 225 | 226 | @ApiModel(value="User Details", description="Contains all details of a user") 227 | public class User { 228 | 229 | @Size(min=2, message="Name should have atleast 2 characters") 230 | @ApiModelProperty(notes = "Name should have atleast 2 characters") 231 | private String name; 232 | 233 | @Past 234 | @ApiModelProperty(notes = "Birth Date should be in the Past") 235 | private Date birthDate; 236 | ``` 237 | 238 | #### Filtering 239 | 240 | ##### Code 241 | ```java 242 | @JsonIgnoreProperties(value={"field1"}) 243 | public class SomeBean { 244 | 245 | private String field1; 246 | 247 | @JsonIgnore 248 | private String field2; 249 | 250 | private String field3; 251 | 252 | ``` 253 | ##### Response 254 | ```json 255 | { 256 | "field3": "value3" 257 | } 258 | ``` 259 | 260 | ### Versioning 261 | - Media type versioning (a.k.a “content negotiation” or “accept header”) 262 | - GitHub 263 | - (Custom) headers versioning 264 | - Microsoft 265 | - URI Versioning 266 | - Twitter 267 | - Request Parameter versioning 268 | - Amazon 269 | - Factors 270 | - URI Pollution 271 | - Misuse of HTTP Headers 272 | - Caching 273 | - Can we execute the request on the browser? 274 | - API Documentation 275 | - No Perfect Solution 276 | 277 | #### More 278 | - https://www.mnot.net/blog/2011/10/25/web_api_versioning_smackdown 279 | - http://urthen.github.io/2013/05/09/ways-to-version-your-api/ 280 | - http://stackoverflow.com/questions/389169/best-practices-for-api-versioning 281 | - http://www.lexicalscope.com/blog/2012/03/12/how-are-rest-apis-versioned/ 282 | - https://www.3scale.net/2016/06/api-versioning-methods-a-brief-reference/ 283 | 284 | 285 | #### Table Structure 286 | 287 | ```sql 288 | create table user ( 289 | id integer not null, 290 | birth_date timestamp, 291 | name varchar(255), 292 | primary key (id) 293 | ); 294 | 295 | create table post ( 296 | id integer not null, 297 | description varchar(255), 298 | user_id integer, 299 | primary key (id) 300 | ); 301 | 302 | alter table post 303 | add constraint post_to_user_foreign_key 304 | foreign key (user_id) references user; 305 | ``` -------------------------------------------------------------------------------- /02.restful-web-services/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.in28minutes.rest.webservices 7 | restful-web-services 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | restful-web-services 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.5.0 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 3.1.1 26 | 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-data-jpa 33 | 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-web 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-validation 44 | 45 | 46 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-actuator 54 | 55 | 56 | 57 | org.springframework.data 58 | spring-data-rest-hal-explorer 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-hateoas 65 | 66 | 67 | 78 | 79 | 80 | org.springdoc 81 | springdoc-openapi-ui 82 | 1.5.9 83 | 84 | 85 | 86 | org.springframework.boot 87 | spring-boot-devtools 88 | runtime 89 | 90 | 91 | 92 | com.h2database 93 | h2 94 | runtime 95 | 96 | 97 | 98 | org.springframework.boot 99 | spring-boot-starter-test 100 | test 101 | 102 | 103 | 104 | 105 | 106 | 107 | org.springframework.boot 108 | spring-boot-maven-plugin 109 | 110 | 111 | 112 | 113 | 114 | 115 | spring-snapshots 116 | Spring Snapshots 117 | https://repo.spring.io/snapshot 118 | 119 | true 120 | 121 | 122 | 123 | jfrog-snapshots 124 | JFROG Snapshots 125 | http://oss.jfrog.org/artifactory/oss-snapshot-local 126 | 127 | true 128 | 129 | 130 | 131 | spring-milestones 132 | Spring Milestones 133 | https://repo.spring.io/milestone 134 | 135 | false 136 | 137 | 138 | 139 | 140 | 141 | 142 | spring-snapshots 143 | Spring Snapshots 144 | https://repo.spring.io/snapshot 145 | 146 | true 147 | 148 | 149 | 150 | spring-milestones 151 | Spring Milestones 152 | https://repo.spring.io/milestone 153 | 154 | false 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RestfulWebServicesApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RestfulWebServicesApplication.class, args); 11 | } 12 | 13 | // @Bean 14 | // public LocaleResolver localeResolver() { 15 | // AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); 16 | // localeResolver.setDefaultLocale(Locale.US); 17 | // return localeResolver; 18 | // } 19 | } 20 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/exception/CustomizedResponseEntityExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.exception; 2 | 3 | import java.util.Date; 4 | 5 | import org.springframework.http.HttpHeaders; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.MethodArgumentNotValidException; 9 | import org.springframework.web.bind.annotation.ControllerAdvice; 10 | import org.springframework.web.bind.annotation.ExceptionHandler; 11 | import org.springframework.web.bind.annotation.RestController; 12 | import org.springframework.web.context.request.WebRequest; 13 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 14 | 15 | import com.in28minutes.rest.webservices.restfulwebservices.user.UserNotFoundException; 16 | 17 | @ControllerAdvice 18 | @RestController 19 | public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { 20 | 21 | @ExceptionHandler(Exception.class) 22 | public final ResponseEntity handleAllExceptions(Exception ex, WebRequest request) { 23 | ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), 24 | request.getDescription(false)); 25 | return new ResponseEntity(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR); 26 | } 27 | 28 | @ExceptionHandler(UserNotFoundException.class) 29 | public final ResponseEntity handleUserNotFoundException(UserNotFoundException ex, WebRequest request) { 30 | ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), 31 | request.getDescription(false)); 32 | return new ResponseEntity(exceptionResponse, HttpStatus.NOT_FOUND); 33 | } 34 | 35 | @Override 36 | protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, 37 | HttpHeaders headers, HttpStatus status, WebRequest request) { 38 | ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), "Validation Failed", 39 | ex.getBindingResult().toString()); 40 | return new ResponseEntity(exceptionResponse, HttpStatus.BAD_REQUEST); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/exception/ExceptionResponse.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.exception; 2 | 3 | import java.util.Date; 4 | 5 | public class ExceptionResponse { 6 | private Date timestamp; 7 | private String message; 8 | private String details; 9 | 10 | public ExceptionResponse(Date timestamp, String message, String details) { 11 | super(); 12 | this.timestamp = timestamp; 13 | this.message = message; 14 | this.details = details; 15 | } 16 | 17 | public Date getTimestamp() { 18 | return timestamp; 19 | } 20 | 21 | public String getMessage() { 22 | return message; 23 | } 24 | 25 | public String getDetails() { 26 | return details; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/filtering/FilteringController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.filtering; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.springframework.http.converter.json.MappingJacksonValue; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | import com.fasterxml.jackson.databind.ser.FilterProvider; 11 | import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; 12 | import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; 13 | 14 | @RestController 15 | public class FilteringController { 16 | 17 | // field1,field2 18 | @GetMapping("/filtering") 19 | public MappingJacksonValue retrieveSomeBean() { 20 | SomeBean someBean = new SomeBean("value1", "value2", "value3"); 21 | 22 | SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("field1", "field2"); 23 | 24 | FilterProvider filters = new SimpleFilterProvider().addFilter("SomeBeanFilter", filter); 25 | 26 | MappingJacksonValue mapping = new MappingJacksonValue(someBean); 27 | 28 | mapping.setFilters(filters); 29 | 30 | return mapping; 31 | } 32 | 33 | // field2, field3 34 | @GetMapping("/filtering-list") 35 | public MappingJacksonValue retrieveListOfSomeBeans() { 36 | List list = Arrays.asList(new SomeBean("value1", "value2", "value3"), 37 | new SomeBean("value12", "value22", "value32")); 38 | 39 | SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("field2", "field3"); 40 | 41 | FilterProvider filters = new SimpleFilterProvider().addFilter("SomeBeanFilter", filter); 42 | 43 | MappingJacksonValue mapping = new MappingJacksonValue(list); 44 | 45 | mapping.setFilters(filters); 46 | 47 | return mapping; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/filtering/SomeBean.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.filtering; 2 | 3 | import com.fasterxml.jackson.annotation.JsonFilter; 4 | 5 | @JsonFilter("SomeBeanFilter") 6 | public class SomeBean { 7 | 8 | private String field1; 9 | 10 | private String field2; 11 | 12 | private String field3; 13 | 14 | public SomeBean(String field1, String field2, String field3) { 15 | super(); 16 | this.field1 = field1; 17 | this.field2 = field2; 18 | this.field3 = field3; 19 | } 20 | 21 | public String getField1() { 22 | return field1; 23 | } 24 | 25 | public void setField1(String field1) { 26 | this.field1 = field1; 27 | } 28 | 29 | public String getField2() { 30 | return field2; 31 | } 32 | 33 | public void setField2(String field2) { 34 | this.field2 = field2; 35 | } 36 | 37 | public String getField3() { 38 | return field3; 39 | } 40 | 41 | public void setField3(String field3) { 42 | this.field3 = field3; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/helloworld/HelloWorldBean.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.helloworld; 2 | 3 | public class HelloWorldBean { 4 | 5 | private String message; 6 | 7 | public HelloWorldBean(String message) { 8 | this.message = message; 9 | } 10 | 11 | public String getMessage() { 12 | return message; 13 | } 14 | 15 | public void setMessage(String message) { 16 | this.message = message; 17 | } 18 | 19 | @Override 20 | public String toString() { 21 | return String.format("HelloWorldBean [message=%s]", message); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/helloworld/HelloWorldController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.helloworld; 2 | 3 | import java.util.Locale; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.MessageSource; 7 | import org.springframework.context.i18n.LocaleContextHolder; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestHeader; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | //Controller 14 | @RestController 15 | public class HelloWorldController { 16 | 17 | @Autowired 18 | private MessageSource messageSource; 19 | 20 | @GetMapping(path = "/hello-world") 21 | public String helloWorld() { 22 | return "Hello World"; 23 | } 24 | 25 | @GetMapping(path = "/hello-world-bean") 26 | public HelloWorldBean helloWorldBean() { 27 | return new HelloWorldBean("Hello World"); 28 | } 29 | 30 | ///hello-world/path-variable/in28minutes 31 | @GetMapping(path = "/hello-world/path-variable/{name}") 32 | public HelloWorldBean helloWorldPathVariable(@PathVariable String name) { 33 | return new HelloWorldBean(String.format("Hello World, %s", name)); 34 | } 35 | 36 | @GetMapping(path = "/hello-world-internationalized") 37 | public String helloWorldInternationalized() { 38 | return messageSource.getMessage("good.morning.message", null, 39 | LocaleContextHolder.getLocale()); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/Post.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.user; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.FetchType; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import javax.persistence.ManyToOne; 8 | 9 | import com.fasterxml.jackson.annotation.JsonIgnore; 10 | 11 | @Entity 12 | public class Post { 13 | 14 | @Id 15 | @GeneratedValue 16 | private Integer id; 17 | private String description; 18 | 19 | @ManyToOne(fetch=FetchType.LAZY) 20 | @JsonIgnore 21 | private User user; 22 | 23 | public Integer getId() { 24 | return id; 25 | } 26 | 27 | public void setId(Integer id) { 28 | this.id = id; 29 | } 30 | 31 | public String getDescription() { 32 | return description; 33 | } 34 | 35 | public void setDescription(String description) { 36 | this.description = description; 37 | } 38 | 39 | public User getUser() { 40 | return user; 41 | } 42 | 43 | public void setUser(User user) { 44 | this.user = user; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return String.format("Post [id=%s, description=%s]", id, description); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/PostRepository.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.user; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | @Repository 7 | public interface PostRepository extends JpaRepository{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/User.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.user; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.Id; 9 | import javax.persistence.OneToMany; 10 | import javax.validation.constraints.Past; 11 | import javax.validation.constraints.Size; 12 | 13 | //@ApiModel(description="All details about the user.") 14 | @Entity 15 | public class User { 16 | 17 | @Id 18 | @GeneratedValue 19 | private Integer id; 20 | 21 | @Size(min=2, message="Name should have atleast 2 characters") 22 | //@ApiModelProperty(notes="Name should have atleast 2 characters") 23 | private String name; 24 | 25 | @Past 26 | //@ApiModelProperty(notes="Birth date should be in the past") 27 | private Date birthDate; 28 | 29 | @OneToMany(mappedBy="user") 30 | private List posts; 31 | 32 | protected User() { 33 | 34 | } 35 | 36 | public User(Integer id, String name, Date birthDate) { 37 | super(); 38 | this.id = id; 39 | this.name = name; 40 | this.birthDate = birthDate; 41 | } 42 | 43 | public Integer getId() { 44 | return id; 45 | } 46 | 47 | public void setId(Integer id) { 48 | this.id = id; 49 | } 50 | 51 | public String getName() { 52 | return name; 53 | } 54 | 55 | public void setName(String name) { 56 | this.name = name; 57 | } 58 | 59 | public Date getBirthDate() { 60 | return birthDate; 61 | } 62 | 63 | public void setBirthDate(Date birthDate) { 64 | this.birthDate = birthDate; 65 | } 66 | 67 | public List getPosts() { 68 | return posts; 69 | } 70 | 71 | public void setPosts(List posts) { 72 | this.posts = posts; 73 | } 74 | 75 | @Override 76 | public String toString() { 77 | return String.format("User [id=%s, name=%s, birthDate=%s]", id, name, birthDate); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/UserDaoService.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.user; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class UserDaoService { 12 | 13 | private static List users = new ArrayList<>(); 14 | 15 | private static int usersCount = 3; 16 | 17 | static { 18 | users.add(new User(1, "Adam", new Date())); 19 | users.add(new User(2, "Eve", new Date())); 20 | users.add(new User(3, "Jack", new Date())); 21 | } 22 | 23 | public List findAll() { 24 | return users; 25 | } 26 | 27 | public User save(User user) { 28 | if (user.getId() == null) { 29 | user.setId(++usersCount); 30 | } 31 | users.add(user); 32 | return user; 33 | } 34 | 35 | public User findOne(int id) { 36 | for (User user : users) { 37 | if (user.getId() == id) { 38 | return user; 39 | } 40 | } 41 | return null; 42 | } 43 | 44 | public User deleteById(int id) { 45 | Iterator iterator = users.iterator(); 46 | while (iterator.hasNext()) { 47 | User user = iterator.next(); 48 | if (user.getId() == id) { 49 | iterator.remove(); 50 | return user; 51 | } 52 | } 53 | return null; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/UserJPAResource.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.user; 2 | 3 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; 4 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; 5 | 6 | import java.net.URI; 7 | import java.util.List; 8 | import java.util.Optional; 9 | 10 | import javax.validation.Valid; 11 | 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.hateoas.EntityModel; 14 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 15 | import org.springframework.http.ResponseEntity; 16 | import org.springframework.web.bind.annotation.DeleteMapping; 17 | import org.springframework.web.bind.annotation.GetMapping; 18 | import org.springframework.web.bind.annotation.PathVariable; 19 | import org.springframework.web.bind.annotation.PostMapping; 20 | import org.springframework.web.bind.annotation.RequestBody; 21 | import org.springframework.web.bind.annotation.RestController; 22 | import org.springframework.web.servlet.support.ServletUriComponentsBuilder; 23 | 24 | @RestController 25 | public class UserJPAResource { 26 | 27 | @Autowired 28 | private UserRepository userRepository; 29 | 30 | @Autowired 31 | private PostRepository postRepository; 32 | 33 | @GetMapping("/jpa/users") 34 | public List retrieveAllUsers() { 35 | return userRepository.findAll(); 36 | } 37 | 38 | @GetMapping("/jpa/users/{id}") 39 | public EntityModel retrieveUser(@PathVariable int id) { 40 | Optional user = userRepository.findById(id); 41 | 42 | if (!user.isPresent()) 43 | throw new UserNotFoundException("id-" + id); 44 | 45 | // "all-users", SERVER_PATH + "/users" 46 | // retrieveAllUsers 47 | EntityModel resource = EntityModel.of(user.get());//new EntityModel(user.get()); 48 | 49 | WebMvcLinkBuilder linkTo = linkTo(methodOn(this.getClass()).retrieveAllUsers()); 50 | 51 | resource.add(linkTo.withRel("all-users")); 52 | 53 | // HATEOAS 54 | 55 | return resource; 56 | } 57 | 58 | @DeleteMapping("/jpa/users/{id}") 59 | public void deleteUser(@PathVariable int id) { 60 | userRepository.deleteById(id); 61 | } 62 | 63 | // 64 | // input - details of user 65 | // output - CREATED & Return the created URI 66 | 67 | // HATEOAS 68 | 69 | @PostMapping("/jpa/users") 70 | public ResponseEntity createUser(@Valid @RequestBody User user) { 71 | User savedUser = userRepository.save(user); 72 | 73 | URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(savedUser.getId()) 74 | .toUri(); 75 | 76 | return ResponseEntity.created(location).build(); 77 | 78 | } 79 | 80 | @GetMapping("/jpa/users/{id}/posts") 81 | public List retrieveAllUsers(@PathVariable int id) { 82 | Optional userOptional = userRepository.findById(id); 83 | 84 | if(!userOptional.isPresent()) { 85 | throw new UserNotFoundException("id-" + id); 86 | } 87 | 88 | return userOptional.get().getPosts(); 89 | } 90 | 91 | 92 | @PostMapping("/jpa/users/{id}/posts") 93 | public ResponseEntity createPost(@PathVariable int id, @RequestBody Post post) { 94 | 95 | Optional userOptional = userRepository.findById(id); 96 | 97 | if(!userOptional.isPresent()) { 98 | throw new UserNotFoundException("id-" + id); 99 | } 100 | 101 | User user = userOptional.get(); 102 | 103 | post.setUser(user); 104 | 105 | postRepository.save(post); 106 | 107 | URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(post.getId()) 108 | .toUri(); 109 | 110 | return ResponseEntity.created(location).build(); 111 | 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/UserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.user; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.bind.annotation.ResponseStatus; 5 | 6 | @ResponseStatus(HttpStatus.NOT_FOUND) 7 | public class UserNotFoundException extends RuntimeException { 8 | public UserNotFoundException(String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.user; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | @Repository 7 | public interface UserRepository extends JpaRepository{ 8 | 9 | } 10 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/user/UserResource.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.user; 2 | 3 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; 4 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; 5 | 6 | import java.net.URI; 7 | import java.util.List; 8 | 9 | import javax.validation.Valid; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.hateoas.EntityModel; 13 | import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.web.bind.annotation.DeleteMapping; 16 | import org.springframework.web.bind.annotation.GetMapping; 17 | import org.springframework.web.bind.annotation.PathVariable; 18 | import org.springframework.web.bind.annotation.PostMapping; 19 | import org.springframework.web.bind.annotation.RequestBody; 20 | import org.springframework.web.bind.annotation.RestController; 21 | import org.springframework.web.servlet.support.ServletUriComponentsBuilder; 22 | 23 | @RestController 24 | public class UserResource { 25 | 26 | @Autowired 27 | private UserDaoService service; 28 | 29 | @GetMapping("/users") 30 | public List retrieveAllUsers() { 31 | return service.findAll(); 32 | } 33 | 34 | @GetMapping("/users/{id}") 35 | public EntityModel retrieveUser(@PathVariable int id) { 36 | User user = service.findOne(id); 37 | 38 | if(user==null) 39 | throw new UserNotFoundException("id-"+ id); 40 | 41 | 42 | //"all-users", SERVER_PATH + "/users" 43 | //retrieveAllUsers 44 | EntityModel resource = EntityModel.of(user); 45 | 46 | WebMvcLinkBuilder linkTo = 47 | linkTo(methodOn(this.getClass()).retrieveAllUsers()); 48 | 49 | resource.add(linkTo.withRel("all-users")); 50 | 51 | //HATEOAS 52 | 53 | return resource; 54 | } 55 | 56 | @DeleteMapping("/users/{id}") 57 | public void deleteUser(@PathVariable int id) { 58 | User user = service.deleteById(id); 59 | 60 | if(user==null) 61 | throw new UserNotFoundException("id-"+ id); 62 | } 63 | 64 | // 65 | // input - details of user 66 | // output - CREATED & Return the created URI 67 | 68 | //HATEOAS 69 | 70 | @PostMapping("/users") 71 | public ResponseEntity createUser(@Valid @RequestBody User user) { 72 | User savedUser = service.save(user); 73 | // CREATED 74 | // /user/{id} savedUser.getId() 75 | 76 | URI location = ServletUriComponentsBuilder 77 | .fromCurrentRequest() 78 | .path("/{id}") 79 | .buildAndExpand(savedUser.getId()).toUri(); 80 | 81 | return ResponseEntity.created(location).build(); 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/versioning/Name.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.versioning; 2 | 3 | public class Name { 4 | private String firstName; 5 | private String lastName; 6 | 7 | public Name() { 8 | } 9 | 10 | public Name(String firstName, String lastName) { 11 | super(); 12 | this.firstName = firstName; 13 | this.lastName = lastName; 14 | } 15 | 16 | public String getFirstName() { 17 | return firstName; 18 | } 19 | 20 | public void setFirstName(String firstName) { 21 | this.firstName = firstName; 22 | } 23 | 24 | public String getLastName() { 25 | return lastName; 26 | } 27 | 28 | public void setLastName(String lastName) { 29 | this.lastName = lastName; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/versioning/PersonV1.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.versioning; 2 | 3 | public class PersonV1 { 4 | private String name; 5 | 6 | public PersonV1() { 7 | super(); 8 | } 9 | 10 | public PersonV1(String name) { 11 | super(); 12 | this.name = name; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/versioning/PersonV2.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.versioning; 2 | 3 | public class PersonV2 { 4 | private Name name; 5 | 6 | public PersonV2() { 7 | super(); 8 | } 9 | 10 | public PersonV2(Name name) { 11 | super(); 12 | this.name = name; 13 | } 14 | 15 | public Name getName() { 16 | return name; 17 | } 18 | 19 | public void setName(Name name) { 20 | this.name = name; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/java/com/in28minutes/rest/webservices/restfulwebservices/versioning/PersonVersioningController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices.versioning; 2 | 3 | import org.springframework.web.bind.annotation.GetMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | //@RestController 7 | public class PersonVersioningController { 8 | 9 | @GetMapping("v1/person") 10 | public PersonV1 personV1() { 11 | return new PersonV1("Bob Charlie"); 12 | } 13 | 14 | @GetMapping("v2/person") 15 | public PersonV2 personV2() { 16 | return new PersonV2(new Name("Bob", "Charlie")); 17 | } 18 | 19 | @GetMapping(value = "/person/param", params = "version=1") 20 | public PersonV1 paramV1() { 21 | return new PersonV1("Bob Charlie"); 22 | } 23 | 24 | @GetMapping(value = "/person/param", params = "version=2") 25 | public PersonV2 paramV2() { 26 | return new PersonV2(new Name("Bob", "Charlie")); 27 | } 28 | 29 | @GetMapping(value = "/person/header", headers = "X-API-VERSION=1") 30 | public PersonV1 headerV1() { 31 | return new PersonV1("Bob Charlie"); 32 | } 33 | 34 | @GetMapping(value = "/person/header", headers = "X-API-VERSION=2") 35 | public PersonV2 headerV2() { 36 | return new PersonV2(new Name("Bob", "Charlie")); 37 | } 38 | 39 | @GetMapping(value = "/person/produces", produces = "application/vnd.company.app-v1+json") 40 | public PersonV1 producesV1() { 41 | return new PersonV1("Bob Charlie"); 42 | } 43 | 44 | @GetMapping(value = "/person/produces", produces = "application/vnd.company.app-v2+json") 45 | public PersonV2 producesV2() { 46 | return new PersonV2(new Name("Bob", "Charlie")); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /02.restful-web-services/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.springframework = info 2 | #This is not really needed as this is the default after 2.0.0.RELEASE 3 | spring.jackson.serialization.write-dates-as-timestamps=false 4 | spring.messages.basename=messages 5 | management.endpoints.web.exposure.include=* 6 | spring.security.user.name=username 7 | spring.security.user.password=password 8 | spring.jpa.show-sql=true 9 | spring.h2.console.enabled=true 10 | spring.datasource.url=jdbc:h2:mem:testdb 11 | #spring.data.jpa.repositories.bootstrap-mode=default 12 | spring.jpa.defer-datasource-initialization=true -------------------------------------------------------------------------------- /02.restful-web-services/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into user values(10001, sysdate(), 'AB'); 2 | insert into user values(10002, sysdate(), 'Jill'); 3 | insert into user values(10003, sysdate(), 'Jam'); 4 | insert into post values(11001, 'My First Post', 10001); 5 | insert into post values(11002, 'My Second Post', 10001); -------------------------------------------------------------------------------- /02.restful-web-services/src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | good.morning.message=Good Morning -------------------------------------------------------------------------------- /02.restful-web-services/src/main/resources/messages_fr.properties: -------------------------------------------------------------------------------- 1 | good.morning.message=Bonjour -------------------------------------------------------------------------------- /02.restful-web-services/src/main/resources/messages_nl.properties: -------------------------------------------------------------------------------- 1 | good.morning.message=Goede Morgen -------------------------------------------------------------------------------- /02.restful-web-services/src/test/java/com/in28minutes/rest/webservices/restfulwebservices/RestfulWebServicesApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.rest.webservices.restfulwebservices; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class RestfulWebServicesApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /03.microservices/2.3.1.RELEASE-upgrade.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/2.3.1.RELEASE-upgrade.zip -------------------------------------------------------------------------------- /03.microservices/currency-conversion-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.in28minutes.microservices 7 | currency-conversion-service 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | currency-conversion-service 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.3.1.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Hoxton.SR5 26 | 3.1.1 27 | 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-config 33 | 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-openfeign 38 | 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-starter-sleuth 43 | 44 | 45 | 46 | org.springframework.cloud 47 | spring-cloud-sleuth-zipkin 48 | 49 | 50 | 51 | org.springframework.cloud 52 | spring-cloud-starter-bus-amqp 53 | 54 | 55 | 56 | org.springframework.cloud 57 | spring-cloud-starter-netflix-eureka-client 58 | 59 | 60 | com.fasterxml.jackson.dataformat 61 | jackson-dataformat-xml 62 | 63 | 64 | 65 | 66 | 67 | org.springframework.cloud 68 | spring-cloud-starter-netflix-ribbon 69 | 70 | 71 | 72 | org.springframework.boot 73 | spring-boot-starter-web 74 | 75 | 76 | 77 | org.springframework.boot 78 | spring-boot-starter-test 79 | test 80 | 81 | 82 | 83 | 84 | 85 | 86 | org.springframework.cloud 87 | spring-cloud-dependencies 88 | ${spring-cloud.version} 89 | pom 90 | import 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | org.springframework.boot 99 | spring-boot-maven-plugin 100 | 101 | 102 | 103 | 104 | 105 | 106 | spring-snapshots 107 | Spring Snapshots 108 | https://repo.spring.io/snapshot 109 | 110 | true 111 | 112 | 113 | 114 | spring-milestones 115 | Spring Milestones 116 | https://repo.spring.io/milestone 117 | 118 | false 119 | 120 | 121 | 122 | 123 | 124 | 125 | spring-snapshots 126 | Spring Snapshots 127 | https://repo.spring.io/snapshot 128 | 129 | true 130 | 131 | 132 | 133 | spring-milestones 134 | Spring Milestones 135 | https://repo.spring.io/milestone 136 | 137 | false 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionBean.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class CurrencyConversionBean { 6 | private Long id; 7 | private String from; 8 | private String to; 9 | private BigDecimal conversionMultiple; 10 | private BigDecimal quantity; 11 | private BigDecimal totalCalculatedAmount; 12 | private int port; 13 | 14 | public CurrencyConversionBean() { 15 | 16 | } 17 | 18 | public CurrencyConversionBean(Long id, String from, String to, BigDecimal conversionMultiple, BigDecimal quantity, 19 | BigDecimal totalCalculatedAmount, int port) { 20 | super(); 21 | this.id = id; 22 | this.from = from; 23 | this.to = to; 24 | this.conversionMultiple = conversionMultiple; 25 | this.quantity = quantity; 26 | this.totalCalculatedAmount = totalCalculatedAmount; 27 | this.port = port; 28 | } 29 | 30 | public Long getId() { 31 | return id; 32 | } 33 | 34 | public void setId(Long id) { 35 | this.id = id; 36 | } 37 | 38 | public String getFrom() { 39 | return from; 40 | } 41 | 42 | public void setFrom(String from) { 43 | this.from = from; 44 | } 45 | 46 | public String getTo() { 47 | return to; 48 | } 49 | 50 | public void setTo(String to) { 51 | this.to = to; 52 | } 53 | 54 | public BigDecimal getConversionMultiple() { 55 | return conversionMultiple; 56 | } 57 | 58 | public void setConversionMultiple(BigDecimal conversionMultiple) { 59 | this.conversionMultiple = conversionMultiple; 60 | } 61 | 62 | public BigDecimal getQuantity() { 63 | return quantity; 64 | } 65 | 66 | public void setQuantity(BigDecimal quantity) { 67 | this.quantity = quantity; 68 | } 69 | 70 | public BigDecimal getTotalCalculatedAmount() { 71 | return totalCalculatedAmount; 72 | } 73 | 74 | public void setTotalCalculatedAmount(BigDecimal totalCalculatedAmount) { 75 | this.totalCalculatedAmount = totalCalculatedAmount; 76 | } 77 | 78 | public int getPort() { 79 | return port; 80 | } 81 | 82 | public void setPort(int port) { 83 | this.port = port; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.http.ResponseEntity; 11 | import org.springframework.web.bind.annotation.GetMapping; 12 | import org.springframework.web.bind.annotation.PathVariable; 13 | import org.springframework.web.bind.annotation.RestController; 14 | import org.springframework.web.client.RestTemplate; 15 | 16 | @RestController 17 | public class CurrencyConversionController { 18 | 19 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 20 | 21 | @Autowired 22 | private CurrencyExchangeServiceProxy proxy; 23 | 24 | @GetMapping("/currency-converter/from/{from}/to/{to}/quantity/{quantity}") 25 | public CurrencyConversionBean convertCurrency(@PathVariable String from, @PathVariable String to, 26 | @PathVariable BigDecimal quantity) { 27 | 28 | // Feign - Problem 1 29 | Map uriVariables = new HashMap<>(); 30 | uriVariables.put("from", from); 31 | uriVariables.put("to", to); 32 | 33 | ResponseEntity responseEntity = new RestTemplate().getForEntity( 34 | "http://localhost:8000/currency-exchange/from/{from}/to/{to}", CurrencyConversionBean.class, 35 | uriVariables); 36 | 37 | CurrencyConversionBean response = responseEntity.getBody(); 38 | 39 | return new CurrencyConversionBean(response.getId(), from, to, response.getConversionMultiple(), quantity, 40 | quantity.multiply(response.getConversionMultiple()), response.getPort()); 41 | } 42 | 43 | @GetMapping("/currency-converter-feign/from/{from}/to/{to}/quantity/{quantity}") 44 | public CurrencyConversionBean convertCurrencyFeign(@PathVariable String from, @PathVariable String to, 45 | @PathVariable BigDecimal quantity) { 46 | 47 | CurrencyConversionBean response = proxy.retrieveExchangeValue(from, to); 48 | 49 | logger.info("{}", response); 50 | 51 | return new CurrencyConversionBean(response.getId(), from, to, response.getConversionMultiple(), quantity, 52 | quantity.multiply(response.getConversionMultiple()), response.getPort()); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | import org.springframework.cloud.openfeign.EnableFeignClients; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | import brave.sampler.Sampler; 10 | 11 | @SpringBootApplication 12 | @EnableFeignClients("com.in28minutes.microservices.currencyconversionservice") 13 | @EnableDiscoveryClient 14 | public class CurrencyConversionServiceApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(CurrencyConversionServiceApplication.class, args); 18 | } 19 | 20 | @Bean 21 | public Sampler defaultSampler() { 22 | return Sampler.ALWAYS_SAMPLE; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyExchangeServiceProxy.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import org.springframework.cloud.openfeign.FeignClient; 4 | import org.springframework.cloud.netflix.ribbon.RibbonClient; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | 8 | //@FeignClient(name="currency-exchange-service", url="localhost:8000") 9 | //@FeignClient(name="currency-exchange-service") 10 | @FeignClient(name="netflix-zuul-api-gateway-server") 11 | @RibbonClient(name="currency-exchange-service") 12 | public interface CurrencyExchangeServiceProxy { 13 | //@GetMapping("/currency-exchange/from/{from}/to/{to}") 14 | @GetMapping("/currency-exchange-service/currency-exchange/from/{from}/to/{to}") 15 | public CurrencyConversionBean retrieveExchangeValue 16 | (@PathVariable("from") String from, @PathVariable("to") String to); 17 | } 18 | -------------------------------------------------------------------------------- /03.microservices/currency-conversion-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=currency-conversion-service 2 | server.port=8100 3 | eureka.client.service-url.default-zone=http://localhost:8761/eureka 4 | #currency-exchange-service.ribbon.listOfServers=http://localhost:8000,http://localhost:8001 -------------------------------------------------------------------------------- /03.microservices/currency-conversion-service/src/test/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyconversionservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CurrencyConversionServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /03.microservices/currency-exchange-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.in28minutes.microservices 7 | currency-exchange-service 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | currency-exchange-service 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.3.1.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Hoxton.SR5 26 | 3.1.1 27 | 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-config 33 | 34 | 35 | org.springframework.cloud 36 | spring-cloud-starter-netflix-eureka-client 37 | 38 | 39 | com.fasterxml.jackson.dataformat 40 | jackson-dataformat-xml 41 | 42 | 43 | 44 | 45 | org.springframework.cloud 46 | spring-cloud-starter-sleuth 47 | 48 | 49 | org.springframework.cloud 50 | spring-cloud-sleuth-zipkin 51 | 52 | 53 | 54 | org.springframework.cloud 55 | spring-cloud-starter-bus-amqp 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-web 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-data-jpa 65 | 66 | 67 | com.h2database 68 | h2 69 | 70 | 71 | 72 | 73 | org.springframework.boot 74 | spring-boot-starter-test 75 | test 76 | 77 | 78 | 79 | 80 | 81 | 82 | org.springframework.cloud 83 | spring-cloud-dependencies 84 | ${spring-cloud.version} 85 | pom 86 | import 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | org.springframework.boot 95 | spring-boot-maven-plugin 96 | 97 | 98 | 99 | 100 | 101 | 102 | spring-snapshots 103 | Spring Snapshots 104 | https://repo.spring.io/snapshot 105 | 106 | true 107 | 108 | 109 | 110 | spring-milestones 111 | Spring Milestones 112 | https://repo.spring.io/milestone 113 | 114 | false 115 | 116 | 117 | 118 | 119 | 120 | 121 | spring-snapshots 122 | Spring Snapshots 123 | https://repo.spring.io/snapshot 124 | 125 | true 126 | 127 | 128 | 129 | spring-milestones 130 | Spring Milestones 131 | https://repo.spring.io/milestone 132 | 133 | false 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /03.microservices/currency-exchange-service/src/main/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.core.env.Environment; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RestController 12 | public class CurrencyExchangeController { 13 | 14 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 15 | 16 | @Autowired 17 | private Environment environment; 18 | 19 | @Autowired 20 | private ExchangeValueRepository repository; 21 | 22 | @GetMapping("/currency-exchange/from/{from}/to/{to}") 23 | public ExchangeValue retrieveExchangeValue 24 | (@PathVariable String from, @PathVariable String to){ 25 | 26 | ExchangeValue exchangeValue = 27 | repository.findByFromAndTo(from, to); 28 | 29 | exchangeValue.setPort( 30 | Integer.parseInt(environment.getProperty("local.server.port"))); 31 | 32 | logger.info("{}", exchangeValue); 33 | 34 | return exchangeValue; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /03.microservices/currency-exchange-service/src/main/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | import org.springframework.context.annotation.Bean; 7 | 8 | import brave.sampler.Sampler; 9 | 10 | @SpringBootApplication 11 | @EnableDiscoveryClient 12 | public class CurrencyExchangeServiceApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(CurrencyExchangeServiceApplication.class, args); 16 | } 17 | 18 | @Bean 19 | public Sampler defaultSampler(){ 20 | return Sampler.ALWAYS_SAMPLE; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /03.microservices/currency-exchange-service/src/main/java/com/in28minutes/microservices/currencyexchangeservice/ExchangeValue.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.Id; 8 | 9 | @Entity 10 | public class ExchangeValue { 11 | 12 | @Id 13 | private Long id; 14 | 15 | @Column(name="currency_from") 16 | private String from; 17 | 18 | @Column(name="currency_to") 19 | private String to; 20 | 21 | private BigDecimal conversionMultiple; 22 | private int port; 23 | 24 | public ExchangeValue() { 25 | 26 | } 27 | 28 | 29 | public ExchangeValue(Long id, String from, String to, BigDecimal conversionMultiple) { 30 | super(); 31 | this.id = id; 32 | this.from = from; 33 | this.to = to; 34 | this.conversionMultiple = conversionMultiple; 35 | } 36 | 37 | public Long getId() { 38 | return id; 39 | } 40 | 41 | public String getFrom() { 42 | return from; 43 | } 44 | 45 | public String getTo() { 46 | return to; 47 | } 48 | 49 | public BigDecimal getConversionMultiple() { 50 | return conversionMultiple; 51 | } 52 | 53 | public int getPort() { 54 | return port; 55 | } 56 | 57 | public void setPort(int port) { 58 | this.port = port; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /03.microservices/currency-exchange-service/src/main/java/com/in28minutes/microservices/currencyexchangeservice/ExchangeValueRepository.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface ExchangeValueRepository extends 6 | JpaRepository{ 7 | ExchangeValue findByFromAndTo(String from, String to); 8 | } 9 | -------------------------------------------------------------------------------- /03.microservices/currency-exchange-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=currency-exchange-service 2 | server.port=8000 3 | 4 | spring.jpa.show-sql=true 5 | spring.h2.console.enabled=true 6 | 7 | eureka.client.service-url.default-zone=http://localhost:8761/eureka -------------------------------------------------------------------------------- /03.microservices/currency-exchange-service/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple,port) 2 | values(10001,'USD','INR',65,0); 3 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple,port) 4 | values(10002,'EUR','INR',75,0); 5 | insert into exchange_value(id,currency_from,currency_to,conversion_multiple,port) 6 | values(10003,'AUD','INR',25,0); -------------------------------------------------------------------------------- /03.microservices/currency-exchange-service/src/test/java/com/in28minutes/microservices/currencyexchangeservice/CurrencyExchangeServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.currencyexchangeservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class CurrencyExchangeServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /03.microservices/limits-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.in28minutes.microservices 7 | limits-service 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | limits-service 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.3.1.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Hoxton.SR5 26 | 3.1.1 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-config 34 | 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-starter-netflix-hystrix 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-starter-bus-amqp 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-web 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-actuator 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-test 57 | test 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.cloud 65 | spring-cloud-dependencies 66 | ${spring-cloud.version} 67 | pom 68 | import 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-maven-plugin 78 | 79 | 80 | 81 | 82 | 83 | 84 | spring-snapshots 85 | Spring Snapshots 86 | https://repo.spring.io/snapshot 87 | 88 | true 89 | 90 | 91 | 92 | spring-milestones 93 | Spring Milestones 94 | https://repo.spring.io/milestone 95 | 96 | false 97 | 98 | 99 | 100 | 101 | 102 | 103 | spring-snapshots 104 | Spring Snapshots 105 | https://repo.spring.io/snapshot 106 | 107 | true 108 | 109 | 110 | 111 | spring-milestones 112 | Spring Milestones 113 | https://repo.spring.io/milestone 114 | 115 | false 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /03.microservices/limits-service/src/main/java/com/in28minutes/microservices/limitsservice/Configuration.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.limitsservice; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | @ConfigurationProperties("limits-service") 8 | public class Configuration { 9 | 10 | private int minimum; 11 | private int maximum; 12 | 13 | public void setMinimum(int minimum) { 14 | this.minimum = minimum; 15 | } 16 | 17 | public void setMaximum(int maximum) { 18 | this.maximum = maximum; 19 | } 20 | 21 | public int getMinimum() { 22 | return minimum; 23 | } 24 | 25 | public int getMaximum() { 26 | return maximum; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03.microservices/limits-service/src/main/java/com/in28minutes/microservices/limitsservice/LimitsConfigurationController.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.limitsservice; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | import com.in28minutes.microservices.limitsservice.bean.LimitConfiguration; 8 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 9 | 10 | @RestController 11 | public class LimitsConfigurationController { 12 | 13 | @Autowired 14 | private Configuration configuration; 15 | 16 | @GetMapping("/limits") 17 | public LimitConfiguration retrieveLimitsFromConfigurations() { 18 | LimitConfiguration limitConfiguration = new LimitConfiguration(configuration.getMaximum(), 19 | configuration.getMinimum()); 20 | return limitConfiguration; 21 | } 22 | 23 | @GetMapping("/fault-tolerance-example") 24 | @HystrixCommand(fallbackMethod="fallbackRetrieveConfiguration") 25 | public LimitConfiguration retrieveConfiguration() { 26 | throw new RuntimeException("Not available"); 27 | } 28 | 29 | public LimitConfiguration fallbackRetrieveConfiguration() { 30 | return new LimitConfiguration(999, 9); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /03.microservices/limits-service/src/main/java/com/in28minutes/microservices/limitsservice/LimitsServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.limitsservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.hystrix.EnableHystrix; 6 | 7 | @SpringBootApplication 8 | @EnableHystrix 9 | public class LimitsServiceApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(LimitsServiceApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /03.microservices/limits-service/src/main/java/com/in28minutes/microservices/limitsservice/bean/LimitConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.limitsservice.bean; 2 | 3 | public class LimitConfiguration { 4 | private int maximum; 5 | private int minimum; 6 | 7 | protected LimitConfiguration() { 8 | 9 | } 10 | 11 | public LimitConfiguration(int maximum, int minimum) { 12 | super(); 13 | this.maximum = maximum; 14 | this.minimum = minimum; 15 | } 16 | 17 | public int getMaximum() { 18 | return maximum; 19 | } 20 | 21 | public int getMinimum() { 22 | return minimum; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /03.microservices/limits-service/src/main/resources/bootstrap.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=limits-service 2 | spring.cloud.config.uri=http://localhost:8888 3 | spring.profiles.active=qa 4 | management.endpoints.web.exposure.include=* -------------------------------------------------------------------------------- /03.microservices/limits-service/src/test/java/com/in28minutes/microservices/limitsservice/LimitsServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.limitsservice; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class LimitsServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /03.microservices/netflix-eureka-naming-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.in28minutes.microservices 7 | netflix-eureka-naming-server 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | netflix-eureka-naming-server 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.3.1.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Hoxton.SR5 26 | 3.1.1 27 | 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-config 33 | 34 | 35 | org.springframework.cloud 36 | spring-cloud-starter-netflix-eureka-server 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.cloud 49 | spring-cloud-dependencies 50 | ${spring-cloud.version} 51 | pom 52 | import 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | 65 | 66 | 67 | 68 | spring-snapshots 69 | Spring Snapshots 70 | https://repo.spring.io/snapshot 71 | 72 | true 73 | 74 | 75 | 76 | spring-milestones 77 | Spring Milestones 78 | https://repo.spring.io/milestone 79 | 80 | false 81 | 82 | 83 | 84 | 85 | 86 | 87 | spring-snapshots 88 | Spring Snapshots 89 | https://repo.spring.io/snapshot 90 | 91 | true 92 | 93 | 94 | 95 | spring-milestones 96 | Spring Milestones 97 | https://repo.spring.io/milestone 98 | 99 | false 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /03.microservices/netflix-eureka-naming-server/src/main/java/com/in28minutes/microservices/netflixeurekanamingserver/NetflixEurekaNamingServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.netflixeurekanamingserver; 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 NetflixEurekaNamingServerApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(NetflixEurekaNamingServerApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /03.microservices/netflix-eureka-naming-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | spring.application.name=netflix-eureka-naming-server 3 | server.port=8761 4 | 5 | eureka.client.register-with-eureka=false 6 | eureka.client.fetch-registry=false -------------------------------------------------------------------------------- /03.microservices/netflix-eureka-naming-server/src/test/java/com/in28minutes/microservices/netflixeurekanamingserver/NetflixEurekaNamingServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.netflixeurekanamingserver; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class NetflixEurekaNamingServerApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /03.microservices/netflix-zuul-api-gateway-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.in28minutes.microservices 7 | netflix-zuul-api-gateway-server 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | netflix-zuul-api-gateway-server 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.3.1.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Hoxton.SR5 26 | 3.1.1 27 | 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-starter-netflix-eureka-client 33 | 34 | 35 | com.fasterxml.jackson.dataformat 36 | jackson-dataformat-xml 37 | 38 | 39 | 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-starter-netflix-zuul 44 | 45 | 46 | 47 | org.springframework.cloud 48 | spring-cloud-starter-sleuth 49 | 50 | 51 | 52 | org.springframework.cloud 53 | spring-cloud-sleuth-zipkin 54 | 55 | 56 | 57 | org.springframework.cloud 58 | spring-cloud-starter-bus-amqp 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-test 65 | test 66 | 67 | 68 | 69 | 70 | 71 | 72 | org.springframework.cloud 73 | spring-cloud-dependencies 74 | ${spring-cloud.version} 75 | pom 76 | import 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | org.springframework.boot 85 | spring-boot-maven-plugin 86 | 87 | 88 | 89 | 90 | 91 | 92 | spring-snapshots 93 | Spring Snapshots 94 | https://repo.spring.io/snapshot 95 | 96 | true 97 | 98 | 99 | 100 | spring-milestones 101 | Spring Milestones 102 | https://repo.spring.io/milestone 103 | 104 | false 105 | 106 | 107 | 108 | 109 | 110 | 111 | spring-snapshots 112 | Spring Snapshots 113 | https://repo.spring.io/snapshot 114 | 115 | true 116 | 117 | 118 | 119 | spring-milestones 120 | Spring Milestones 121 | https://repo.spring.io/milestone 122 | 123 | false 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /03.microservices/netflix-zuul-api-gateway-server/src/main/java/com/in28minutes/microservices/netflixzuulapigatewayserver/NetflixZuulApiGatewayServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.netflixzuulapigatewayserver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | import brave.sampler.Sampler; 10 | 11 | @EnableZuulProxy 12 | @EnableDiscoveryClient 13 | @SpringBootApplication 14 | public class NetflixZuulApiGatewayServerApplication { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(NetflixZuulApiGatewayServerApplication.class, args); 18 | } 19 | 20 | @Bean 21 | public Sampler defaultSampler(){ 22 | return Sampler.ALWAYS_SAMPLE; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /03.microservices/netflix-zuul-api-gateway-server/src/main/java/com/in28minutes/microservices/netflixzuulapigatewayserver/ZuulLoggingFilter.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.netflixzuulapigatewayserver; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.stereotype.Component; 8 | 9 | import com.netflix.zuul.ZuulFilter; 10 | import com.netflix.zuul.context.RequestContext; 11 | 12 | @Component 13 | public class ZuulLoggingFilter extends ZuulFilter{ 14 | 15 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 16 | 17 | @Override 18 | public boolean shouldFilter() { 19 | return true; 20 | } 21 | 22 | @Override 23 | public Object run() { 24 | HttpServletRequest request = 25 | RequestContext.getCurrentContext().getRequest(); 26 | logger.info("request -> {} request uri -> {}", 27 | request, request.getRequestURI()); 28 | return null; 29 | } 30 | 31 | @Override 32 | public String filterType() { 33 | return "pre"; 34 | } 35 | 36 | @Override 37 | public int filterOrder() { 38 | return 1; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /03.microservices/netflix-zuul-api-gateway-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=netflix-zuul-api-gateway-server 2 | server.port=8765 3 | eureka.client.service-url.default-zone=http://localhost:8761/eureka 4 | -------------------------------------------------------------------------------- /03.microservices/netflix-zuul-api-gateway-server/src/test/java/com/in28minutes/microservices/netflixzuulapigatewayserver/NetflixZuulApiGatewayServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.netflixzuulapigatewayserver; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class NetflixZuulApiGatewayServerApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /03.microservices/spring-cloud-config-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.in28minutes.microservices 7 | spring-cloud-config-server 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | spring-cloud-config-server 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.3.1.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Hoxton.SR5 26 | 3.1.1 27 | 28 | 29 | 30 | 31 | org.springframework.cloud 32 | spring-cloud-config-server 33 | 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-bus-amqp 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-test 43 | test 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-dependencies 52 | ${spring-cloud.version} 53 | pom 54 | import 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | 68 | 69 | 70 | spring-snapshots 71 | Spring Snapshots 72 | https://repo.spring.io/snapshot 73 | 74 | true 75 | 76 | 77 | 78 | spring-milestones 79 | Spring Milestones 80 | https://repo.spring.io/milestone 81 | 82 | false 83 | 84 | 85 | 86 | 87 | 88 | 89 | spring-snapshots 90 | Spring Snapshots 91 | https://repo.spring.io/snapshot 92 | 93 | true 94 | 95 | 96 | 97 | spring-milestones 98 | Spring Milestones 99 | https://repo.spring.io/milestone 100 | 101 | false 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /03.microservices/spring-cloud-config-server/src/main/java/com/in28minutes/microservices/springcloudconfigserver/SpringCloudConfigServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.springcloudconfigserver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | @EnableConfigServer 8 | @SpringBootApplication 9 | public class SpringCloudConfigServerApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(SpringCloudConfigServerApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /03.microservices/spring-cloud-config-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=spring-cloud-config-server 2 | server.port=8888 3 | spring.cloud.config.server.git.uri=file:///Ranga/git/01.udemy-course-repos/spring-micro-services/03.microservices/git-localconfig-repo -------------------------------------------------------------------------------- /03.microservices/spring-cloud-config-server/src/test/java/com/in28minutes/microservices/springcloudconfigserver/SpringCloudConfigServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.in28minutes.microservices.springcloudconfigserver; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class SpringCloudConfigServerApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /03.microservices/step01.md: -------------------------------------------------------------------------------- 1 | 2 | ## Complete Code Example 3 | 4 | 5 | ### /limits-service/pom.xml 6 | 7 | ```xml 8 | 9 | 11 | 4.0.0 12 | 13 | com.in28minutes.microservices 14 | limits-service 15 | 0.0.1-SNAPSHOT 16 | jar 17 | 18 | limits-service 19 | Demo project for Spring Boot 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-parent 24 | 2.0.0.RELEASE 25 | 26 | 27 | 28 | 29 | UTF-8 30 | UTF-8 31 | 1.8 32 | Finchley.M8 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-actuator 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-starter-config 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-web 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-devtools 52 | runtime 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-test 57 | test 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.cloud 65 | spring-cloud-dependencies 66 | ${spring-cloud.version} 67 | pom 68 | import 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-maven-plugin 78 | 79 | 80 | 81 | 82 | 83 | 84 | spring-snapshots 85 | Spring Snapshots 86 | https://repo.spring.io/snapshot 87 | 88 | true 89 | 90 | 91 | 92 | spring-milestones 93 | Spring Milestones 94 | https://repo.spring.io/milestone 95 | 96 | false 97 | 98 | 99 | 100 | 101 | 102 | 103 | spring-snapshots 104 | Spring Snapshots 105 | https://repo.spring.io/snapshot 106 | 107 | true 108 | 109 | 110 | 111 | spring-milestones 112 | Spring Milestones 113 | https://repo.spring.io/milestone 114 | 115 | false 116 | 117 | 118 | 119 | 120 | 121 | 122 | ``` 123 | --- 124 | 125 | ### /limits-service/src/main/java/com/in28minutes/microservices/limitsservice/LimitsServiceApplication.java 126 | 127 | ```java 128 | package com.in28minutes.microservices.limitsservice; 129 | 130 | import org.springframework.boot.SpringApplication; 131 | import org.springframework.boot.autoconfigure.SpringBootApplication; 132 | 133 | @SpringBootApplication 134 | public class LimitsServiceApplication { 135 | 136 | public static void main(String[] args) { 137 | SpringApplication.run(LimitsServiceApplication.class, args); 138 | } 139 | } 140 | ``` 141 | --- 142 | 143 | ### /limits-service/src/main/resources/application.properties 144 | 145 | ```properties 146 | ``` 147 | --- 148 | 149 | ### /limits-service/src/test/java/com/in28minutes/microservices/limitsservice/LimitsServiceApplicationTests.java 150 | 151 | ```java 152 | package com.in28minutes.microservices.limitsservice; 153 | 154 | import org.junit.Test; 155 | import org.junit.runner.RunWith; 156 | import org.springframework.boot.test.context.SpringBootTest; 157 | import org.springframework.test.context.junit4.SpringRunner; 158 | 159 | @RunWith(SpringRunner.class) 160 | @SpringBootTest 161 | public class LimitsServiceApplicationTests { 162 | 163 | @Test 164 | public void contextLoads() { 165 | } 166 | 167 | } 168 | ``` 169 | --- 170 | -------------------------------------------------------------------------------- /03.microservices/step01.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step01.zip -------------------------------------------------------------------------------- /03.microservices/step03.md: -------------------------------------------------------------------------------- 1 | 2 | ## Complete Code Example 3 | 4 | 5 | ### /limits-service/pom.xml 6 | 7 | ```xml 8 | 9 | 11 | 4.0.0 12 | 13 | com.in28minutes.microservices 14 | limits-service 15 | 0.0.1-SNAPSHOT 16 | jar 17 | 18 | limits-service 19 | Demo project for Spring Boot 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-parent 24 | 2.0.0.RELEASE 25 | 26 | 27 | 28 | 29 | UTF-8 30 | UTF-8 31 | 1.8 32 | Finchley.M8 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-actuator 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-starter-config 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-web 47 | 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-devtools 52 | runtime 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-test 57 | test 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.cloud 65 | spring-cloud-dependencies 66 | ${spring-cloud.version} 67 | pom 68 | import 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-maven-plugin 78 | 79 | 80 | 81 | 82 | 83 | 84 | spring-snapshots 85 | Spring Snapshots 86 | https://repo.spring.io/snapshot 87 | 88 | true 89 | 90 | 91 | 92 | spring-milestones 93 | Spring Milestones 94 | https://repo.spring.io/milestone 95 | 96 | false 97 | 98 | 99 | 100 | 101 | 102 | 103 | spring-snapshots 104 | Spring Snapshots 105 | https://repo.spring.io/snapshot 106 | 107 | true 108 | 109 | 110 | 111 | spring-milestones 112 | Spring Milestones 113 | https://repo.spring.io/milestone 114 | 115 | false 116 | 117 | 118 | 119 | 120 | 121 | 122 | ``` 123 | --- 124 | 125 | ### /limits-service/src/main/java/com/in28minutes/microservices/limitsservice/bean/LimitConfiguration.java 126 | 127 | ```java 128 | package com.in28minutes.microservices.limitsservice.bean; 129 | 130 | public class LimitConfiguration { 131 | private int maximum; 132 | private int minimum; 133 | 134 | protected LimitConfiguration() { 135 | 136 | } 137 | 138 | public LimitConfiguration(int maximum, int minimum) { 139 | super(); 140 | this.maximum = maximum; 141 | this.minimum = minimum; 142 | } 143 | 144 | public int getMaximum() { 145 | return maximum; 146 | } 147 | 148 | public int getMinimum() { 149 | return minimum; 150 | } 151 | 152 | } 153 | ``` 154 | --- 155 | 156 | ### /limits-service/src/main/java/com/in28minutes/microservices/limitsservice/Configuration.java 157 | 158 | ```java 159 | package com.in28minutes.microservices.limitsservice; 160 | 161 | import org.springframework.boot.context.properties.ConfigurationProperties; 162 | import org.springframework.stereotype.Component; 163 | 164 | @Component 165 | @ConfigurationProperties("limits-service") 166 | public class Configuration { 167 | 168 | private int minimum; 169 | private int maximum; 170 | 171 | public void setMinimum(int minimum) { 172 | this.minimum = minimum; 173 | } 174 | 175 | public void setMaximum(int maximum) { 176 | this.maximum = maximum; 177 | } 178 | 179 | public int getMinimum() { 180 | return minimum; 181 | } 182 | 183 | public int getMaximum() { 184 | return maximum; 185 | } 186 | 187 | } 188 | ``` 189 | --- 190 | 191 | ### /limits-service/src/main/java/com/in28minutes/microservices/limitsservice/LimitsConfigurationController.java 192 | 193 | ```java 194 | package com.in28minutes.microservices.limitsservice; 195 | 196 | import org.springframework.beans.factory.annotation.Autowired; 197 | import org.springframework.web.bind.annotation.GetMapping; 198 | import org.springframework.web.bind.annotation.RestController; 199 | 200 | import com.in28minutes.microservices.limitsservice.bean.LimitConfiguration; 201 | 202 | @RestController 203 | public class LimitsConfigurationController { 204 | 205 | @Autowired 206 | private Configuration configuration; 207 | 208 | @GetMapping("/limits") 209 | public LimitConfiguration retrieveLimitsFromConfigurations() { 210 | return new LimitConfiguration(configuration.getMaximum(), 211 | configuration.getMinimum()); 212 | } 213 | 214 | } 215 | ``` 216 | --- 217 | 218 | ### /limits-service/src/main/java/com/in28minutes/microservices/limitsservice/LimitsServiceApplication.java 219 | 220 | ```java 221 | package com.in28minutes.microservices.limitsservice; 222 | 223 | import org.springframework.boot.SpringApplication; 224 | import org.springframework.boot.autoconfigure.SpringBootApplication; 225 | 226 | @SpringBootApplication 227 | public class LimitsServiceApplication { 228 | public static void main(String[] args) { 229 | SpringApplication.run(LimitsServiceApplication.class, args); 230 | } 231 | } 232 | ``` 233 | --- 234 | 235 | ### /limits-service/src/main/resources/application.properties 236 | 237 | ```properties 238 | spring.application.name=limits-service 239 | 240 | limits-service.minimum=9 241 | limits-service.maximum=999 242 | ``` 243 | --- 244 | 245 | ### /limits-service/src/test/java/com/in28minutes/microservices/limitsservice/LimitsServiceApplicationTests.java 246 | 247 | ```java 248 | package com.in28minutes.microservices.limitsservice; 249 | 250 | import org.junit.Test; 251 | import org.junit.runner.RunWith; 252 | import org.springframework.boot.test.context.SpringBootTest; 253 | import org.springframework.test.context.junit4.SpringRunner; 254 | 255 | @RunWith(SpringRunner.class) 256 | @SpringBootTest 257 | public class LimitsServiceApplicationTests { 258 | 259 | @Test 260 | public void contextLoads() { 261 | } 262 | 263 | } 264 | ``` 265 | --- 266 | -------------------------------------------------------------------------------- /03.microservices/step03.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step03.zip -------------------------------------------------------------------------------- /03.microservices/step08.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step08.zip -------------------------------------------------------------------------------- /03.microservices/step09.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step09.zip -------------------------------------------------------------------------------- /03.microservices/step11.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step11.zip -------------------------------------------------------------------------------- /03.microservices/step17.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step17.zip -------------------------------------------------------------------------------- /03.microservices/step20.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step20.zip -------------------------------------------------------------------------------- /03.microservices/step23.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step23.zip -------------------------------------------------------------------------------- /03.microservices/step25.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step25.zip -------------------------------------------------------------------------------- /03.microservices/step29.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step29.zip -------------------------------------------------------------------------------- /03.microservices/step34.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step34.zip -------------------------------------------------------------------------------- /03.microservices/step41.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step41.zip -------------------------------------------------------------------------------- /03.microservices/step42.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step42.zip -------------------------------------------------------------------------------- /03.microservices/step43.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step43.zip -------------------------------------------------------------------------------- /03.microservices/step44.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/03.microservices/step44.zip -------------------------------------------------------------------------------- /2.5.0-upgrade-faq.md: -------------------------------------------------------------------------------- 1 | ## 2.5.0 Course Updates 2 | 3 | Really excited to announce amazing updates to the course! 4 | 5 | **Great News! We have made significant changes to the REST API section of the course!** 6 | 7 | 8 | ## FAQ 9 | 10 | #### What are the new changes? 11 | 12 | - Updated all code for 2.5.0 RELEASE of Spring Boot 13 | - Major Changes for REST API: 14 | - Rerecorded 10 lectures 15 | - Simplified Internationalization 16 | - Using spring-data-rest-hal-explorer instead of spring-data-rest-hal-browser 17 | - Using Spring Doc Open API instead of Spring Fox Swagger to generate Swagger Docs 18 | 19 | 20 | #### Can I get a link to complete code after the change for REST API? 21 | 22 | Here you go - https://github.com/in28minutes/spring-microservices/blob/master/02.restful-web-services/2.5.0-UPGRADE.md 23 | 24 | #### Where can I see the diff of changes? 25 | 26 | https://github.com/in28minutes/spring-microservices/commit/998e4e8e25a7f46cfce3d562f8c0312f340396fd -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spring MicroServices 2 | 3 | [![Image](https://www.springboottutorial.com/images/Course-Master-Microservices-with-Spring-Boot-and-Spring-Cloud.png "Master Microservices with Spring Boot and Spring Cloud")](https://www.udemy.com/course/microservices-with-spring-boot-and-spring-cloud/) 4 | 5 | Learn how to create awesome Microservices and RESTful web services with Spring and Spring Boot. 6 | 7 | ## Overview 8 | * [Installing Tools](#installing-tools) 9 | * [Running Examples](#running-examples) 10 | * [Course Overview](#course-overview) 11 | - [Course Steps](#step-list) 12 | - [Expectations](#expectations) 13 | * [About in28Minutes](#about-in28minutes) 14 | - [Our Beliefs](#our-beliefs) 15 | - [Our Approach](#our-approach) 16 | - [Find Us](#useful-links) 17 | - [Other Courses](#other-courses) 18 | 19 | ### Introduction 20 | 21 | Developing RESTful web services is fun. The combination of Spring Boot, Spring Web MVC, Spring Web Services and JPA makes it even more fun. And its even more fun to create Microservices. 22 | 23 | There are two parts to this course - RESTful web services and Microservices 24 | 25 | Architectures are moving towards microservices. 26 | 27 | RESTful web services are the first step to developing great microservices. Spring Boot, in combination with Spring Web MVC (also called Spring REST) makes it easy to develop RESTful web services. 28 | 29 | In the first part of the course, you will learn the basics of RESTful web services developing resources for a social media application. You will learn to implement these resources with multiple features - versioning, exception handling, documentation (Swagger), basic authentication (Spring Security), filtering and HATEOAS. You will learn the best practices in designing RESTful web services. 30 | 31 | In this part of the course, you will be using Spring (Dependency Management), Spring MVC (or Spring REST), Spring Boot, Spring Security (Authentication and Authorization), Spring Boot Actuator (Monitoring), Swagger (Documentation), Maven (dependencies management), Eclipse (IDE), Postman (REST Services Client) and Tomcat Embedded Web Server. We will help you set up each one of these. 32 | 33 | In the second part of the course, you will learn the basics of Microservices. You will understand how to implement microservices using Spring Cloud. 34 | 35 | In this part of the course, you will learn to establish communication between microservices, enable load balancing, scaling up and down of microservices. You will also learn to centralize configuration of microservices with Spring Cloud Config Server. You will implement Eureka Naming Server and Distributed tracing with Spring Cloud Sleuth and Zipkin. You will create fault toleranct microservices with Zipkin 36 | 37 | 38 | ### You will learn 39 | - You will be able to develop and design RESTful web services 40 | - You will setup Centralized Microservice Configuration with Spring Cloud Config Server 41 | - You will understand how to implement Exception Handling, Validation, HATEOAS and filtering for RESTful Web Services. 42 | - You will implement client side load balancing (Ribbon), Dynamic scaling(Eureka Naming Server) and an API Gateway (Zuul) 43 | - You will learn to implement Distributed tracing for microservices with Spring Cloud Sleuth and Zipkin 44 | - You will implement Fault Tolerance for microservices with Zipkin 45 | - You will understand how to version your RESTful Web Services 46 | - You will understand how to monitor RESTful Services with Spring Boot Actuator 47 | - You will understand how to document RESTful Web Services with Swagger 48 | - You will understand the best practices in designing RESTful web services 49 | - Using Spring Cloud Bus to exchange messages about Configuration updates 50 | - Simplify communication with other Microservices using Feign REST Client 51 | 52 | 53 | ### Step Wise Details 54 | Refer each steps 55 | 56 | ### Expectations 57 | - You should know Java and Spring. 58 | - A basic understanding of developing web applications is a bonus but NOT mandatory. 59 | - A basic understanding of Spring Boot is a bonus but NOT mandatory. We have seperate section to introduce Spring Boot. 60 | - A basic understanding of JPA is a bonus but NOT mandatory. We have seperate section to introduce JPA. 61 | - You are NOT expected to have any experience with Eclipse, Maven or Tomcat. 62 | - We will help you install Eclipse and get up and running with Maven and Tomcat. 63 | 64 | ## Installing Tools 65 | - Eclipse & Embedded Maven 66 | - PostMan 67 | - Git Client - https://git-scm.com/ 68 | - Rabbit MQ - https://www.rabbitmq.com/download.html 69 | 70 | 71 | ### Installing Eclipse & Embedded Maven 72 | - Installation Video : https://www.youtube.com/playlist?list=PLBBog2r6uMCSmMVTW_QmDLyASBvovyAO3 73 | - GIT Repository For Installation : https://github.com/in28minutes/getting-started-in-5-steps 74 | - PDF : https://github.com/in28minutes/SpringIn28Minutes/blob/master/InstallationGuide-JavaEclipseAndMaven_v2.pdf 75 | 76 | ### Installing Rabbit MQ 77 | 78 | #### Windows 79 | - https://www.rabbitmq.com/install-windows.html 80 | - https://www.rabbitmq.com/which-erlang.html 81 | - http://www.erlang.org/downloads 82 | - Video - https://www.youtube.com/watch?v=gKzKUmtOwR4 83 | 84 | #### Mac 85 | - https://www.rabbitmq.com/install-homebrew.html 86 | 87 | ## Running Examples 88 | - Download the zip or clone the Git repository. 89 | - Unzip the zip file (if you downloaded one) 90 | - Open Command Prompt and Change directory (cd) to folder containing pom.xml 91 | - Open Eclipse 92 | - File -> Import -> Existing Maven Project -> Navigate to the folder where you unzipped the zip 93 | - Select the right project 94 | - Choose the Spring Boot Application file (search for @SpringBootApplication) 95 | - Right Click on the file and Run as Java Application 96 | - You are all Set 97 | - For help : use our installation guide - https://www.youtube.com/playlist?list=PLBBog2r6uMCSmMVTW_QmDLyASBvovyAO3 98 | 99 | ### Diagrams 100 | 101 | - Check notes.md 102 | 103 | ### Troubleshooting 104 | - Refer our TroubleShooting Guide - https://github.com/in28minutes/in28minutes-initiatives/tree/master/The-in28Minutes-TroubleshootingGuide-And-FAQ 105 | 106 | ## Youtube Playlists - 500+ Videos 107 | 108 | [Click here - 30+ Playlists with 500+ Videos on Spring, Spring Boot, REST, Microservices and the Cloud](https://www.youtube.com/user/rithustutorials/playlists?view=1&sort=lad&flow=list) 109 | 110 | ## Keep Learning in28Minutes 111 | 112 | in28Minutes is creating amazing solutions for you to learn Spring Boot, Full Stack and the Cloud - Docker, Kubernetes, AWS, React, Angular etc. - [Check out all our courses here](https://github.com/in28minutes/learn) 113 | 114 | ![in28MinutesLearningRoadmap-July2019.png](https://github.com/in28minutes/in28Minutes-Course-Roadmap/raw/master/in28MinutesLearningRoadmap-July2019.png) 115 | -------------------------------------------------------------------------------- /spring-boot-2-0-0-Upgrade-notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/spring-boot-2-0-0-Upgrade-notes.pdf -------------------------------------------------------------------------------- /spring-microservices-presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/spring-microservices-presentation.pdf -------------------------------------------------------------------------------- /zipkin-server-2.12.9-exec.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/in28minutes/spring-microservices/b88121cffa5a70a72880bc084db0bb35fa3756e5/zipkin-server-2.12.9-exec.jar --------------------------------------------------------------------------------