diff --git a/week14/msa/config-repository b/week14/msa/config-repository new file mode 160000 index 0000000..2198982 --- /dev/null +++ b/week14/msa/config-repository @@ -0,0 +1 @@ +Subproject commit 2198982600aad6b0a2c40672a212dda08ec305de diff --git a/week14/msa/config-service/.gitattributes b/week14/msa/config-service/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/msa/config-service/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/msa/config-service/.gitignore b/week14/msa/config-service/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/msa/config-service/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/msa/config-service/build.gradle b/week14/msa/config-service/build.gradle new file mode 100644 index 0000000..e9d5452 --- /dev/null +++ b/week14/msa/config-service/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.10' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'dev.petclinic' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +repositories { + mavenCentral() +} + +ext { + set('springCloudVersion', "2023.0.5") +} + +dependencies { + implementation 'org.springframework.cloud:spring-cloud-config-server' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +dependencyManagement { + imports { + mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" + } +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/msa/config-service/gradle/wrapper/gradle-wrapper.jar b/week14/msa/config-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/msa/config-service/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/msa/config-service/gradle/wrapper/gradle-wrapper.properties b/week14/msa/config-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/msa/config-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/msa/config-service/gradlew b/week14/msa/config-service/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/msa/config-service/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/msa/config-service/gradlew.bat b/week14/msa/config-service/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/msa/config-service/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/msa/config-service/settings.gradle b/week14/msa/config-service/settings.gradle new file mode 100644 index 0000000..4a8db26 --- /dev/null +++ b/week14/msa/config-service/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'config-service' diff --git a/week14/msa/config-service/src/main/java/dev/petclinic/ConfigServiceApplication.java b/week14/msa/config-service/src/main/java/dev/petclinic/ConfigServiceApplication.java new file mode 100644 index 0000000..22f18c5 --- /dev/null +++ b/week14/msa/config-service/src/main/java/dev/petclinic/ConfigServiceApplication.java @@ -0,0 +1,15 @@ +package dev.petclinic; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.config.server.EnableConfigServer; + +@SpringBootApplication +@EnableConfigServer +public class ConfigServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ConfigServiceApplication.class, args); + } + +} diff --git a/week14/msa/config-service/src/main/resources/application.yml b/week14/msa/config-service/src/main/resources/application.yml new file mode 100644 index 0000000..cea7eed --- /dev/null +++ b/week14/msa/config-service/src/main/resources/application.yml @@ -0,0 +1,12 @@ +server: + port: 8888 + + +spring: + application: + name: config-service + cloud: + config: + server: + git: + uri: 'https://github.com/sengjun0624/config-repository.git' diff --git a/week14/msa/config-service/src/test/java/dev/petclinic/ConfigServiceApplicationTests.java b/week14/msa/config-service/src/test/java/dev/petclinic/ConfigServiceApplicationTests.java new file mode 100644 index 0000000..4ca3b77 --- /dev/null +++ b/week14/msa/config-service/src/test/java/dev/petclinic/ConfigServiceApplicationTests.java @@ -0,0 +1,13 @@ +package dev.petclinic; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ConfigServiceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/week14/msa/reservation-service/.gitattributes b/week14/msa/reservation-service/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/msa/reservation-service/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/msa/reservation-service/.gitignore b/week14/msa/reservation-service/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/msa/reservation-service/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/msa/reservation-service/build.gradle b/week14/msa/reservation-service/build.gradle new file mode 100644 index 0000000..cb77b4c --- /dev/null +++ b/week14/msa/reservation-service/build.gradle @@ -0,0 +1,52 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.10' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'dev.petclinic' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} +repositories { + mavenCentral() +} + +ext { + set('springCloudVersion', "2023.0.5") +} + +dependencies { + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc' + runtimeOnly 'com.mysql:mysql-connector-j' + runtimeOnly 'io.asyncer:r2dbc-mysql' + implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit' + + implementation 'org.springframework.cloud:spring-cloud-starter-config' + + implementation 'org.springframework.boot:spring-boot-starter-webflux' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'io.projectreactor:reactor-test' + + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +dependencyManagement { + imports { + mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" + } +} +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/msa/reservation-service/gradle/wrapper/gradle-wrapper.jar b/week14/msa/reservation-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/msa/reservation-service/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/msa/reservation-service/gradle/wrapper/gradle-wrapper.properties b/week14/msa/reservation-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/msa/reservation-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/msa/reservation-service/gradlew b/week14/msa/reservation-service/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/msa/reservation-service/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/msa/reservation-service/gradlew.bat b/week14/msa/reservation-service/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/msa/reservation-service/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/msa/reservation-service/settings.gradle b/week14/msa/reservation-service/settings.gradle new file mode 100644 index 0000000..cc9c71f --- /dev/null +++ b/week14/msa/reservation-service/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'reservation-service' diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/ReservationServiceApplication.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/ReservationServiceApplication.java new file mode 100644 index 0000000..8ffd80d --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/ReservationServiceApplication.java @@ -0,0 +1,13 @@ +package dev.petclinic; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ReservationServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ReservationServiceApplication.class, args); + } + +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/config/WebConfig.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/config/WebConfig.java new file mode 100644 index 0000000..e156ca7 --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/config/WebConfig.java @@ -0,0 +1,14 @@ +package dev.petclinic.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.client.WebClient; + +@Configuration +public class WebConfig { + private final String URL = "http://localhost:8081"; + @Bean + public WebClient webClient(WebClient.Builder webClientBuilder){ + return webClientBuilder.baseUrl(URL).build(); + } +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationAcceptedMessage.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationAcceptedMessage.java new file mode 100644 index 0000000..4d25db4 --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationAcceptedMessage.java @@ -0,0 +1,5 @@ +package dev.petclinic.dto; + +public record ReservationAcceptedMessage( + Long reservationId +) {} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationDispatchedMessage.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationDispatchedMessage.java new file mode 100644 index 0000000..4c2288d --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationDispatchedMessage.java @@ -0,0 +1,5 @@ +package dev.petclinic.dto; + +public record ReservationDispatchedMessage( + Long reservationId +) {} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationRequest.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationRequest.java new file mode 100644 index 0000000..b62d27d --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/ReservationRequest.java @@ -0,0 +1,12 @@ +package dev.petclinic.dto; + +import java.time.LocalDate; + +import org.springframework.data.relational.core.mapping.Table; + +public record ReservationRequest ( + Long ownerId, + Long petId, + Long vetId, + LocalDate reservationDate +) {} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/Specialty.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/Specialty.java new file mode 100644 index 0000000..2d59b70 --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/Specialty.java @@ -0,0 +1,7 @@ +package dev.petclinic.dto; + +public record Specialty( + Long id, + String name +) { +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/Vet.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/Vet.java new file mode 100644 index 0000000..a304bb9 --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/Vet.java @@ -0,0 +1,11 @@ +package dev.petclinic.dto; + +import java.util.List; + +public record Vet( + Long id, + String firstName, + String lastName, + List specialties // Specialty는 별도의 레코드 타입으로 정의된다고 가정 +) { +} \ No newline at end of file diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/VetAvailability.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/VetAvailability.java new file mode 100644 index 0000000..e031d24 --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/dto/VetAvailability.java @@ -0,0 +1,10 @@ +package dev.petclinic.dto; + +import java.util.List; + +public record VetAvailability( + Long id, + Vet vet, + List availableDays +) { +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/event/ReservationFunctions.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/event/ReservationFunctions.java new file mode 100644 index 0000000..f2d73be --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/event/ReservationFunctions.java @@ -0,0 +1,28 @@ +package dev.petclinic.event; + +import java.util.function.Consumer; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import dev.petclinic.dto.ReservationDispatchedMessage; +import dev.petclinic.service.ReservationService; +import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Flux; + +/* +에약이 확정되면, 스케줄링 서비스 애플리케이션이 생성한 메시지를 이벤트 브로커에서 꺼내 소비하는 함수 구현 + */ +@Configuration +@Slf4j +public class ReservationFunctions { + @Bean + public Consumer> dispatchReservation(ReservationService reservationService) { + // 예약 확정 이벤트 처리 + return flux -> reservationService.consumeReservationDispatchedEvent(flux) + .doOnNext( + reservation -> log.info(" == 스케줄링 처리 완료 이벤트가 전송됨, id:{}", reservation.id())) + .subscribe(); // 리액티브 스트림을 활성화 하기 위해선 subscribe 해야함. + } + +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/model/Reservation.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/model/Reservation.java new file mode 100644 index 0000000..6eaf9de --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/model/Reservation.java @@ -0,0 +1,24 @@ +package dev.petclinic.model; + +import java.time.LocalDate; + +import org.springframework.data.annotation.Id; +import org.springframework.data.relational.core.mapping.Table; + +// Record 불변 객체 셍상 +// dto를 귀찮으니 all Args 같은거 제공 +@Table(name = "reservations") +public record Reservation ( + @Id + Long id, + + Long ownerId, + Long petId, + Long vetId, + LocalDate reservationDate, + ReservationStatus status +) { + public static Reservation of(Long ownerId, Long petId, Long vetId, LocalDate reservationDate, ReservationStatus status) { + return new Reservation(null, ownerId, petId, vetId, reservationDate, status); + } +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/model/ReservationRepository.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/model/ReservationRepository.java new file mode 100644 index 0000000..4c310b7 --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/model/ReservationRepository.java @@ -0,0 +1,8 @@ +package dev.petclinic.model; + + +import org.springframework.data.repository.reactive.ReactiveCrudRepository; + +public interface ReservationRepository extends ReactiveCrudRepository { + +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/model/ReservationStatus.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/model/ReservationStatus.java new file mode 100644 index 0000000..c372320 --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/model/ReservationStatus.java @@ -0,0 +1,7 @@ +package dev.petclinic.model; + +public enum ReservationStatus { + PENDING, + CONFIRMED, + CANCELLED +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/service/ReservationService.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/service/ReservationService.java new file mode 100644 index 0000000..1dc6b1b --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/service/ReservationService.java @@ -0,0 +1,87 @@ +package dev.petclinic.service; + +import org.springframework.cloud.stream.function.StreamBridge; +import org.springframework.stereotype.Service; + +import dev.petclinic.dto.ReservationAcceptedMessage; +import dev.petclinic.dto.ReservationDispatchedMessage; +import dev.petclinic.dto.ReservationRequest; +import dev.petclinic.dto.VetAvailability; +import dev.petclinic.model.Reservation; +import dev.petclinic.model.ReservationRepository; +import dev.petclinic.model.ReservationStatus; +import dev.petclinic.web.VetAvailabilityClient; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Service +@Slf4j +@RequiredArgsConstructor +public class ReservationService { + private final ReservationRepository reservationRepository; + private final VetAvailabilityClient vetClient; + + // Before MQ + private final StreamBridge streamBridge; + // After MQ + private final StreamBridge streamBridge2; + public Flux getAllReservations() { + return reservationRepository.findAll(); + } + + public Mono submitReservation(ReservationRequest request) { + Mono vetAvailability = vetClient.getVetAvailabilityById(request.vetId()); + + Mono reservationMono = vetAvailability + .map(vet -> buildAcceptReservation(vet, request)) + .flatMap(reservationRepository::save) + .doOnNext(reservation -> publishReservationAcceptedEvent(reservation)) + .doOnSubscribe(subscription -> System.out.println("예약 프로세스에 대하 구독이 시작됨")); + + return reservationMono; + } + + private static Reservation buildAcceptReservation(VetAvailability vet, ReservationRequest reservationRequest) { + return Reservation.of( + reservationRequest.ownerId(), + reservationRequest.petId(), + reservationRequest.vetId(), + reservationRequest.reservationDate(), + ReservationStatus.PENDING); + } + + // 퍼블리셔(예약 서비스) 로직 구현 - 예약이 접수되면 브로커(RabbitMQ)에 예약 접수 메시지 전송 + private void publishReservationAcceptedEvent(Reservation reservation) { + log.info(" == Reservation Accepted(Pending) 이벤트가 호출됨, id: {}", reservation.id()); + + // 예약이 접수되었다는 이벤트 객체 생성 + var reservationAcceptedMessage = new ReservationAcceptedMessage(reservation.id()); + log.info(" == 예약 접수 이벤트가 전송됨, id: {}", reservation.id()); + + // 큐에 적재 + boolean result // 메시지를 acceptReservation-out-0에 명시적으로 전송 + = streamBridge.send("acceptReservation-out-0", reservationAcceptedMessage); + log.info("적재 결과, {}", result); + + } + + public Flux consumeReservationDispatchedEvent(Flux flux) { + return flux.flatMap(message -> + reservationRepository.findById(message.reservationId())) + .map(this::buildDispatchedReservation) + .flatMap(reservationRepository::save); + } + + private Reservation buildDispatchedReservation(Reservation existingReservation) { + return new Reservation( + existingReservation.id(), + existingReservation.ownerId(), + existingReservation.petId(), + existingReservation.vetId(), + existingReservation.reservationDate(), + ReservationStatus.CONFIRMED + ); + } +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/web/ReservationResource.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/web/ReservationResource.java new file mode 100644 index 0000000..5dcc861 --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/web/ReservationResource.java @@ -0,0 +1,34 @@ +package dev.petclinic.web; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import dev.petclinic.dto.ReservationRequest; +import dev.petclinic.model.Reservation; +import dev.petclinic.service.ReservationService; +import lombok.RequiredArgsConstructor; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@RequestMapping("/reservations") +@RestController +@RequiredArgsConstructor +public class ReservationResource { + private final ReservationService reservationService; + + + @GetMapping + public ResponseEntity> getAllReservations( ) { + return ResponseEntity.ok(reservationService.getAllReservations()); + } + + @PostMapping + public ResponseEntity> submitReservation(@RequestBody ReservationRequest request) { + return ResponseEntity.ok(reservationService.submitReservation(request)); + } +} diff --git a/week14/msa/reservation-service/src/main/java/dev/petclinic/web/VetAvailabilityClient.java b/week14/msa/reservation-service/src/main/java/dev/petclinic/web/VetAvailabilityClient.java new file mode 100644 index 0000000..6f5d8cb --- /dev/null +++ b/week14/msa/reservation-service/src/main/java/dev/petclinic/web/VetAvailabilityClient.java @@ -0,0 +1,43 @@ +package dev.petclinic.web; + +/* +MSA간 통신 과정에서 사용되는 클래스인 웹 클라이언트 Wrapper 클래스 +수의사 서비스 전용 요청 클라 + */ + +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; + +import dev.petclinic.dto.VetAvailability; +import lombok.RequiredArgsConstructor; +import reactor.core.publisher.Mono; + +@Component +@RequiredArgsConstructor +public class VetAvailabilityClient { + private static final String VETS_ROOT_API = "/vets/"; + + private final WebClient webClient; + + /** + * Vet이 진료가 가능한 날짜를 조회하는 API vet-service에 요청을 보내는 함수 + * @param id + * @return + */ + public Mono getVetAvailabilityById(Long id) { + return webClient + .get() // GET 요청 + .uri(VETS_ROOT_API + id) // 요청 URL은 vets/{vetId} + .retrieve() // 요청을 보낸 후 응답을 받음 + .bodyToMono(VetAvailability.class); // 받은 객체를 Mono로 변환 + + // TODO: 복원력(Resilience) 향상 + // 방법1. 커넥션 타임아웃(Timeout) 지정, 원격 서비스에 요청을 전송하고 응답을 받기까지 기다릴 수 있는 제한 시간 설정 + // 방법2. 재시도(Retry) 횟수 및 시간 지정 + // ex. 재시도를 시스템이 응답할 때까지 쉬지 않고 수행할 경우? 서버에 부하가 올 수 있음 + // 지수 백오프(exponential backoff) 전략 활용 + // 재시도 횟수가 늘어남에 따라 응답을 하기까지 지연되는 시간도 서서히 늘리는 것 + // (서비스가 회복되고 응답할 수 있는 시간을 주기 위함) + // 방식 - 각 재시도 요청마다 지연 시간이 요청을 시도한 횟수의 100ms(초기 백오프값)을 곱한 값으로 계산되도록 적용 + } +} diff --git a/week14/msa/reservation-service/src/main/resources/application.yml b/week14/msa/reservation-service/src/main/resources/application.yml new file mode 100644 index 0000000..724d90c --- /dev/null +++ b/week14/msa/reservation-service/src/main/resources/application.yml @@ -0,0 +1,9 @@ +spring: + application: + name: reservation-service + config: + import: "optional:configserver:" + cloud: + config: + uri: http://localhost:8888 + diff --git a/week14/msa/reservation-service/src/test/java/dev/petclinic/ReservationServiceApplicationTests.java b/week14/msa/reservation-service/src/test/java/dev/petclinic/ReservationServiceApplicationTests.java new file mode 100644 index 0000000..23d2322 --- /dev/null +++ b/week14/msa/reservation-service/src/test/java/dev/petclinic/ReservationServiceApplicationTests.java @@ -0,0 +1,13 @@ +package dev.petclinic; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ReservationServiceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/week14/msa/schedule-service/.gitattributes b/week14/msa/schedule-service/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/msa/schedule-service/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/msa/schedule-service/.gitignore b/week14/msa/schedule-service/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/msa/schedule-service/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/msa/schedule-service/build.gradle b/week14/msa/schedule-service/build.gradle new file mode 100644 index 0000000..6de379a --- /dev/null +++ b/week14/msa/schedule-service/build.gradle @@ -0,0 +1,49 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.10' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'dev.petclinic' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} +repositories { + mavenCentral() +} + +ext { + set('springCloudVersion', "2023.0.5") +} + +dependencies { + // cloud-config-client 의존성을 추가할 때 같이 작성 + implementation 'org.springframework.cloud:spring-cloud-starter-config' + implementation 'org.springframework.boot:spring-boot-starter' + + implementation 'org.springframework.cloud:spring-cloud-stream-binder-rabbit' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +// cloud-config-client 의존성을 추가할 때 같이 작성 +dependencyManagement { + imports { + mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" + } +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/msa/schedule-service/gradle/wrapper/gradle-wrapper.jar b/week14/msa/schedule-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/msa/schedule-service/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/msa/schedule-service/gradle/wrapper/gradle-wrapper.properties b/week14/msa/schedule-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/msa/schedule-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/msa/schedule-service/gradlew b/week14/msa/schedule-service/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/msa/schedule-service/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/msa/schedule-service/gradlew.bat b/week14/msa/schedule-service/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/msa/schedule-service/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/msa/schedule-service/settings.gradle b/week14/msa/schedule-service/settings.gradle new file mode 100644 index 0000000..aaede98 --- /dev/null +++ b/week14/msa/schedule-service/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'schedule-service' diff --git a/week14/msa/schedule-service/src/main/java/dev/petclinic/DispatcherFunctions.java b/week14/msa/schedule-service/src/main/java/dev/petclinic/DispatcherFunctions.java new file mode 100644 index 0000000..b307579 --- /dev/null +++ b/week14/msa/schedule-service/src/main/java/dev/petclinic/DispatcherFunctions.java @@ -0,0 +1,67 @@ +package dev.petclinic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.function.Function; + +import reactor.core.publisher.Flux; + +/* + 스케줄링 서비스의 동작 흐름 + 스케줄링 서비스는 예약이 접수되었다는 큐를 구독하고 있음 + 해당 큐에는 예약이 접수되었다는 이벤트 객체가 적재되어 있음(ReservationAcceptedMessage) + + 큐에 이벤트가 적재되면 MQ는 스케줄링 서비스에게 push + 스케줄링 서비스는 예약 접수 이벤트를 가지고 스케줄링을 처리하기 위해 다음의 동작을 수행함 + + 함수는 입출력이 있음 + 1. schedule() 호출 + schedule()는 입력값으로 ReservationAcceptedMessage를 받음 + 반환값으로 예약 ID인 Long타입을 반환 + + 2. confirm() 호출 + schedule()에 의해 호출되면서 schedule() 함수의 반환값으로 받은 Long 타입을 + 자신의 입력값으로 전달받음 + + 반환값으로는 예약 스케줄링이 완료되었다는 이벤트 객체를 의미하는 + Flux를 반환 + */ + + +// 서버리스로 동작할 함수 및 로직 작성 +@Configuration +public class DispatcherFunctions { + + private static final Logger log = LoggerFactory.getLogger(DispatcherFunctions.class); + + // Function<외부에서 들어오는 입력값 파라미터, 반환값> + @Bean + public Function schedule() { + return reservationAcceptedMessage -> { + log.info("예약 ID: {} 가 스케줄링 처리됨"); + + // 스케줄링 로직 처리.. + + // schedule()의 반환값은 예약 접수 ID(Long 타입) + return reservationAcceptedMessage.reservationId(); + }; + } + // schedule() 함수 다음으로 동작하는 함수, 스케줄링 처리 확정 로직을 수행한다고 가정 + @Bean + public Function, Flux> confirm() { + return reservationFlux -> + reservationFlux.map(reservationId -> { + log.info("예약 ID: {} 가 확정 처리됨", reservationId); + + // 스케줄링 처리 확정 로직 처리.. + + // 스케줄링이 완료되었다는 이벤트 객체를 반환 + return new ReservationDispatchedMessage(reservationId); + }); + } + + +} diff --git a/week14/msa/schedule-service/src/main/java/dev/petclinic/ReservationAcceptedMessage.java b/week14/msa/schedule-service/src/main/java/dev/petclinic/ReservationAcceptedMessage.java new file mode 100644 index 0000000..6aaa179 --- /dev/null +++ b/week14/msa/schedule-service/src/main/java/dev/petclinic/ReservationAcceptedMessage.java @@ -0,0 +1,5 @@ +package dev.petclinic; + +public record ReservationAcceptedMessage( + Long reservationId +) {} diff --git a/week14/msa/schedule-service/src/main/java/dev/petclinic/ReservationDispatchedMessage.java b/week14/msa/schedule-service/src/main/java/dev/petclinic/ReservationDispatchedMessage.java new file mode 100644 index 0000000..56d0e87 --- /dev/null +++ b/week14/msa/schedule-service/src/main/java/dev/petclinic/ReservationDispatchedMessage.java @@ -0,0 +1,5 @@ +package dev.petclinic; + +public record ReservationDispatchedMessage( + Long reservationId +) {} diff --git a/week14/msa/schedule-service/src/main/java/dev/petclinic/ScheduleServiceApplication.java b/week14/msa/schedule-service/src/main/java/dev/petclinic/ScheduleServiceApplication.java new file mode 100644 index 0000000..2fa2075 --- /dev/null +++ b/week14/msa/schedule-service/src/main/java/dev/petclinic/ScheduleServiceApplication.java @@ -0,0 +1,13 @@ +package dev.petclinic; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ScheduleServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ScheduleServiceApplication.class, args); + } + +} diff --git a/week14/msa/schedule-service/src/main/resources/application.yml b/week14/msa/schedule-service/src/main/resources/application.yml new file mode 100644 index 0000000..f536769 --- /dev/null +++ b/week14/msa/schedule-service/src/main/resources/application.yml @@ -0,0 +1,9 @@ +spring: + application: + name: schedule-service + config: + import: "optional:configserver:" + cloud: + config: + uri: http://localhost:8888 + diff --git a/week14/msa/schedule-service/src/test/java/dev/petclinic/ScheduleServiceApplicationTests.java b/week14/msa/schedule-service/src/test/java/dev/petclinic/ScheduleServiceApplicationTests.java new file mode 100644 index 0000000..bbcc15f --- /dev/null +++ b/week14/msa/schedule-service/src/test/java/dev/petclinic/ScheduleServiceApplicationTests.java @@ -0,0 +1,13 @@ +package dev.petclinic; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ScheduleServiceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/week14/msa/vet-service/.gitattributes b/week14/msa/vet-service/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/msa/vet-service/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/msa/vet-service/.gitignore b/week14/msa/vet-service/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/msa/vet-service/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/msa/vet-service/build.gradle b/week14/msa/vet-service/build.gradle new file mode 100644 index 0000000..7f9e659 --- /dev/null +++ b/week14/msa/vet-service/build.gradle @@ -0,0 +1,57 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.10' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'dev.petclinie' +version = '0.0.1-SNAPSHOT' + + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +// cloud-config-client 의존성을 추가할 때 같이 작성 +// 스프링 클라우드 버전 추가 +ext { + set('springCloudVersion', "2023.0.5") +} + +dependencies { + + // cloud-config-client 의존성을 추가할 때 같이 작성 + implementation 'org.springframework.cloud:spring-cloud-starter-config' + + + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + runtimeOnly 'com.mysql:mysql-connector-j' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +// cloud-config-client 의존성을 추가할 때 같이 작성 +dependencyManagement { + imports { + mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" + } +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/msa/vet-service/gradle/wrapper/gradle-wrapper.jar b/week14/msa/vet-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/msa/vet-service/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/msa/vet-service/gradle/wrapper/gradle-wrapper.properties b/week14/msa/vet-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/msa/vet-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/msa/vet-service/gradlew b/week14/msa/vet-service/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/msa/vet-service/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/msa/vet-service/gradlew.bat b/week14/msa/vet-service/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/msa/vet-service/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/msa/vet-service/settings.gradle b/week14/msa/vet-service/settings.gradle new file mode 100644 index 0000000..debf2ed --- /dev/null +++ b/week14/msa/vet-service/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'vet-service' diff --git a/week14/msa/vet-service/src/main/java/dev/petclinic/VetServiceApplication.java b/week14/msa/vet-service/src/main/java/dev/petclinic/VetServiceApplication.java new file mode 100644 index 0000000..f154c10 --- /dev/null +++ b/week14/msa/vet-service/src/main/java/dev/petclinic/VetServiceApplication.java @@ -0,0 +1,13 @@ +package dev.petclinic; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class VetServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(VetServiceApplication.class, args); + } + +} diff --git a/week14/msa/vet-service/src/main/java/dev/petclinic/model/Specialty.java b/week14/msa/vet-service/src/main/java/dev/petclinic/model/Specialty.java new file mode 100644 index 0000000..e0302ca --- /dev/null +++ b/week14/msa/vet-service/src/main/java/dev/petclinic/model/Specialty.java @@ -0,0 +1,18 @@ +package dev.petclinic.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.ToString; + +@Entity +@Table(name = "specialties") +@Getter +@ToString +public class Specialty { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String name; + +} diff --git a/week14/msa/vet-service/src/main/java/dev/petclinic/model/Vet.java b/week14/msa/vet-service/src/main/java/dev/petclinic/model/Vet.java new file mode 100644 index 0000000..0ccf5e5 --- /dev/null +++ b/week14/msa/vet-service/src/main/java/dev/petclinic/model/Vet.java @@ -0,0 +1,28 @@ +package dev.petclinic.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.ToString; + +import java.util.Set; + +@Entity +@Table(name = "vets") +@Getter +@ToString +public class Vet { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String firstName; + + private String lastName; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), + inverseJoinColumns = @JoinColumn(name = "specialty_id")) + private Set specialties; + +} diff --git a/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetAvailability.java b/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetAvailability.java new file mode 100644 index 0000000..c352bf3 --- /dev/null +++ b/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetAvailability.java @@ -0,0 +1,52 @@ +package dev.petclinic.model; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.ToString; + +import java.time.DayOfWeek; +import java.util.HashSet; +import java.util.Set; + +@Entity +@ToString +@Getter +public class VetAvailability { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "vet_id", nullable = false) + private Vet vet; + + private byte availableDays; + + // 요일별 예약 가능 여부를 비트마스크로 설정 + public void setAvailableDays(Set availableDays) { + byte mask = 0; + for (DayOfWeek day : availableDays) { + mask |= (1 << day.getValue() % 7); // DayOfWeek의 값은 1부터 시작하므로 7로 모듈러 연산 + } + this.availableDays = mask; + } + + // 특정 요일에 예약 가능한지 확인하는 메서드 + public boolean isAvailableOn(DayOfWeek day) { + return (availableDays & (1 << day.getValue() % 7)) != 0; + } + + // 예약 가능한 요일 목록을 반환하는 메서드 + public Set getAvailableDays() { + Set days = new HashSet<>(); + for (DayOfWeek day : DayOfWeek.values()) { + if ((availableDays & (1 << day.getValue() % 7)) != 0) { + days.add(day); + } + } + return days; + } + +} + diff --git a/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetAvailabilityRepository.java b/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetAvailabilityRepository.java new file mode 100644 index 0000000..934b496 --- /dev/null +++ b/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetAvailabilityRepository.java @@ -0,0 +1,19 @@ +package dev.petclinic.model; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface VetAvailabilityRepository extends JpaRepository { + + VetAvailability findByVetId(@Param("id") Long vetId); + + // 예약 가능한 특정 요일을 조회하는 메서드 + @Query(value = "SELECT * FROM vet_availability WHERE (available_days & :dayMask) != 0", nativeQuery = true) + List findAvailableVetsOnDay(@Param("dayMask") byte dayMask); + +} diff --git a/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetRepository.java b/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetRepository.java new file mode 100644 index 0000000..8f04032 --- /dev/null +++ b/week14/msa/vet-service/src/main/java/dev/petclinic/model/VetRepository.java @@ -0,0 +1,6 @@ +package dev.petclinic.model; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface VetRepository extends JpaRepository { +} diff --git a/week14/msa/vet-service/src/main/java/dev/petclinic/service/VetService.java b/week14/msa/vet-service/src/main/java/dev/petclinic/service/VetService.java new file mode 100644 index 0000000..5a79ed5 --- /dev/null +++ b/week14/msa/vet-service/src/main/java/dev/petclinic/service/VetService.java @@ -0,0 +1,30 @@ +package dev.petclinic.service; + +import dev.petclinic.model.Vet; +import dev.petclinic.model.VetAvailability; +import dev.petclinic.model.VetAvailabilityRepository; +import dev.petclinic.model.VetRepository; +import lombok.RequiredArgsConstructor; + +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class VetService { + + private final VetRepository vetRepository; + private final VetAvailabilityRepository vetAvailabilityRepository; + + public List getVetList() { + return vetRepository.findAll(); + } + + public VetAvailability getVetById(@PathVariable Long vetId) { + return vetAvailabilityRepository.findByVetId(vetId); + } + + // 수의사 ID로 해당 수의사의 진료 가능한 요일 조회 +} diff --git a/week14/msa/vet-service/src/main/java/dev/petclinic/web/VetResource.java b/week14/msa/vet-service/src/main/java/dev/petclinic/web/VetResource.java new file mode 100644 index 0000000..02b3466 --- /dev/null +++ b/week14/msa/vet-service/src/main/java/dev/petclinic/web/VetResource.java @@ -0,0 +1,37 @@ +package dev.petclinic.web; + +import dev.petclinic.model.Vet; +import dev.petclinic.model.VetAvailability; +import dev.petclinic.service.VetService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 본질적으로는 Controller 역할 수행 + */ + +@RequestMapping("/vets") +@RestController +@RequiredArgsConstructor +public class VetResource { + + private final VetService vetService; + + // 전체 수의사 정보 조회 + @GetMapping + public List getVetList() { + return vetService.getVetList(); + } + + // 수의사 ID로 해당 수의사의 진료 가능한 요일 조회 + @GetMapping("/{vetId}") + public VetAvailability getVetById(@PathVariable Long vetId) throws InterruptedException { + + return vetService.getVetById(vetId); + } +} diff --git a/week14/msa/vet-service/src/main/resources/application.yml b/week14/msa/vet-service/src/main/resources/application.yml new file mode 100644 index 0000000..9b00361 --- /dev/null +++ b/week14/msa/vet-service/src/main/resources/application.yml @@ -0,0 +1,8 @@ +spring: + application: + name: vet-service + config: + import: "optional:configserver:" + cloud: + config: + uri: http://localhost:8888 diff --git a/week14/msa/vet-service/src/main/resources/data.sql b/week14/msa/vet-service/src/main/resources/data.sql new file mode 100644 index 0000000..95d2612 --- /dev/null +++ b/week14/msa/vet-service/src/main/resources/data.sql @@ -0,0 +1,31 @@ +INSERT IGNORE INTO vets VALUES (1, 'James', 'Carter'); +INSERT IGNORE INTO vets VALUES (2, 'Helen', 'Leary'); +INSERT IGNORE INTO vets VALUES (3, 'Linda', 'Douglas'); +INSERT IGNORE INTO vets VALUES (4, 'Rafael', 'Ortega'); +INSERT IGNORE INTO vets VALUES (5, 'Henry', 'Stevens'); +INSERT IGNORE INTO vets VALUES (6, 'Sharon', 'Jenkins'); + +INSERT IGNORE INTO specialties VALUES (1, 'radiology'); +INSERT IGNORE INTO specialties VALUES (2, 'surgery'); +INSERT IGNORE INTO specialties VALUES (3, 'dentistry'); + +INSERT IGNORE INTO vet_specialties VALUES (2, 1); +INSERT IGNORE INTO vet_specialties VALUES (3, 2); +INSERT IGNORE INTO vet_specialties VALUES (3, 3); +INSERT IGNORE INTO vet_specialties VALUES (4, 2); +INSERT IGNORE INTO vet_specialties VALUES (5, 1); + +-- 수의사 ID가 1인 경우 +-- 월요일부터 일요일까지 모두 가능한 경우 (비트마스크: 1111111, 127) +INSERT INTO vet_availability (vet_id, available_days) VALUES +(1, 127), + +-- 수의사 ID가 2인 경우 +-- 월요일, 화요일, 토요일 가능한 경우 (비트마스크: 1000010, 66) +INSERT INTO vet_availability (vet_id, available_days) VALUES +(2, 66), + +-- 수의사 ID가 3인 경우 +-- 화요일, 수요일, 목요일 가능한 경우 (비트마스크: 0011100, 28) +INSERT INTO vet_availability (vet_id, available_days) VALUES +(3, 28); \ No newline at end of file diff --git a/week14/msa/vet-service/src/main/resources/schema.sql b/week14/msa/vet-service/src/main/resources/schema.sql new file mode 100644 index 0000000..2598724 --- /dev/null +++ b/week14/msa/vet-service/src/main/resources/schema.sql @@ -0,0 +1,32 @@ +DROP DATABASE petclinic_vet; +CREATE DATABASE petclinic_vet; +use petclinic_vet; + +CREATE TABLE IF NOT EXISTS vets ( + id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + first_name VARCHAR(30), + last_name VARCHAR(30), + INDEX(last_name) +) engine=InnoDB; + +CREATE TABLE IF NOT EXISTS specialties ( + id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(80), + INDEX(name) +) engine=InnoDB; + +CREATE TABLE IF NOT EXISTS vet_specialties ( + vet_id BIGINT(20) UNSIGNED NOT NULL, + specialty_id BIGINT(20) UNSIGNED NOT NULL, + FOREIGN KEY (vet_id) REFERENCES vets(id), + FOREIGN KEY (specialty_id) REFERENCES specialties(id), + UNIQUE (vet_id,specialty_id) +) engine=InnoDB; + +CREATE TABLE vet_availability ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + vet_id BIGINT(20) UNSIGNED NOT NULL, + available_days TINYINT UNSIGNED, -- 요일 정보는 최대 7비트만 사용하므로 TINYINT로 저장 가능 + FOREIGN KEY (vet_id) REFERENCES vets(id) +); + diff --git a/week14/msa/vet-service/src/test/java/dev/petclinic/VetServiceApplicationTests.java b/week14/msa/vet-service/src/test/java/dev/petclinic/VetServiceApplicationTests.java new file mode 100644 index 0000000..b28172a --- /dev/null +++ b/week14/msa/vet-service/src/test/java/dev/petclinic/VetServiceApplicationTests.java @@ -0,0 +1,13 @@ +package dev.petclinic; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class VetServiceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/week14/mvc-webflux/api-client/.gitattributes b/week14/mvc-webflux/api-client/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/mvc-webflux/api-client/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/mvc-webflux/api-client/.gitignore b/week14/mvc-webflux/api-client/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/mvc-webflux/api-client/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/mvc-webflux/api-client/build.gradle b/week14/mvc-webflux/api-client/build.gradle new file mode 100644 index 0000000..ce3dcf4 --- /dev/null +++ b/week14/mvc-webflux/api-client/build.gradle @@ -0,0 +1,39 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.4' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'dev.client' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/mvc-webflux/api-client/gradle/wrapper/gradle-wrapper.jar b/week14/mvc-webflux/api-client/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/mvc-webflux/api-client/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/mvc-webflux/api-client/gradle/wrapper/gradle-wrapper.properties b/week14/mvc-webflux/api-client/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/mvc-webflux/api-client/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/mvc-webflux/api-client/gradlew b/week14/mvc-webflux/api-client/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/mvc-webflux/api-client/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/mvc-webflux/api-client/gradlew.bat b/week14/mvc-webflux/api-client/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/mvc-webflux/api-client/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/mvc-webflux/api-client/settings.gradle b/week14/mvc-webflux/api-client/settings.gradle new file mode 100644 index 0000000..e9b266a --- /dev/null +++ b/week14/mvc-webflux/api-client/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'api-client' diff --git a/week14/mvc-webflux/api-client/src/main/java/dev/client/ApiClientApplication.java b/week14/mvc-webflux/api-client/src/main/java/dev/client/ApiClientApplication.java new file mode 100644 index 0000000..381edfc --- /dev/null +++ b/week14/mvc-webflux/api-client/src/main/java/dev/client/ApiClientApplication.java @@ -0,0 +1,13 @@ +package dev.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ApiClientApplication { + + public static void main(String[] args) { + SpringApplication.run(ApiClientApplication.class, args); + } + +} diff --git a/week14/mvc-webflux/api-client/src/main/resources/application.properties b/week14/mvc-webflux/api-client/src/main/resources/application.properties new file mode 100644 index 0000000..798447a --- /dev/null +++ b/week14/mvc-webflux/api-client/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=api-client diff --git a/week14/mvc-webflux/api-client/src/test/java/dev/client/ApiClientApplicationTests.java b/week14/mvc-webflux/api-client/src/test/java/dev/client/ApiClientApplicationTests.java new file mode 100644 index 0000000..eb7f72c --- /dev/null +++ b/week14/mvc-webflux/api-client/src/test/java/dev/client/ApiClientApplicationTests.java @@ -0,0 +1,81 @@ +package dev.client; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@SpringBootTest +class ApiClientApplicationTests { + + private static final List ORDER_IDS + = List.of(1001, 1002, 1003, 1004, 1005); + private static final String MVC_BASE_URL = "http://localhost:8080/mvc/delivery-info/"; + + private static final String WEBFLUX_BASE_URL = "http://localhost:9000/webflux/delivery-info/"; + + private final HttpClient httpClient = HttpClient.newHttpClient(); + + // mvc 방식의 테스트 케이스 + @Test + void MVC_요청() throws Exception { + Instant start = Instant.now(); // 시작 시간 측정 + + // mvc-commerce-service로 여러 번 요청 수행 + for (int orderId : ORDER_IDS) { + // HttpRequest - 순수 java로 작성된 API Client + + // 요청에 필요한 객체 생성 + HttpRequest request = HttpRequest.newBuilder() + .uri(new URI(MVC_BASE_URL + orderId)) + .GET() + .build(); + + // 실제 요청 수행 + HttpResponse response // 응답 결과 + = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + log.info("응답(orderId={}): {}", orderId, response.body()); + } + + Instant end = Instant.now(); // 종료 시간 측정 + log.info("[동기 요청 종료] 총 소요 시간: {}ms", + Duration.between(start,end).toMillis()); + } + + // webflux 방식의 테스트 케이스 + @Test + void Webflux_요청() throws Exception { + log.info("[비동기 요청 시작]"); + Instant start = Instant.now(); + + // 비동기적으로 총 5번 요청 수행 시, 결과를 다 받고 출력 + CompletableFuture[] futures = ORDER_IDS.stream() + .map(orderId -> { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(WEBFLUX_BASE_URL + orderId)) + .GET() + .build(); + + return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .thenAccept(response -> + log.info("응답(orderId={}): {}", orderId, response.body()) + ); + }) + .toArray(CompletableFuture[]::new); + + CompletableFuture.allOf(futures).join(); + + Instant end = Instant.now(); + log.info("[비동기 요청 종료] 총 소요 시간: {}ms", Duration.between(start, end).toMillis()); + } +} diff --git a/week14/mvc-webflux/commerce-webflux/.gitattributes b/week14/mvc-webflux/commerce-webflux/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/mvc-webflux/commerce-webflux/.gitignore b/week14/mvc-webflux/commerce-webflux/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/mvc-webflux/commerce-webflux/build.gradle b/week14/mvc-webflux/commerce-webflux/build.gradle new file mode 100644 index 0000000..469e631 --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.4' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'dev.webflux' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +repositories { + mavenCentral() +} + +dependencies { + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + implementation 'org.springframework.boot:spring-boot-starter-webflux' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'io.projectreactor:reactor-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/mvc-webflux/commerce-webflux/gradle/wrapper/gradle-wrapper.jar b/week14/mvc-webflux/commerce-webflux/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/mvc-webflux/commerce-webflux/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/mvc-webflux/commerce-webflux/gradle/wrapper/gradle-wrapper.properties b/week14/mvc-webflux/commerce-webflux/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/mvc-webflux/commerce-webflux/gradlew b/week14/mvc-webflux/commerce-webflux/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/mvc-webflux/commerce-webflux/gradlew.bat b/week14/mvc-webflux/commerce-webflux/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/mvc-webflux/commerce-webflux/settings.gradle b/week14/mvc-webflux/commerce-webflux/settings.gradle new file mode 100644 index 0000000..aa46edf --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'commerce-webflux' diff --git a/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/CommerceController.java b/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/CommerceController.java new file mode 100644 index 0000000..e0a63a5 --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/CommerceController.java @@ -0,0 +1,41 @@ +package dev.webflux; + + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +@Slf4j +@RequestMapping(path = "/webflux/delivery-info") +@RestController +@RequiredArgsConstructor +public class CommerceController { + + // 비동기 요청 클라이언트 + private final WebClient webClient; + + private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); + + @GetMapping("/{orderId}") + public Mono getInfo(@PathVariable int orderId) { + log.info("요청 시작 시간 - : {}", LocalTime.now().format(TIME_FORMATTER)); + + String delivery_service_url = "/webflux/delivery/{orderId}"; + + return webClient // 실제 요청 수행 + .get() + .uri(delivery_service_url, orderId) + .retrieve() + .bodyToMono(DeliveryInfo.class) // Mono 타입으로 변경 + .doOnNext(info // 결과를 응답 받고 처리할 로직(콜백) + -> log.info("응답 완료 시간 - : {}", LocalTime.now().format(TIME_FORMATTER))); + } +} diff --git a/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/CommerceWebfluxApplication.java b/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/CommerceWebfluxApplication.java new file mode 100644 index 0000000..a310a19 --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/CommerceWebfluxApplication.java @@ -0,0 +1,21 @@ +package dev.webflux; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.reactive.function.client.WebClient; + +@SpringBootApplication +public class CommerceWebfluxApplication { + + public static void main(String[] args) { + SpringApplication.run(CommerceWebfluxApplication.class, args); + } + + // 비동기 요청을 수행하는 클라이언트 객체를 스프링 빈으로 등록 + @Bean + public WebClient webClient() { + String delivery_webflux_url = "http://localhost:9010"; + return WebClient.builder().baseUrl(delivery_webflux_url).build(); + } +} diff --git a/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/DeliveryInfo.java b/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/DeliveryInfo.java new file mode 100644 index 0000000..55c7797 --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/src/main/java/dev/webflux/DeliveryInfo.java @@ -0,0 +1,13 @@ +package dev.webflux; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class DeliveryInfo { + + private int orderId; // 주문 ID + private String status; // 배송 상태 (예: 배송중, 배송완료, 배송지연) + +} diff --git a/week14/mvc-webflux/commerce-webflux/src/main/resources/application.properties b/week14/mvc-webflux/commerce-webflux/src/main/resources/application.properties new file mode 100644 index 0000000..ff51622 --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.application.name=commerce-webflux + +server.port = 9000 diff --git a/week14/mvc-webflux/commerce-webflux/src/test/java/dev/webflux/CommerceWebfluxApplicationTests.java b/week14/mvc-webflux/commerce-webflux/src/test/java/dev/webflux/CommerceWebfluxApplicationTests.java new file mode 100644 index 0000000..a8cd8a9 --- /dev/null +++ b/week14/mvc-webflux/commerce-webflux/src/test/java/dev/webflux/CommerceWebfluxApplicationTests.java @@ -0,0 +1,13 @@ +package dev.webflux; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class CommerceWebfluxApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/week14/mvc-webflux/delivery-mvc/.gitattributes b/week14/mvc-webflux/delivery-mvc/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/mvc-webflux/delivery-mvc/.gitignore b/week14/mvc-webflux/delivery-mvc/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/mvc-webflux/delivery-mvc/build.gradle b/week14/mvc-webflux/delivery-mvc/build.gradle new file mode 100644 index 0000000..ec0f784 --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.4' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'mvc.delivery' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/mvc-webflux/delivery-mvc/gradle/wrapper/gradle-wrapper.jar b/week14/mvc-webflux/delivery-mvc/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/mvc-webflux/delivery-mvc/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/mvc-webflux/delivery-mvc/gradle/wrapper/gradle-wrapper.properties b/week14/mvc-webflux/delivery-mvc/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/mvc-webflux/delivery-mvc/gradlew b/week14/mvc-webflux/delivery-mvc/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/mvc-webflux/delivery-mvc/gradlew.bat b/week14/mvc-webflux/delivery-mvc/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/mvc-webflux/delivery-mvc/settings.gradle b/week14/mvc-webflux/delivery-mvc/settings.gradle new file mode 100644 index 0000000..17e5adb --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'delivery-mvc' diff --git a/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryController.java b/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryController.java new file mode 100644 index 0000000..7b81edd --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryController.java @@ -0,0 +1,41 @@ +package mvc.delivery; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.extern.slf4j.Slf4j; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.Map; + +/* + 사용자(api-client)로부터 배송 조회 요청을 받는 컨트롤러 + */ +@Slf4j +@RequestMapping(path = "/mvc/delivery") +@RestController +public class DeliveryController { + + private static final Map deliveryStatusMap = Map.of( + 1001, "배송 중", // 1001인 주문 id는 배송 중인 상태 + 1002, "배송 중", // 1002인 주문 id는 배송 중인 상태 + 1003, "배송 지연", + 1004, "입고", + 1005, "배송 지연" + ); + + @GetMapping("/{orderId}") + public ResponseEntity getDeliveryInfo(@PathVariable int orderId) throws InterruptedException { + + // 배송 정보 조회의 시간을 의도적으로 지연 + Thread.sleep(3000); + + String status = deliveryStatusMap.get(orderId); + + DeliveryInfo info = new DeliveryInfo(orderId, status); + return ResponseEntity.ok(info); + } +} diff --git a/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryInfo.java b/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryInfo.java new file mode 100644 index 0000000..cd6844f --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryInfo.java @@ -0,0 +1,12 @@ +package mvc.delivery; + +import lombok.AllArgsConstructor; +import lombok.Data; +@Data +@AllArgsConstructor +public class DeliveryInfo { + + private int orderId; // 주문 ID + private String status; // 배송 상태 (예: 배송중, 배송완료, 배송지연) + +} diff --git a/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryMvcApplication.java b/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryMvcApplication.java new file mode 100644 index 0000000..1c274aa --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/src/main/java/mvc/delivery/DeliveryMvcApplication.java @@ -0,0 +1,13 @@ +package mvc.delivery; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DeliveryMvcApplication { + + public static void main(String[] args) { + SpringApplication.run(DeliveryMvcApplication.class, args); + } + +} diff --git a/week14/mvc-webflux/delivery-mvc/src/main/resources/application.properties b/week14/mvc-webflux/delivery-mvc/src/main/resources/application.properties new file mode 100644 index 0000000..10fcfa9 --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.application.name=delivery-mvc + +server.port=8090 diff --git a/week14/mvc-webflux/delivery-mvc/src/test/java/mvc/delivery/DeliveryMvcApplicationTests.java b/week14/mvc-webflux/delivery-mvc/src/test/java/mvc/delivery/DeliveryMvcApplicationTests.java new file mode 100644 index 0000000..0297d80 --- /dev/null +++ b/week14/mvc-webflux/delivery-mvc/src/test/java/mvc/delivery/DeliveryMvcApplicationTests.java @@ -0,0 +1,13 @@ +package mvc.delivery; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class DeliveryMvcApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/week14/mvc-webflux/delivery-webflux/.gitattributes b/week14/mvc-webflux/delivery-webflux/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/mvc-webflux/delivery-webflux/.gitignore b/week14/mvc-webflux/delivery-webflux/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/mvc-webflux/delivery-webflux/build.gradle b/week14/mvc-webflux/delivery-webflux/build.gradle new file mode 100644 index 0000000..9f030fe --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/build.gradle @@ -0,0 +1,31 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.4' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'delivery.webflux' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +repositories { + mavenCentral() +} + +dependencies { + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + implementation 'org.springframework.boot:spring-boot-starter-webflux' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'io.projectreactor:reactor-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/mvc-webflux/delivery-webflux/gradle/wrapper/gradle-wrapper.jar b/week14/mvc-webflux/delivery-webflux/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/mvc-webflux/delivery-webflux/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/mvc-webflux/delivery-webflux/gradle/wrapper/gradle-wrapper.properties b/week14/mvc-webflux/delivery-webflux/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/mvc-webflux/delivery-webflux/gradlew b/week14/mvc-webflux/delivery-webflux/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/mvc-webflux/delivery-webflux/gradlew.bat b/week14/mvc-webflux/delivery-webflux/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/mvc-webflux/delivery-webflux/settings.gradle b/week14/mvc-webflux/delivery-webflux/settings.gradle new file mode 100644 index 0000000..197dbba --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'delivery-webflux' diff --git a/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryController.java b/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryController.java new file mode 100644 index 0000000..2983b52 --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryController.java @@ -0,0 +1,41 @@ +package delivery.webflux; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +import java.time.format.DateTimeFormatter; +import java.util.Map; + +@Slf4j +@RequestMapping(path = "/webflux/delivery") +@RestController +public class DeliveryController { + + // 인메모리 배송 정보 데이터 + private static final Map deliveryStatusMap = Map.of( + 1001, "배송 중", + 1002, "배송 중", + 1003, "배송 지연", + 1004, "입고", + 1005, "배송 지연" + ); + + private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); + + @GetMapping("/{orderId}") + public Mono getDeliveryInfo(@PathVariable("orderId") int orderId) throws InterruptedException { + + Thread.sleep(3000); + + String s = deliveryStatusMap.get(orderId); + DeliveryInfo info = new DeliveryInfo(orderId, s); + + return Mono.just(info); // just Mono 객체 생성 + } + +} diff --git a/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryInfo.java b/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryInfo.java new file mode 100644 index 0000000..bbd9f09 --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryInfo.java @@ -0,0 +1,13 @@ +package delivery.webflux; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class DeliveryInfo { + + private int orderId; // 주문 ID + private String status; // 배송 상태 (예: 배송중, 배송완료, 배송지연) + +} diff --git a/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryWebfluxApplication.java b/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryWebfluxApplication.java new file mode 100644 index 0000000..7c4f5d5 --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/src/main/java/delivery/webflux/DeliveryWebfluxApplication.java @@ -0,0 +1,13 @@ +package delivery.webflux; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DeliveryWebfluxApplication { + + public static void main(String[] args) { + SpringApplication.run(DeliveryWebfluxApplication.class, args); + } + +} diff --git a/week14/mvc-webflux/delivery-webflux/src/main/resources/application.properties b/week14/mvc-webflux/delivery-webflux/src/main/resources/application.properties new file mode 100644 index 0000000..a03d4e5 --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.application.name=delivery-webflux + +server.port=9010 diff --git a/week14/mvc-webflux/delivery-webflux/src/test/java/delivery/webflux/DeliveryWebfluxApplicationTests.java b/week14/mvc-webflux/delivery-webflux/src/test/java/delivery/webflux/DeliveryWebfluxApplicationTests.java new file mode 100644 index 0000000..8bf7f05 --- /dev/null +++ b/week14/mvc-webflux/delivery-webflux/src/test/java/delivery/webflux/DeliveryWebfluxApplicationTests.java @@ -0,0 +1,13 @@ +package delivery.webflux; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class DeliveryWebfluxApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/week14/mvc-webflux/mvc-commerce/.gitattributes b/week14/mvc-webflux/mvc-commerce/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/mvc-webflux/mvc-commerce/.gitignore b/week14/mvc-webflux/mvc-commerce/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/mvc-webflux/mvc-commerce/build.gradle b/week14/mvc-webflux/mvc-commerce/build.gradle new file mode 100644 index 0000000..2f68f29 --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.4' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'commerce.mvc' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/mvc-webflux/mvc-commerce/gradle/wrapper/gradle-wrapper.jar b/week14/mvc-webflux/mvc-commerce/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/mvc-webflux/mvc-commerce/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/mvc-webflux/mvc-commerce/gradle/wrapper/gradle-wrapper.properties b/week14/mvc-webflux/mvc-commerce/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/mvc-webflux/mvc-commerce/gradlew b/week14/mvc-webflux/mvc-commerce/gradlew new file mode 100755 index 0000000..faf9300 --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/mvc-webflux/mvc-commerce/gradlew.bat b/week14/mvc-webflux/mvc-commerce/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/mvc-webflux/mvc-commerce/settings.gradle b/week14/mvc-webflux/mvc-commerce/settings.gradle new file mode 100644 index 0000000..7e0e822 --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'mvc-commerce' diff --git a/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/CommerceController.java b/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/CommerceController.java new file mode 100644 index 0000000..226b496 --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/CommerceController.java @@ -0,0 +1,39 @@ +package commerce.mvc; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import lombok.extern.slf4j.Slf4j; + +/* + 사용자(api-client)로부터 배송 조회 요청을 받는 컨트롤러 + */ +@Slf4j +@RequestMapping(path = "/mvc/delivery-info") +@RestController +public class CommerceController { + private final RestTemplate restTemplate = new RestTemplate(); + private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); + @GetMapping("/{orderId}") + public ResponseEntity getInfo(@PathVariable("orderId") int orderId) { + log.info("요청 시작 시간 - : {}", LocalTime.now().format(TIME_FORMATTER)); + + // delivery 서비스(외부 API)에게 배송 조회 요청을 전송 + // delivery 서비스의 URL 지정 + String url = "http://localhost:8090/mvc/delivery/" + orderId; + + // 해당 서비스에게 요청 전송 + DeliveryInfo deliveryInfo = restTemplate.getForObject(url, DeliveryInfo.class); + + // 결과를 응답 받으면 그대로 클라이언트에게 응답 + log.info("응답 완료 시간 - : {}", LocalTime.now().format(TIME_FORMATTER)); + return ResponseEntity.ok(deliveryInfo); + } +} diff --git a/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/DeliveryInfo.java b/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/DeliveryInfo.java new file mode 100644 index 0000000..50d8fad --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/DeliveryInfo.java @@ -0,0 +1,12 @@ +package commerce.mvc; + +import lombok.AllArgsConstructor; +import lombok.Data; +@Data +@AllArgsConstructor +public class DeliveryInfo { + + private int orderId; // 주문 ID + private String status; // 배송 상태 (예: 배송중, 배송완료, 배송지연) + +} diff --git a/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/MvcCommerceApplication.java b/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/MvcCommerceApplication.java new file mode 100644 index 0000000..796f4af --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/src/main/java/commerce/mvc/MvcCommerceApplication.java @@ -0,0 +1,13 @@ +package commerce.mvc; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MvcCommerceApplication { + + public static void main(String[] args) { + SpringApplication.run(MvcCommerceApplication.class, args); + } + +} diff --git a/week14/mvc-webflux/mvc-commerce/src/main/resources/application.properties b/week14/mvc-webflux/mvc-commerce/src/main/resources/application.properties new file mode 100644 index 0000000..31f4a19 --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=mvc-commerce diff --git a/week14/mvc-webflux/mvc-commerce/src/test/java/commerce/mvc/MvcCommerceApplicationTests.java b/week14/mvc-webflux/mvc-commerce/src/test/java/commerce/mvc/MvcCommerceApplicationTests.java new file mode 100644 index 0000000..30f4cac --- /dev/null +++ b/week14/mvc-webflux/mvc-commerce/src/test/java/commerce/mvc/MvcCommerceApplicationTests.java @@ -0,0 +1,13 @@ +package commerce.mvc; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class MvcCommerceApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/.gitattributes b/week14/rabbit-mq/RabbitAmqpTutorials/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/.gitignore b/week14/rabbit-mq/RabbitAmqpTutorials/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/build.gradle b/week14/rabbit-mq/RabbitAmqpTutorials/build.gradle new file mode 100644 index 0000000..f5d1c97 --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/build.gradle @@ -0,0 +1,29 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.4.4' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'org.springframework' +version = '0.0.1-SNAPSHOT' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-amqp' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.amqp:spring-rabbit-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/gradle/wrapper/gradle-wrapper.jar b/week14/rabbit-mq/RabbitAmqpTutorials/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/week14/rabbit-mq/RabbitAmqpTutorials/gradle/wrapper/gradle-wrapper.jar differ diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/gradle/wrapper/gradle-wrapper.properties b/week14/rabbit-mq/RabbitAmqpTutorials/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/gradlew b/week14/rabbit-mq/RabbitAmqpTutorials/gradlew new file mode 100755 index 0000000..41693d0 --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.h +# See the LiceRabbitAmqpTutorials-0.0.1-SNAPSHOT.jarnse for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/gradlew.bat b/week14/rabbit-mq/RabbitAmqpTutorials/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/settings.gradle b/week14/rabbit-mq/RabbitAmqpTutorials/settings.gradle new file mode 100644 index 0000000..0df669d --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'RabbitAmqpTutorials' diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/RabbitAmqpTutorialsApplication.java b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/RabbitAmqpTutorialsApplication.java new file mode 100644 index 0000000..bca561e --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/RabbitAmqpTutorialsApplication.java @@ -0,0 +1,33 @@ +package org.springframework.rabbitamqptutorials; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.rabbitamqptutorials.tutorials.tut1.RabbitAmqpTutorialsRunner; + +@SpringBootApplication +@EnableScheduling +public class RabbitAmqpTutorialsApplication { + + @Profile("usage_message") + @Bean + public CommandLineRunner usage() { + return args -> { + System.out.println("This app uses Spring Profiles to control its behavior.\n"); + System.out.println("Sample usage: java -jar rabbit-tutorials.jar --spring.profiles.active=hello-world,sender"); + }; + } + + @Profile("!usage_message") + @Bean + public CommandLineRunner tutorial() { + return new RabbitAmqpTutorialsRunner(); + } + + public static void main(String[] args) throws Exception { + SpringApplication.run(RabbitAmqpTutorialsApplication.class, args); + } +} diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/RabbitAmqpTutorialsRunner.java b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/RabbitAmqpTutorialsRunner.java new file mode 100644 index 0000000..458aed6 --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/RabbitAmqpTutorialsRunner.java @@ -0,0 +1,22 @@ +package org.springframework.rabbitamqptutorials.tutorials.tut1; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.ConfigurableApplicationContext; + +public class RabbitAmqpTutorialsRunner implements CommandLineRunner { + + @Value("${tutorial.client.duration:0}") + private int duration; + + @Autowired + private ConfigurableApplicationContext ctx; + + @Override + public void run(String... arg0) throws Exception { + System.out.println("Ready ... running for " + duration + "ms"); + Thread.sleep(duration); + ctx.close(); + } +} diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Config.java b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Config.java new file mode 100644 index 0000000..205d371 --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Config.java @@ -0,0 +1,28 @@ +package org.springframework.rabbitamqptutorials.tutorials.tut1; + +import org.springframework.amqp.core.Queue; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Profile({"tut1","hello-world"}) +@Configuration +public class Tut1Config { + + @Bean + public Queue hello() { + return new Queue("hello"); + } + + @Profile("receiver") + @Bean + public Tut1Receiver receiver() { + return new Tut1Receiver(); + } + + @Profile("sender") + @Bean + public Tut1Sender sender() { + return new Tut1Sender(); + } +} diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Receiver.java b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Receiver.java new file mode 100644 index 0000000..1bec200 --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Receiver.java @@ -0,0 +1,13 @@ +package org.springframework.rabbitamqptutorials.tutorials.tut1; + +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; + +@RabbitListener(queues = "hello") +public class Tut1Receiver { + + @RabbitHandler + public void receive(String in) { + System.out.println(" [x] Received '" + in + "'"); + } +} diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Sender.java b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Sender.java new file mode 100644 index 0000000..90e583a --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/java/org/springframework/rabbitamqptutorials/tutorials/tut1/Tut1Sender.java @@ -0,0 +1,22 @@ +package org.springframework.rabbitamqptutorials.tutorials.tut1;// Sender + +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; + +public class Tut1Sender { + + @Autowired + private RabbitTemplate template; + + @Autowired + private Queue queue; + + @Scheduled(fixedDelay = 1000, initialDelay = 500) + public void send() { + String message = "Hello World!"; + this.template.convertAndSend(queue.getName(), message); + System.out.println(" [x] Sent '" + message + "'"); + } +} diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/src/main/resources/application.yml b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/resources/application.yml new file mode 100644 index 0000000..d498402 --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/src/main/resources/application.yml @@ -0,0 +1,16 @@ +spring: + profiles: + active: usage_message + rabbitmq: + host: localhost + port: 5672 + username: guest + password: guest +logging: + level: + org: ERROR + +tutorial: + client: + duration: 10000 + diff --git a/week14/rabbit-mq/RabbitAmqpTutorials/src/test/java/org/springframework/rabbitamqptutorials/RabbitAmqpTutorialsApplicationTests.java b/week14/rabbit-mq/RabbitAmqpTutorials/src/test/java/org/springframework/rabbitamqptutorials/RabbitAmqpTutorialsApplicationTests.java new file mode 100644 index 0000000..8018079 --- /dev/null +++ b/week14/rabbit-mq/RabbitAmqpTutorials/src/test/java/org/springframework/rabbitamqptutorials/RabbitAmqpTutorialsApplicationTests.java @@ -0,0 +1,13 @@ +package org.springframework.rabbitamqptutorials; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class RabbitAmqpTutorialsApplicationTests { + + @Test + void contextLoads() { + } + +}