├── .gitattributes
├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── fastcampus-spring-cloud.iml
├── jarRepositories.xml
├── misc.xml
├── modules.xml
├── modules
│ └── fastcam-spring-config
│ │ ├── fastcampus-spring-cloud.fastcam-spring-config.iml
│ │ ├── fastcampus-spring-cloud.fastcam-spring-config.main.iml
│ │ └── fastcampus-spring-cloud.fastcam-spring-config.test.iml
└── vcs.xml
├── fastcam-feignclient
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── src
│ ├── main
│ ├── java
│ │ └── info
│ │ │ └── thecodinglive
│ │ │ └── feignclient
│ │ │ ├── FeignApp.java
│ │ │ ├── config
│ │ │ ├── ConfigController.java
│ │ │ ├── ConfigProp.java
│ │ │ ├── EurekaFeignClientConfig.java
│ │ │ └── MapServiceFeignClientConfig.java
│ │ │ ├── eureka
│ │ │ └── PhotoAppController.java
│ │ │ └── mapService
│ │ │ ├── KakaoLocalSearchClient.java
│ │ │ ├── LocalSearchResponse.java
│ │ │ ├── LocalSearchResponseWrapper.java
│ │ │ └── LocalSearchService.java
│ └── resources
│ │ └── application.yml
│ └── test
│ └── java
│ └── info
│ └── thecodinglive
│ └── feignClient
│ └── mapService
│ ├── KakoLocalSearchTest.java
│ └── MapServiceTest.java
├── fastcam-photoapp
├── .gitignore
├── build.gradle.kts
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── lombok.config
└── src
│ ├── main
│ ├── java
│ │ └── info
│ │ │ └── thecodinglive
│ │ │ └── photoapp
│ │ │ ├── PhotoApp.java
│ │ │ ├── api
│ │ │ ├── FeignController.java
│ │ │ ├── MDCLogFilter.java
│ │ │ └── post
│ │ │ │ ├── Content.java
│ │ │ │ ├── HeadController.java
│ │ │ │ ├── MdcController.java
│ │ │ │ ├── NewServiceController.java
│ │ │ │ ├── PostImage.java
│ │ │ │ └── PostReadController.java
│ │ │ ├── circuit
│ │ │ ├── InternalServerErrorException.java
│ │ │ └── MessageController.java
│ │ │ ├── config
│ │ │ ├── MDCKeys.java
│ │ │ ├── MutlpartConfig.java
│ │ │ ├── PhotoAppProperties.java
│ │ │ ├── SwaggerConfig.java
│ │ │ └── WebConfig.java
│ │ │ └── storage
│ │ │ ├── FastcamJacksonConverter.java
│ │ │ ├── FileUploadController.java
│ │ │ ├── FileUploadService.java
│ │ │ ├── FileWriter.java
│ │ │ ├── ImageFile.java
│ │ │ ├── ImageFileUploadResult.java
│ │ │ └── gcp
│ │ │ ├── GCPStorageComponent.java
│ │ │ ├── GcpFileDownloadController.java
│ │ │ ├── GcpFileUploadController.java
│ │ │ └── GcpStorageService.java
│ └── resources
│ │ ├── admin.yml
│ │ ├── application.yml
│ │ ├── test-down.jpg
│ │ └── test.jpg
│ └── test
│ └── java
│ └── info
│ └── thecodinglive
│ └── photoapp
│ ├── DateFormatTest.java
│ └── GcpStorageServiceTest.java
├── fastcam-resilience4j-server
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── resilience4j
│ │ └── provide
│ │ ├── ProvideApp.java
│ │ └── service
│ │ ├── BulkHeadController.java
│ │ ├── CircuitController.java
│ │ └── InternalServerErrorException.java
│ └── resources
│ └── application.yml
├── fastcam-resilience4j
├── build.gradle.kts
├── docker
│ ├── dashboard.json
│ ├── docker-compose.yml
│ ├── grafana.env
│ └── prometheus.yml
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── resilience4j
│ │ ├── ResilienceApp.java
│ │ ├── config
│ │ ├── CircuitConfig.java
│ │ └── WebConfig.java
│ │ └── service
│ │ ├── BulkHeadController.java
│ │ └── circuit
│ │ ├── CircuitAnnotationService.java
│ │ ├── CircuitController.java
│ │ ├── HttpBinService.java
│ │ └── MyException.java
│ └── resources
│ └── application.yml
├── fastcam-spring-admin
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── admin
│ │ └── AdminServerApp.java
│ └── resources
│ ├── application.yml
│ └── eureka-client.yml
├── fastcam-spring-apigw
├── build.gradle.kts
├── gradlew
├── gradlew.bat
├── out
│ └── production
│ │ └── resources
│ │ ├── api-gw.yml
│ │ ├── application.yml
│ │ └── eureka-client.yml
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── spgw
│ │ ├── SpGwApp.java
│ │ └── filters
│ │ └── errors
│ │ ├── GWErrorResponse.java
│ │ └── GlobalExceptionHandler.java
│ └── resources
│ ├── api-gw.yml
│ ├── application.yml
│ └── eureka-client.yml
├── fastcam-spring-config-consumer
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── cloud
│ │ ├── ConfigConsumerApp.java
│ │ └── config
│ │ ├── ConfigChangeListener.java
│ │ ├── ConfigController.java
│ │ ├── ConfigMgmt.java
│ │ ├── ConfigProp.java
│ │ └── TestController.java
│ └── resources
│ ├── application.yml
│ └── bootstrap.yml
├── fastcam-spring-config
├── build.gradle.kts
├── gradlew
├── gradlew.bat
├── out
│ └── production
│ │ └── resources
│ │ ├── app12.yml
│ │ ├── application.properties
│ │ ├── application.yml
│ │ └── config
│ │ ├── mongo-dev.yml
│ │ └── mongo-real.yml
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── cloud
│ │ └── ConfigServer.java
│ └── resources
│ ├── application.yml
│ └── config
│ ├── mongo-default.yml
│ ├── mongo-dev.yml
│ └── mongo-real.yml
├── fastcam-spring-eureka
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── eureka
│ │ └── EurekaServerApp.java
│ └── resources
│ └── application.yml
├── fastcam-spring-kafka
├── build.gradle.kts
├── docker
│ └── docker-compose.yml
├── gradlew
├── gradlew.bat
├── out
│ └── production
│ │ └── resources
│ │ └── application.yml
└── src
│ ├── main
│ ├── java
│ │ └── info
│ │ │ └── thecodinglive
│ │ │ └── kafka
│ │ │ ├── KafkaApp.java
│ │ │ ├── eventService
│ │ │ ├── EventController.java
│ │ │ ├── FastcamJacksonConverter.java
│ │ │ ├── MyEvent.java
│ │ │ └── MyEventService.java
│ │ │ ├── receiver
│ │ │ └── KafkaReceiver.java
│ │ │ └── sender
│ │ │ └── KafkaProducer.java
│ └── resources
│ │ └── application.yml
│ └── test
│ └── java
│ └── info
│ └── thecodinglive
│ └── kafka
│ └── SenderTest.java
├── fastcam-spring-rabbitmq
├── build.gradle.kts
├── docker
│ └── docker-compose.yml
├── gradlew
├── gradlew.bat
├── lombok.config
├── out
│ └── production
│ │ └── resources
│ │ ├── application.yml
│ │ └── docker
│ │ └── docker-compose.yml
└── src
│ ├── main
│ ├── java
│ │ └── info
│ │ │ └── thecodinglive
│ │ │ └── rabbitmq
│ │ │ ├── RabbitMQApp.java
│ │ │ ├── config
│ │ │ ├── FastcamRabbitQueue.java
│ │ │ └── RabbitMQConfig.java
│ │ │ ├── receiver
│ │ │ └── RabbitMQReceiver.java
│ │ │ ├── sample
│ │ │ └── model
│ │ │ │ └── MyTask.java
│ │ │ └── sender
│ │ │ ├── MessageController.java
│ │ │ └── RabbitMessagePublisher.java
│ └── resources
│ │ ├── application.yml
│ │ └── docker
│ │ └── docker-compose.yml
│ └── test
│ └── java
│ └── info
│ └── thecodinglive
│ └── rabbitmq
│ └── sender
│ └── RabbitMQSenderTest.java
├── fastcam-spring-sleuth
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── monitoring
│ │ ├── SpringSleuth.java
│ │ ├── config
│ │ └── SleuthConfig.java
│ │ └── sleuth
│ │ └── TestController.java
│ └── resources
│ └── application.yml
├── fastcam-spring-utils
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ └── java
│ └── info
│ └── thecodinglive
│ └── utils
│ └── jackson
│ └── FastcamJacksonConverter.java
├── fastcam-spring-vault
├── build.gradle.kts
├── gradlew
├── gradlew.bat
└── src
│ └── main
│ ├── java
│ └── info
│ │ └── thecodinglive
│ │ └── cloud
│ │ ├── app
│ │ └── SpringVaultApp.java
│ │ └── config
│ │ └── MySqlConfig.java
│ └── resources
│ ├── application.yml
│ ├── bootstrap.yml
│ └── config
│ ├── mongo-default.yml
│ ├── mongo-dev.yml
│ └── mongo-real.yml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── readme.md
└── settings.gradle.kts
/.gitattributes:
--------------------------------------------------------------------------------
1 | #
2 | # https://help.github.com/articles/dealing-with-line-endings/
3 | #
4 | # These are explicitly windows files and should use crlf
5 | *.bat text eol=crlf
6 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Java template
2 | *.class
3 |
4 | # Mobile Tools for Java (J2ME)
5 | .mtj.tmp/
6 |
7 | # Package Files #
8 | *.jar
9 | *.war
10 | *.ear
11 |
12 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
13 | hs_err_pid*
14 | ### JetBrains template
15 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
16 |
17 | *.iml
18 |
19 | ## Directory-based project format:
20 | .idea/
21 | # if you remove the above rule, at least ignore the following:
22 |
23 | # User-specific stuff:
24 | # .idea/workspace.xml
25 | # .idea/tasks.xml
26 | # .idea/dictionaries
27 |
28 | # Sensitive or high-churn files:
29 | # .idea/dataSources.ids
30 | # .idea/dataSources.xml
31 | # .idea/sqlDataSources.xml
32 | # .idea/dynamic.xml
33 | # .idea/uiDesigner.xml
34 |
35 | # Gradle:
36 | # .idea/gradle.xml
37 | # .idea/libraries
38 |
39 | # Mongo Explorer plugin:
40 | # .idea/mongoSettings.xml
41 |
42 | ## File-based project format:
43 | *.ipr
44 | *.iws
45 |
46 | ## Plugin-specific files:
47 |
48 | # IntelliJ
49 | out/
50 |
51 | # mpeltonen/sbt-idea plugin
52 | .idea_modules/
53 |
54 | # JIRA plugin
55 | atlassian-ide-plugin.xml
56 |
57 | # Crashlytics plugin (for Android Studio and IntelliJ)
58 | com_crashlytics_export_strings.xml
59 | crashlytics.properties
60 | crashlytics-build.properties
61 | <<<<<<< HEAD
62 | ### Gradle template
63 | =======
64 | fabric.properties
65 |
66 | # Editor-based Rest Client
67 | .idea/httpRequests
68 |
69 | # Android studio 3.1+ serialized cache file
70 | .idea/caches/build_file_checksums.ser
71 |
72 | ### Intellij Patch ###
73 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
74 |
75 | *.iml
76 | modules.xml
77 | .idea/misc.xml
78 | *.ipr
79 |
80 | # Sonarlint plugin
81 | # https://plugins.jetbrains.com/plugin/7973-sonarlint
82 | .idea/**/sonarlint/
83 |
84 | # SonarQube Plugin
85 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
86 | .idea/**/sonarIssues.xml
87 |
88 | # Markdown Navigator plugin
89 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
90 | .idea/**/markdown-navigator.xml
91 | .idea/**/markdown-navigator-enh.xml
92 | .idea/**/markdown-navigator/
93 |
94 | # Cache file creation bug
95 | # See https://youtrack.jetbrains.com/issue/JBR-2257
96 | .idea/$CACHE_FILE$
97 |
98 | # CodeStream plugin
99 | # https://plugins.jetbrains.com/plugin/12206-codestream
100 | .idea/codestream.xml
101 |
102 | ### Java ###
103 | # Compiled class file
104 | *.class
105 |
106 | # Log file
107 | *.log
108 |
109 | # BlueJ files
110 | *.ctxt
111 |
112 | # Mobile Tools for Java (J2ME)
113 | .mtj.tmp/
114 |
115 | # Package Files #
116 | *.jar
117 | *.war
118 | *.nar
119 | *.ear
120 | *.zip
121 | *.tar.gz
122 | *.rar
123 |
124 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
125 | hs_err_pid*
126 |
127 | ### Gradle ###
128 | >>>>>>> spring-admin
129 | .gradle
130 | build/
131 |
132 | # Ignore Gradle GUI config
133 | gradle-app.setting
134 |
135 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
136 | !gradle-wrapper.jar
137 | ### Eclipse template
138 | *.pydevproject
139 | .metadata
140 | .gradle
141 | bin/
142 | tmp/
143 | *.tmp
144 | *.bak
145 | *.swp
146 | *~.nib
147 | local.properties
148 | .settings/
149 | .loadpath
150 |
151 | # Eclipse Core
152 | .project
153 |
154 | # External tool builders
155 | .externalToolBuilders/
156 |
157 | # Locally stored "Eclipse launch configurations"
158 | *.launch
159 |
160 | # CDT-specific
161 | .cproject
162 |
163 | # JDT-specific (Eclipse Java Development Tools)
164 | .classpath
165 |
166 | # Java annotation processor (APT)
167 | .factorypath
168 |
169 | # PDT-specific
170 | .buildpath
171 |
172 | # sbteclipse plugin
173 | .target
174 |
175 | # TeXlipse plugin
176 | .texlipse
177 |
178 | # Created by .ignore support plugin (hsz.mobi)
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.idea/fastcampus-spring-cloud.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/modules/fastcam-spring-config/fastcampus-spring-cloud.fastcam-spring-config.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/fastcam-feignclient/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | plugins {
4 | id("org.springframework.boot") version "2.4.3"
5 | id("io.spring.dependency-management") version "1.0.11.RELEASE"
6 | kotlin("jvm") version "1.4.30"
7 | kotlin("plugin.spring") version "1.4.30"
8 | }
9 |
10 | group = "info.thecodinglive.feign"
11 | version = "0.0.1-SNAPSHOT"
12 | java.sourceCompatibility = JavaVersion.VERSION_11
13 |
14 | configurations {
15 | compileOnly {
16 | extendsFrom(configurations.annotationProcessor.get())
17 | }
18 | }
19 |
20 | repositories {
21 | jcenter()
22 | }
23 |
24 | dependencies {
25 | implementation("org.springframework.boot:spring-boot-starter-web")
26 | implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
27 |
28 | implementation("org.springframework.cloud:spring-cloud-config-client")
29 | implementation("org.springframework.cloud:spring-cloud-starter-bootstrap")
30 | implementation("org.springframework.boot:spring-boot-starter-actuator")
31 |
32 | compileOnly("org.projectlombok:lombok")
33 | annotationProcessor("org.projectlombok:lombok")
34 |
35 |
36 | implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
37 | //test
38 |
39 | testImplementation("org.springframework.boot:spring-boot-starter-test")
40 | }
41 |
42 | dependencyManagement {
43 | imports {
44 | mavenBom ("org.springframework.cloud:spring-cloud-dependencies:2020.0.1")
45 | }
46 | }
47 |
48 |
49 | tasks.withType {
50 | kotlinOptions {
51 | freeCompilerArgs = listOf("-Xjsr305=strict")
52 | jvmTarget = "11"
53 | }
54 | }
55 |
56 | tasks.withType {
57 | useJUnitPlatform()
58 | }
59 |
--------------------------------------------------------------------------------
/fastcam-feignclient/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/FeignApp.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
10 |
11 |
12 | @EnableDiscoveryClient
13 | @SpringBootApplication
14 | public class FeignApp {
15 | public static void main(String ar[]) {
16 | SpringApplication.run(FeignApp.class, ar);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/config/ConfigController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.config;
2 |
3 |
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.cloud.context.config.annotation.RefreshScope;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 |
12 | @Slf4j
13 | @RestController
14 | public class ConfigController {
15 | @Autowired
16 | private ConfigProp configProp;
17 |
18 |
19 | @GetMapping("/v1/check/prop")
20 | public String findPropMessage() {
21 | log.info("config:: {}", configProp.toString());
22 | return "ok";
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/config/ConfigProp.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.config;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | @Data
10 | @EnableConfigurationProperties
11 | @ConfigurationProperties(prefix = "mongodbserver")
12 | public class ConfigProp {
13 | private String url;
14 | private String username;
15 | private String password;
16 | }
17 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/config/EurekaFeignClientConfig.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.config;
2 |
3 | import org.springframework.cloud.openfeign.EnableFeignClients;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | @Configuration
7 | @EnableFeignClients(basePackages = "info.thecodinglive.feignclient.eureka")
8 | public class EurekaFeignClientConfig {
9 | }
10 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/config/MapServiceFeignClientConfig.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.config;
2 |
3 | import org.springframework.cloud.openfeign.EnableFeignClients;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | @Configuration
7 | @EnableFeignClients(basePackages = "info.thecodinglive.feignclient.mapService")
8 | public class MapServiceFeignClientConfig {
9 | }
10 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/eureka/PhotoAppController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.eureka;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.cloud.openfeign.FeignClient;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | @RestController
9 | public class PhotoAppController {
10 |
11 | @Autowired
12 | PhotoClient photoClient;
13 |
14 | @GetMapping("/photo")
15 | public String findServer() {
16 | return photoClient.sayHello();
17 | }
18 |
19 |
20 |
21 | @FeignClient("photoapp") //도메인 정보
22 | interface PhotoClient {
23 | @GetMapping("/clients")
24 | String sayHello();
25 | }
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/mapService/KakaoLocalSearchClient.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.mapService;
2 |
3 | import org.springframework.cloud.openfeign.FeignClient;
4 | import org.springframework.http.ResponseEntity;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RequestHeader;
7 | import org.springframework.web.bind.annotation.RequestParam;
8 |
9 | @FeignClient(value = "kakao", url = "http://dapi.kakao.com")
10 | /**
11 | * @See https://developers.kakao.com/docs/latest/ko/local/dev-guide
12 | * **/
13 | public interface KakaoLocalSearchClient {
14 | @GetMapping("/v2/local/search/keyword.json")
15 | ResponseEntity findLocationNotIncludeHeader(String query); //fail not include header
16 |
17 | @GetMapping("/v2/local/search/keyword.json")
18 | ResponseEntity findLocationWithHeader(@RequestHeader("Authorization") String authHeader,
19 | @RequestParam("query") String query);
20 |
21 | @GetMapping("/v2/local/search/keyword.json")
22 | ResponseEntity findLocation(@RequestHeader("Authorization") String authHeader,
23 | @RequestParam("query") String query);
24 |
25 | @GetMapping("/v2/local/search/keyword.json")
26 | ResponseEntity findResponse(@RequestHeader("Authorization") String authHeader,
27 | @RequestParam("query") String query);
28 | }
29 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/mapService/LocalSearchResponse.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.mapService;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | @JsonIgnoreProperties(ignoreUnknown = true)
7 | public class LocalSearchResponse {
8 | private Integer id;
9 | @JsonProperty("address_name")
10 | private String addressName;
11 | @JsonProperty("category_group_name")
12 | private String categoryGroupName;
13 | @JsonProperty("category_group_code")
14 | private String categoryGroupCode;
15 | @JsonProperty("category_name")
16 | private String categoryName;
17 | private String distance;
18 | private String phone;
19 | @JsonProperty("place_name")
20 | private String placeName;
21 | @JsonProperty("place_url")
22 | private String placeUrl;
23 | @JsonProperty("road_address_name")
24 | private String roadAddressName;
25 | private String x;
26 | private String y;
27 |
28 | public LocalSearchResponse() {
29 | }
30 |
31 | public void setId(Integer id) {
32 | this.id = id;
33 | }
34 |
35 | public void setAddressName(String addressName) {
36 | this.addressName = addressName;
37 | }
38 |
39 | public void setCategoryGroupName(String categoryGroupName) {
40 | this.categoryGroupName = categoryGroupName;
41 | }
42 |
43 | public void setCategoryGroupCode(String categoryGroupCode) {
44 | this.categoryGroupCode = categoryGroupCode;
45 | }
46 |
47 | public void setCategoryName(String categoryName) {
48 | this.categoryName = categoryName;
49 | }
50 |
51 | public void setDistance(String distance) {
52 | this.distance = distance;
53 | }
54 |
55 | public void setPhone(String phone) {
56 | this.phone = phone;
57 | }
58 |
59 | public void setPlaceName(String placeName) {
60 | this.placeName = placeName;
61 | }
62 |
63 | public void setPlaceUrl(String placeUrl) {
64 | this.placeUrl = placeUrl;
65 | }
66 |
67 | public void setRoadAddressName(String roadAddressName) {
68 | this.roadAddressName = roadAddressName;
69 | }
70 |
71 | public void setX(String x) {
72 | this.x = x;
73 | }
74 |
75 | public void setY(String y) {
76 | this.y = y;
77 | }
78 |
79 | public Integer getId() {
80 | return id;
81 | }
82 |
83 | public String getAddressName() {
84 | return addressName;
85 | }
86 |
87 | public String getCategoryGroupName() {
88 | return categoryGroupName;
89 | }
90 |
91 | public String getCategoryGroupCode() {
92 | return categoryGroupCode;
93 | }
94 |
95 | public String getCategoryName() {
96 | return categoryName;
97 | }
98 |
99 | public String getDistance() {
100 | return distance;
101 | }
102 |
103 | public String getPhone() {
104 | return phone;
105 | }
106 |
107 | public String getPlaceName() {
108 | return placeName;
109 | }
110 |
111 | public String getPlaceUrl() {
112 | return placeUrl;
113 | }
114 |
115 | public String getRoadAddressName() {
116 | return roadAddressName;
117 | }
118 |
119 | public String getX() {
120 | return x;
121 | }
122 |
123 | public String getY() {
124 | return y;
125 | }
126 |
127 | @Override
128 | public String toString() {
129 | return "LocalSearchResponse{" +
130 | "id=" + id +
131 | ", addressName='" + addressName + '\'' +
132 | ", categoryGroupName='" + categoryGroupName + '\'' +
133 | ", categoryGroupCode='" + categoryGroupCode + '\'' +
134 | ", categoryName='" + categoryName + '\'' +
135 | ", distance='" + distance + '\'' +
136 | ", phone='" + phone + '\'' +
137 | ", placeName='" + placeName + '\'' +
138 | ", placeUrl='" + placeUrl + '\'' +
139 | ", roadAddressName='" + roadAddressName + '\'' +
140 | ", x='" + x + '\'' +
141 | ", y='" + y + '\'' +
142 | '}';
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/mapService/LocalSearchResponseWrapper.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.mapService;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 |
5 | import java.util.List;
6 |
7 | public class LocalSearchResponseWrapper {
8 | public LocalSearchResponseWrapper() {
9 | }
10 |
11 | public LocalSearchResponseWrapper(List localSearchResponse, LocalSearchMeta localSearchMeta) {
12 | this.localSearchResponse = localSearchResponse;
13 | this.localSearchMeta = localSearchMeta;
14 | }
15 |
16 | @JsonProperty("documents")
17 | private List localSearchResponse;
18 | @JsonProperty("meta")
19 | private LocalSearchMeta localSearchMeta;
20 |
21 | public List getLocalSearchResponse() {
22 | return localSearchResponse;
23 | }
24 |
25 | public void setLocalSearchResponse(List localSearchResponse) {
26 | this.localSearchResponse = localSearchResponse;
27 | }
28 |
29 | public LocalSearchMeta getLocalSearchMeta() {
30 | return localSearchMeta;
31 | }
32 |
33 | public void setLocalSearchMeta(LocalSearchMeta localSearchMeta) {
34 | this.localSearchMeta = localSearchMeta;
35 | }
36 |
37 | private static class LocalSearchMeta {}
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/java/info/thecodinglive/feignclient/mapService/LocalSearchService.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignclient.mapService;
2 |
3 | import org.springframework.http.ResponseEntity;
4 | import org.springframework.stereotype.Service;
5 |
6 | @Service
7 | public class LocalSearchService {
8 | private static final String authKey = "KakaoAK 464b4c25cadd87ca45f1ea99a7822608";
9 | private KakaoLocalSearchClient kakaoLocalSearchClient;
10 |
11 | public LocalSearchService(KakaoLocalSearchClient kakaoLocalSearchClient) {
12 | this.kakaoLocalSearchClient = kakaoLocalSearchClient;
13 | }
14 |
15 | public ResponseEntity findLocationRetrunMap(String keyword) {
16 | return kakaoLocalSearchClient.findLocation(authKey, keyword);
17 | }
18 |
19 | public ResponseEntity findResponse(String keyword) {
20 | return kakaoLocalSearchClient.findResponse(authKey, keyword);
21 | }
22 |
23 |
24 |
25 | public ResponseEntity findLocaion(String keyword) {
26 | return kakaoLocalSearchClient.findLocationWithHeader(authKey, keyword);
27 | }
28 |
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | #https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html#_feign_logging
2 |
3 | feign:
4 | cleint:
5 | config:
6 | default:
7 | connectionTimeout: 1000
8 | readTimeout: 3000
9 | loggerLevel: FULL
10 | logging:
11 | level:
12 | info.thecodinglive.feignclient: debug
13 |
14 |
15 |
16 | server.port: 8083
17 |
18 | spring.config.import:
19 | configserver: http://127.0.0.1:8888
20 | spring.profiles.active: dev
21 |
22 | spring.cloud:
23 | config.enabled: true
24 | config.name: mongo
25 | #import=configserver: http://localhost:8888
26 | #fail-fast: true
27 |
28 | spring.application.name: fastCamFeign
29 |
30 |
31 |
32 | eureka:
33 | client:
34 | serviceUrl:
35 | defaultZone: http://localhost:8761/eureka/
36 | instance:
37 | leaseRenewalIntervalInSeconds: 10
38 | metadataMap:
39 | instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
40 |
41 |
--------------------------------------------------------------------------------
/fastcam-feignclient/src/test/java/info/thecodinglive/feignClient/mapService/MapServiceTest.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.feignClient.mapService;
2 |
3 | import info.thecodinglive.feignclient.mapService.LocalSearchResponse;
4 | import info.thecodinglive.feignclient.mapService.LocalSearchResponseWrapper;
5 | import info.thecodinglive.feignclient.mapService.LocalSearchService;
6 | import org.junit.jupiter.api.Assertions;
7 | import org.junit.jupiter.api.Test;
8 | import org.junit.jupiter.api.extension.ExtendWith;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 | import org.springframework.test.context.junit.jupiter.SpringExtension;
12 |
13 | import java.util.List;
14 | import java.util.stream.Collectors;
15 |
16 | @ExtendWith(SpringExtension.class)
17 | @SpringBootTest
18 | public class MapServiceTest {
19 | @Autowired
20 | LocalSearchService localSearchService;
21 | Integer locationId = 26358363;
22 |
23 | @Test
24 | public void localSearch() {
25 |
26 | //given
27 | //12455726
28 | LocalSearchResponse searchRespose = new LocalSearchResponse();
29 |
30 | LocalSearchResponseWrapper localSearchResponseWrapper = localSearchService
31 | .findLocationRetrunMap("율동공원").getBody();
32 |
33 | System.out.println( localSearchResponseWrapper.getLocalSearchResponse());
34 | //
35 | // //when
36 | List localSearchResultList = localSearchResponseWrapper.getLocalSearchResponse().stream()
37 | .filter( p -> p.getId().equals(locationId))
38 | .collect(Collectors.toList());
39 | //
40 | Assertions.assertEquals(1, localSearchResultList.size(), "사이즈는 1이어야 합니다.");
41 |
42 | localSearchResultList.forEach( p -> {
43 | searchRespose.setPlaceUrl(p.getPlaceUrl());
44 | searchRespose.setPhone(p.getPhone());
45 | });
46 |
47 | String searchLocationResult = String.format("전화번호: %s, 지도url: %s", searchRespose.getPhone(),
48 | searchRespose.getPlaceUrl());
49 |
50 | System.out.println(searchLocationResult);
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/fastcam-photoapp/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | .gradle
3 | build/
4 | !gradle/wrapper/gradle-wrapper.jar
5 | !**/src/main/**/build/
6 | !**/src/test/**/build/
7 |
8 | ### STS ###
9 | .apt_generated
10 | .classpath
11 | .factorypath
12 | .project
13 | .settings
14 | .springBeans
15 | .sts4-cache
16 | bin/
17 | !**/src/main/**/bin/
18 | !**/src/test/**/bin/
19 |
20 | ### IntelliJ IDEA ###
21 | .idea
22 | *.iws
23 | *.iml
24 | *.ipr
25 | out/
26 | !**/src/main/**/out/
27 | !**/src/test/**/out/
28 |
29 | ### NetBeans ###
30 | /nbproject/private/
31 | /nbbuild/
32 | /dist/
33 | /nbdist/
34 | /.nb-gradle/
35 |
36 | ### VS Code ###
37 | .vscode/
38 |
--------------------------------------------------------------------------------
/fastcam-photoapp/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | plugins {
4 | id("org.springframework.boot") version "2.4.3"
5 | id("io.spring.dependency-management") version "1.0.11.RELEASE"
6 | kotlin("jvm") version "1.4.30"
7 | kotlin("plugin.spring") version "1.4.30"
8 | }
9 |
10 | group = "info.thecodinglive.photoapp"
11 | version = "0.0.1-SNAPSHOT"
12 | java.sourceCompatibility = JavaVersion.VERSION_11
13 |
14 | configurations {
15 | compileOnly {
16 | extendsFrom(configurations.annotationProcessor.get())
17 | }
18 | }
19 |
20 | repositories {
21 | mavenCentral()
22 | }
23 |
24 | dependencies {
25 | implementation(project(":fastcam-spring-utils"))
26 | implementation("org.springframework.boot:spring-boot-starter-web")
27 | implementation("org.springframework.boot:spring-boot-starter-actuator")
28 | implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
29 | implementation("org.jetbrains.kotlin:kotlin-reflect")
30 | implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
31 | implementation("commons-fileupload:commons-fileupload:1.4")
32 | implementation("io.springfox:springfox-swagger2:2.9.2")
33 | implementation("io.springfox:springfox-swagger-ui:2.9.2")
34 |
35 | implementation ("org.springframework.cloud:spring-cloud-gcp-starter-storage")
36 |
37 | implementation("org.springframework.cloud:spring-cloud-config:3.0.1")
38 | implementation("org.springframework.cloud:spring-cloud-context:3.0.1")
39 | implementation("org.springframework.boot:spring-boot-starter-actuator")
40 |
41 |
42 | implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
43 | implementation ("org.springframework.cloud:spring-cloud-gcp-starter-storage")
44 |
45 | implementation("org.springframework.cloud:spring-cloud-starter-sleuth")
46 | implementation("org.springframework.cloud:spring-cloud-sleuth-zipkin")
47 | implementation ("de.codecentric:spring-boot-admin-starter-client:2.4.0")
48 |
49 |
50 | compileOnly("org.projectlombok:lombok")
51 | annotationProcessor("org.projectlombok:lombok")
52 | testImplementation("org.springframework.boot:spring-boot-starter-test")
53 | }
54 |
55 | dependencyManagement {
56 | imports {
57 | mavenBom ("org.springframework.cloud:spring-cloud-dependencies:2020.0.1")
58 | mavenBom ("org.springframework.cloud:spring-cloud-gcp-dependencies:1.2.7.RELEASE")
59 | mavenBom ("org.springframework.cloud:spring-cloud-dependencies:2020.0.1")
60 | }
61 | }
62 |
63 | tasks.withType {
64 | kotlinOptions {
65 | freeCompilerArgs = listOf("-Xjsr305=strict")
66 | jvmTarget = "11"
67 | }
68 | }
69 |
70 | tasks.withType {
71 | useJUnitPlatform()
72 | }
--------------------------------------------------------------------------------
/fastcam-photoapp/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodinglive/fastcampus-example/8fc38f151532d7fc4168fd2cbb6e9cf42e9dd472/fastcam-photoapp/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/fastcam-photoapp/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/fastcam-photoapp/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/fastcam-photoapp/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/fastcam-photoapp/lombok.config:
--------------------------------------------------------------------------------
1 | lombok.log.fieldName = LOG
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/PhotoApp.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 |
7 | @EnableDiscoveryClient
8 | @SpringBootApplication
9 | public class PhotoApp {
10 | public static void main(String ar[]) {
11 | SpringApplication.run(PhotoApp.class, ar);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/api/FeignController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.api;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.cloud.client.ServiceInstance;
5 | import org.springframework.cloud.client.discovery.DiscoveryClient;
6 | import org.springframework.web.bind.annotation.GetMapping;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | import java.util.List;
10 |
11 | @RestController
12 | public class FeignController {
13 | @Autowired
14 | DiscoveryClient discoveryClient;
15 |
16 | @GetMapping("/clients")
17 | public String welcome() {
18 | List instances = discoveryClient.getInstances("photoapp");
19 | ServiceInstance selectedInstance = instances.get(0);
20 |
21 | return "welcome to spring cloud:" + selectedInstance.getInstanceId() + ":" + selectedInstance.getPort();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/api/MDCLogFilter.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.api;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.slf4j.MDC;
5 | import org.springframework.stereotype.Component;
6 | import org.springframework.util.StringUtils;
7 |
8 | import javax.servlet.*;
9 | import javax.servlet.http.HttpServletRequest;
10 | import java.io.IOException;
11 | import java.util.UUID;
12 |
13 | @Slf4j
14 | public class MDCLogFilter implements Filter {
15 | @Override
16 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
17 | HttpServletRequest req = (HttpServletRequest) request;
18 |
19 | String requestId = UUID.randomUUID().toString();
20 | String requestUrl = req.getRequestURI();
21 | String userAgent = req.getHeader("User-Agent");
22 | String clientIP = getClientIP(req);
23 |
24 | MDC.put("requestId", requestId);
25 | MDC.put("requestUrl", requestUrl);
26 | MDC.put("userAgent", userAgent);
27 | MDC.put("clientIP", clientIP);
28 |
29 | chain.doFilter(req, response);
30 | }
31 |
32 | @Override
33 | public void init(FilterConfig filterConfig) throws ServletException {
34 | LOG.info("MDC filter initialize");
35 | }
36 |
37 | @Override
38 | public void destroy() {
39 | MDC.clear();
40 | }
41 |
42 |
43 | private String getClientIP(HttpServletRequest request) {
44 | String ip = request.getHeader("X-Forwarded-For");
45 | LOG.info("ip: {}", ip);
46 |
47 | if(!StringUtils.hasLength(ip)) {
48 | ip = request.getRemoteAddr();
49 | }
50 | return ip;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/api/post/Content.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.api.post;
2 |
3 | import lombok.*;
4 | import org.springframework.util.Assert;
5 |
6 |
7 | @EqualsAndHashCode
8 | @Getter
9 | @ToString
10 | @Builder
11 | public class Content {
12 | private String contentId;
13 | private String title;
14 | private String body;
15 | private String writerNickName;
16 | private PostImage attachImage;
17 | }
18 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/api/post/HeadController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.api.post;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.http.ResponseEntity;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RequestHeader;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 |
10 |
11 | @Slf4j
12 | @RestController
13 | public class HeadController {
14 | @GetMapping("/v1.0/headservice")
15 | public ResponseEntity retriveHeadData(@RequestHeader(value = "X-PHOTO-API-VERSION") String apiVersion) {
16 | LOG.info("header data: {}", apiVersion);
17 | return ResponseEntity.ok("ok");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/api/post/MdcController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.api.post;
2 |
3 | import info.thecodinglive.photoapp.config.MDCKeys;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.slf4j.MDC;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | @Slf4j
11 | @RestController
12 | public class MdcController {
13 | @GetMapping("/v1/mdc")
14 | public ResponseEntity getData() {
15 | String requestId = MDC.get(MDCKeys.REQUEST_ID.getPropertyKey());
16 | String clientIP = MDC.get(MDCKeys.CLIENT_IP.getPropertyKey());
17 | String userAgent = MDC.get(MDCKeys.USER_AGENT.getPropertyKey());
18 |
19 | LOG.info("requestId: {} clientIP: {} userAgent {}", requestId, clientIP, userAgent);
20 |
21 | return ResponseEntity.ok("ok");
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/api/post/NewServiceController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.api.post;
2 |
3 | import org.springframework.web.bind.annotation.GetMapping;
4 | import org.springframework.web.bind.annotation.RestController;
5 |
6 | @RestController
7 | public class NewServiceController {
8 | @GetMapping("/v1.0/newservice")
9 | public String releaseNewService() {
10 | return "open new service";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/api/post/PostImage.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.api.post;
2 |
3 | import lombok.Builder;
4 | import lombok.Getter;
5 |
6 | @Getter
7 | @Builder
8 | public class PostImage {
9 | private String fileName;
10 | private String path;
11 | private Integer width;
12 | private Integer height;
13 | }
14 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/api/post/PostReadController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.api.post;
2 |
3 | import org.springframework.http.ResponseEntity;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.PostMapping;
6 | import org.springframework.web.bind.annotation.RequestBody;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | import java.util.UUID;
10 |
11 | @RestController
12 | public class PostReadController {
13 | @GetMapping("/v1.0/contents/1")
14 | public ResponseEntity> retriveInMemoryData() {
15 | Content content = Content.builder()
16 | .contentId(UUID.randomUUID().toString())
17 | .body("get data")
18 | .title("sp gateway test")
19 | .writerNickName("testnick")
20 | .build();
21 |
22 | return ResponseEntity.ok(content);
23 | }
24 |
25 | @GetMapping("/v1.0/contents/2")
26 | public ResponseEntity> throwTimeOut() {
27 | try {
28 | Thread.sleep(1000 * 30);
29 | } catch (Exception e) {
30 |
31 | }
32 | return ResponseEntity.ok("timeout");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/circuit/InternalServerErrorException.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.circuit;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | /**
7 | * InternalServerErrorException
8 | */
9 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
10 | public class InternalServerErrorException extends RuntimeException {
11 |
12 | public InternalServerErrorException(String msg) {
13 | super(msg);
14 | }
15 |
16 | }
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/circuit/MessageController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.circuit;
2 |
3 | import org.springframework.web.bind.annotation.GetMapping;
4 | import org.springframework.web.bind.annotation.RestController;
5 |
6 | @RestController
7 | public class MessageController {
8 | private static final int SECOND = 1000;
9 |
10 | @GetMapping("/")
11 | public String okay() {
12 | return "I'm fine.";
13 | }
14 |
15 | @GetMapping("/slow")
16 | public String slow() throws InterruptedException {
17 | Thread.sleep(SECOND);
18 | return "I'm fine, just slow";
19 | }
20 |
21 | @GetMapping("/error")
22 | public String error() {
23 | throw new InternalServerErrorException("I'm definitely not fine!");
24 | }
25 |
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/config/MDCKeys.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.config;
2 |
3 | public enum MDCKeys {
4 | /**
5 | * MDC.put("requestId", requestId);
6 | * MDC.put("requestUrl", requestUrl);
7 | * MDC.put("userAgent", userAgent);
8 | * MDC.put("clientIP", clientIP);
9 | */
10 |
11 | REQUEST_ID("requestId"),
12 | REQUEST_URL("requestUrl"),
13 | USER_AGENT("userAgent"),
14 | CLIENT_IP("clientIP");
15 |
16 | MDCKeys(String propertyKey) {
17 | this.propertyKey = propertyKey;
18 | }
19 |
20 | public String getPropertyKey() {
21 | return propertyKey;
22 | }
23 |
24 | private String propertyKey;
25 | }
26 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/config/MutlpartConfig.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.config;
2 |
3 |
4 | import lombok.Getter;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Value;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.context.annotation.Profile;
10 | import org.springframework.core.io.FileSystemResource;
11 | import org.springframework.web.multipart.commons.CommonsMultipartResolver;
12 |
13 | import java.io.IOException;
14 | import java.nio.charset.StandardCharsets;
15 |
16 |
17 | @Slf4j
18 | @Configuration
19 | public class MutlpartConfig {
20 |
21 | @Value("${photoapp.file.defaultPath}")
22 | public String defaultPath ="";
23 |
24 | @Bean
25 | public CommonsMultipartResolver multipartResolver() {
26 | CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
27 | multipartResolver.setResolveLazily(true);
28 | multipartResolver.setMaxUploadSize(1024 * 1024 * 10);
29 | multipartResolver.setDefaultEncoding(StandardCharsets.UTF_8.displayName());
30 | //try {
31 | LOG.info("path:" + defaultPath);
32 | //multipartResolver.setUploadTempDir(new FileSystemResource(defaultPath));
33 | // } catch (IOException e) {
34 | // LOG.error("init error", e);
35 | //}
36 | return multipartResolver;
37 | }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/config/PhotoAppProperties.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.config;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Value;
7 | import org.springframework.boot.context.properties.ConfigurationProperties;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 | import javax.annotation.PostConstruct;
11 |
12 | @Slf4j
13 | @Configuration
14 | @Setter
15 | @Getter
16 | public class PhotoAppProperties {
17 | @Value("${photoapp.file.defaultPath}")
18 | private String defaultPath;
19 |
20 | @PostConstruct
21 | private void init() {
22 | LOG.info("path:: {}",this.defaultPath);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/config/SwaggerConfig.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.config;
2 |
3 | import io.swagger.annotations.ApiOperation;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.http.ResponseEntity;
7 | import springfox.documentation.builders.ApiInfoBuilder;
8 | import springfox.documentation.builders.PathSelectors;
9 | import springfox.documentation.builders.RequestHandlerSelectors;
10 | import springfox.documentation.service.ApiInfo;
11 | import springfox.documentation.spi.DocumentationType;
12 | import springfox.documentation.spring.web.plugins.Docket;
13 | import springfox.documentation.swagger.web.DocExpansion;
14 | import springfox.documentation.swagger.web.ModelRendering;
15 | import springfox.documentation.swagger.web.UiConfiguration;
16 | import springfox.documentation.swagger.web.UiConfigurationBuilder;
17 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
18 |
19 | @Configuration
20 | @EnableSwagger2
21 | public class SwaggerConfig {
22 | @Bean
23 | public UiConfiguration uiConfig() {
24 | return UiConfigurationBuilder.builder()
25 | .deepLinking(true)
26 | .displayOperationId(false)
27 | .defaultModelExpandDepth(3)
28 | .defaultModelExpandDepth(3)
29 | .docExpansion(DocExpansion.LIST)
30 | .displayRequestDuration(false)
31 | .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS)
32 | .validatorUrl(null)
33 | .build();
34 | }
35 |
36 | @Bean
37 | public Docket api() {
38 | return new Docket(DocumentationType.SWAGGER_2)
39 | .groupName("photo api")
40 | .apiInfo(apiInfo())
41 | .select()
42 | .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
43 | .paths(PathSelectors.any())
44 | .build();
45 | }
46 |
47 |
48 | private ApiInfo apiInfo() {
49 | return new ApiInfoBuilder()
50 | .title("photo upload api")
51 | .description("사진 업로드 api")
52 | .version("1.0.0")
53 | .build();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/config/WebConfig.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.config;
2 |
3 | import info.thecodinglive.photoapp.api.MDCLogFilter;
4 | import org.springframework.boot.web.servlet.FilterRegistrationBean;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 |
8 | import java.util.Arrays;
9 |
10 | @Configuration
11 | public class WebConfig {
12 | @Bean
13 | public FilterRegistrationBean getFilterRegistrationBean() {
14 | FilterRegistrationBean registrationBean = new FilterRegistrationBean(new MDCLogFilter());
15 | registrationBean.setUrlPatterns(Arrays.asList("/v1/*"));
16 | return registrationBean;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/FastcamJacksonConverter.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import com.fasterxml.jackson.core.type.TypeReference;
5 | import com.fasterxml.jackson.databind.DeserializationFeature;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.fasterxml.jackson.databind.SerializationFeature;
8 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
9 |
10 | public class FastcamJacksonConverter {
11 | private static final ObjectMapper mapper;
12 |
13 | static {
14 | mapper = new ObjectMapper()
15 | .setSerializationInclusion(JsonInclude.Include.NON_NULL)
16 | .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
17 | .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
18 | .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
19 | .configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false)
20 | .registerModule(new JavaTimeModule());
21 | }
22 |
23 | private FastcamJacksonConverter() {
24 | throw new RuntimeException("construct not support");
25 | }
26 |
27 | public static ObjectMapper getInstance() {
28 | return mapper;
29 | }
30 |
31 | public static String toJson(Object value) {
32 | try{
33 | return mapper.writeValueAsString(value);
34 | } catch (Exception e) {
35 | throw new RuntimeException("convert error");
36 | }
37 | }
38 |
39 | public static T toObject(String content, Class valueType) {
40 | try {
41 | return mapper.readValue(content, valueType);
42 | } catch (Exception e) {
43 | throw new RuntimeException("convert error");
44 | }
45 | }
46 |
47 | public static T toObject(String content, TypeReference type) {
48 | try {
49 | return mapper.readValue(content, type);
50 | } catch (Exception e) {
51 | throw new RuntimeException("convert error");
52 | }
53 | }
54 |
55 | public static T convert(Object obj, Class type) {
56 | try {
57 | return mapper.convertValue(obj, type);
58 | } catch (Exception e) {
59 | throw new RuntimeException("convert error");
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/FileUploadController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.PostMapping;
7 |
8 | import org.springframework.web.bind.annotation.RequestParam;
9 | import org.springframework.web.bind.annotation.RequestPart;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import org.springframework.web.multipart.MultipartFile;
12 |
13 |
14 | @Api
15 | @RestController
16 | public class FileUploadController {
17 |
18 | @Autowired
19 | FileUploadService fileUploadService;
20 |
21 | @ApiOperation("이미지 파일 업로드")
22 | @PostMapping("/v1.0/upload/image")
23 | public ImageFileUploadResult transfer(
24 | @RequestParam("userKey") String userKey,
25 | @RequestPart("imageFile") MultipartFile multipartFile) {
26 | ImageFile imageFile = fileUploadService.upload(multipartFile);
27 | return ImageFileUploadResult.builder()
28 | .fileName(imageFile.getFileName())
29 | .fileId(imageFile.getFileId())
30 | .fileSize(imageFile.getFileSize())
31 | .build();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/FileUploadService.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 |
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Service;
8 | import org.springframework.web.multipart.MultipartFile;
9 |
10 | import javax.servlet.annotation.MultipartConfig;
11 | import java.util.UUID;
12 |
13 | @Slf4j
14 | @Service
15 | public class FileUploadService {
16 | @Autowired
17 | private FileWriter fileWriter;
18 |
19 | public ImageFile upload(MultipartFile sourceFile) {
20 | String fileId = UUID.randomUUID().toString();
21 | String filePath = fileWriter.getFilePath(fileId, sourceFile);
22 | LOG.info("filePath:: {}", filePath );
23 | fileWriter.writeFile(sourceFile, filePath);
24 |
25 | return ImageFile.builder()
26 | .fileName(sourceFile.getName())
27 | .filePath(filePath)
28 | .fileId(fileId)
29 | .fileSize(sourceFile.getSize())
30 | .build();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/FileWriter.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage;
2 |
3 | import info.thecodinglive.photoapp.config.PhotoAppProperties;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.apache.commons.io.FilenameUtils;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Service;
8 | import org.springframework.web.multipart.MultipartFile;
9 |
10 | import javax.servlet.annotation.MultipartConfig;
11 | import java.io.File;
12 | import java.io.IOException;
13 | import java.time.LocalDateTime;
14 | import java.time.format.DateTimeFormatter;
15 |
16 | @Slf4j
17 | @Service
18 | public class FileWriter {
19 | @Autowired
20 | PhotoAppProperties photoAppProperties;
21 |
22 | public long writeFile(MultipartFile multipartFile, String filePath) {
23 | try {
24 | multipartFile.transferTo(new File(filePath));
25 | } catch (IllegalStateException ile) {
26 | throw new RuntimeException("file write error");
27 | } catch (IOException ioe) {
28 | throw new RuntimeException("ioe error");
29 | }
30 | return multipartFile.getSize();
31 | }
32 |
33 | public String getFilePath(String fileId, MultipartFile sourceFile) {
34 | return photoAppProperties.getDefaultPath() +"/" + dateStr() + "/" + fileId + "." + getMimeType(sourceFile.getOriginalFilename());
35 | }
36 |
37 |
38 | private static String getMimeType(String filePath) {
39 | return FilenameUtils.getExtension(filePath);
40 | }
41 |
42 | public static String dateStr() {
43 | LocalDateTime now = LocalDateTime.now();
44 | DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
45 | return now.format(dateTimeFormatter);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/ImageFile.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage;
2 |
3 | import lombok.Builder;
4 | import lombok.Getter;
5 |
6 | @Getter
7 | @Builder
8 | public class ImageFile {
9 | private String fileId;
10 | private Long fileSize;
11 | private String fileName;
12 | private String fileType;
13 | private String filePath;
14 | }
15 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/ImageFileUploadResult.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage;
2 |
3 | import lombok.Builder;
4 | import lombok.Getter;
5 |
6 | @Builder
7 | @Getter
8 | public class ImageFileUploadResult {
9 | private String fileId;
10 | private String fileName;
11 | private Long fileSize;
12 | }
13 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/gcp/GCPStorageComponent.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage.gcp;
2 |
3 |
4 | import com.google.api.services.storage.model.StorageObject;
5 | import com.google.auth.Credentials;
6 | import com.google.auth.oauth2.GoogleCredentials;
7 | import com.google.cloud.storage.*;
8 | import lombok.RequiredArgsConstructor;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.stereotype.Component;
11 | import org.springframework.stereotype.Service;
12 | import org.springframework.util.ResourceUtils;
13 |
14 | import javax.annotation.PostConstruct;
15 | import javax.servlet.http.HttpServletResponse;
16 | import java.io.FileInputStream;
17 | import java.io.FileOutputStream;
18 | import java.io.InputStream;
19 | import java.nio.file.Files;
20 | import java.nio.file.Paths;
21 | import java.util.ArrayList;
22 | import java.util.Arrays;
23 |
24 | @Slf4j
25 | @Component
26 | @RequiredArgsConstructor
27 | public class GCPStorageComponent {
28 | private static final String PROJECT_ID = "boot-sample1";
29 | private static final String BUCKET_NAME = "photosample-storage";
30 |
31 | private BlobInfo createBlobInfo(String bucketName, String objectName) {
32 | BlobId blobId = BlobId.of(bucketName, objectName);
33 | return BlobInfo.newBuilder(blobId).build();
34 | }
35 |
36 |
37 | public void uploadGcpStorage(String bucketName, String objectName, String filePath) {
38 | try {
39 | Storage storage = StorageOptions.newBuilder().setProjectId(PROJECT_ID).build().getService();
40 | storage.create(createBlobInfo(bucketName, objectName), Files.readAllBytes(Paths.get(filePath)));
41 | LOG.info("file upload: {} uploaded to bucket {} as {}", filePath, bucketName, objectName);
42 | } catch (Exception e) {
43 | LOG.debug("error", e);
44 | }
45 | }
46 |
47 |
48 | public void uploadGcpStorageStream(String objectName, InputStream fileInput) {
49 | try {
50 | Storage storage = StorageOptions.newBuilder().setProjectId(PROJECT_ID).build().getService();
51 | storage.create(createBlobInfo(BUCKET_NAME, objectName), fileInput.readAllBytes());
52 | LOG.info("file upload: {} uploaded to bucket {}", BUCKET_NAME, objectName);
53 | } catch (Exception e) {
54 | LOG.debug("error", e);
55 | }
56 | }
57 |
58 | public void downloadGcpStroage(String bucketName, String objectName, String destPath) {
59 | try {
60 | Storage storage = StorageOptions.newBuilder().setProjectId(PROJECT_ID).build().getService();
61 | Blob blob = storage.get(BlobId.of(bucketName, objectName));
62 | blob.downloadTo(Paths.get(destPath));
63 |
64 | LOG.info("file download: {} uploaded to bucket {} as {}", destPath, bucketName, objectName);
65 | } catch (Exception e) {
66 | LOG.debug("error", e);
67 | }
68 | }
69 |
70 | public void downloadGcpStroage(String objectName, HttpServletResponse response) {
71 | try {
72 | Storage storage = StorageOptions.newBuilder().setProjectId(PROJECT_ID).build().getService();
73 | Blob blob = storage.get(BlobId.of(BUCKET_NAME, objectName));
74 | response.setHeader("Content-Disposition", "attachment; filename=\"" + objectName + "\";");
75 | response.setHeader("Content-Transfer-Encoding", "binary");
76 | blob.downloadTo(response.getOutputStream());
77 |
78 | LOG.info("file download to bucket {} as {}", BUCKET_NAME, objectName);
79 | } catch (Exception e) {
80 | LOG.debug("error", e);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/gcp/GcpFileDownloadController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage.gcp;
2 |
3 | import io.swagger.annotations.ApiOperation;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.PostMapping;
9 | import org.springframework.web.bind.annotation.RequestPart;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import org.springframework.web.multipart.MultipartFile;
12 |
13 | import javax.servlet.http.HttpServletResponse;
14 | import java.io.OutputStream;
15 |
16 | @Slf4j
17 | @RestController
18 | @RequiredArgsConstructor
19 | public class GcpFileDownloadController {
20 | private final GcpStorageService gcpStorageService;
21 |
22 | @ApiOperation("gcp 파일 다운로드")
23 | @GetMapping("/v1.0/gcp/download")
24 | public ResponseEntity> fileDownload(
25 | HttpServletResponse response,
26 | String downloadFileName) {
27 | gcpStorageService.gcpFileDown(downloadFileName, response);
28 | return ResponseEntity.ok("ok");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/gcp/GcpFileUploadController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage.gcp;
2 |
3 | import io.swagger.annotations.ApiOperation;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestPart;
9 | import org.springframework.web.bind.annotation.RestController;
10 | import org.springframework.web.multipart.MultipartFile;
11 |
12 | import java.util.Random;
13 | import java.util.UUID;
14 |
15 | @Slf4j
16 | @RestController
17 | @RequiredArgsConstructor
18 | public class GcpFileUploadController {
19 | private final GcpStorageService gcpStorageService;
20 |
21 | @ApiOperation("gcp 파일 업로드")
22 | @PostMapping("/v1.0/gcp/upload")
23 | public ResponseEntity> fileupload(@RequestPart("imageFile") MultipartFile multipartFile) {
24 | gcpStorageService.gcpFileUpload(multipartFile.getOriginalFilename(), multipartFile);
25 |
26 | return ResponseEntity.ok("ok");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/java/info/thecodinglive/photoapp/storage/gcp/GcpStorageService.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp.storage.gcp;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.stereotype.Service;
6 | import org.springframework.web.multipart.MultipartFile;
7 |
8 | import javax.servlet.http.HttpServletResponse;
9 |
10 | @Service
11 | @RequiredArgsConstructor
12 | @Slf4j
13 | public class GcpStorageService {
14 | private final GCPStorageComponent gcpStorageComponent;
15 |
16 | public void gcpFileUpload(String uploadedFileName, MultipartFile multipartFile) {
17 | try {
18 | gcpStorageComponent.uploadGcpStorageStream(uploadedFileName, multipartFile.getInputStream());
19 | }catch (Exception e) {
20 | LOG.error("upload error", e);
21 | }
22 | }
23 |
24 | public void gcpFileDown(String gcpFileName, HttpServletResponse servletResponse) {
25 | gcpStorageComponent.downloadGcpStroage(gcpFileName, servletResponse);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/resources/admin.yml:
--------------------------------------------------------------------------------
1 | spring.boot:
2 | admin:
3 | client:
4 | instance:
5 | health-url: http://localhost:8080/swagger-ui.html
6 | #url: http://localhost:8091
7 | auto-registration: true
8 | management:
9 | endpoint:
10 | health:
11 | show-details: ALWAYS
12 | endpoints:
13 | web:
14 | exposure:
15 | include: "*"
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | #https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html
2 | server.port: 8080
3 | spring:
4 | application:
5 | name: photoapp
6 | jackson:
7 | default-property-inclusion: non_null
8 | servlet:
9 | multipart.enabled: true
10 |
11 | photoapp.file:
12 | defaultPath: c:\up-dir
13 |
14 |
15 | spring.zipkin:
16 | base-url: http://localhost:9411
17 |
18 | spring.sleuth.sampler.probability: 1.0
19 |
20 | eureka:
21 | client:
22 | serviceUrl:
23 | defaultZone: http://localhost:8761/eureka/
24 | instance:
25 | leaseRenewalIntervalInSeconds: 10
26 | metadataMap:
27 | instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
28 |
29 |
30 | spring.config.import: admin.yml
31 |
32 |
33 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/resources/test-down.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodinglive/fastcampus-example/8fc38f151532d7fc4168fd2cbb6e9cf42e9dd472/fastcam-photoapp/src/main/resources/test-down.jpg
--------------------------------------------------------------------------------
/fastcam-photoapp/src/main/resources/test.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thecodinglive/fastcampus-example/8fc38f151532d7fc4168fd2cbb6e9cf42e9dd472/fastcam-photoapp/src/main/resources/test.jpg
--------------------------------------------------------------------------------
/fastcam-photoapp/src/test/java/info/thecodinglive/photoapp/DateFormatTest.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp;
2 |
3 | import info.thecodinglive.photoapp.storage.FileWriter;
4 | import org.assertj.core.api.Assert;
5 | import org.junit.jupiter.api.Assertions;
6 | import org.junit.jupiter.api.Test;
7 | import org.junit.jupiter.api.extension.ExtendWith;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.test.context.junit.jupiter.SpringExtension;
10 | import org.springframework.test.context.junit4.SpringRunner;
11 |
12 | import java.time.LocalDateTime;
13 |
14 | //@SpringBootTest
15 | //@ExtendWith(SpringExtension.class)
16 | public class DateFormatTest {
17 | @Test
18 | void fileWriteGenerateDate() {
19 | //given
20 | String expectdDate = FileWriter.dateStr();
21 | //then
22 | System.out.println(FileWriter.dateStr());
23 | Assertions.assertNotNull(expectdDate);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/fastcam-photoapp/src/test/java/info/thecodinglive/photoapp/GcpStorageServiceTest.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.photoapp;
2 |
3 | import info.thecodinglive.photoapp.storage.gcp.GCPStorageComponent;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.extension.ExtendWith;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.boot.test.context.SpringBootTest;
8 | import org.springframework.test.context.junit.jupiter.SpringExtension;
9 |
10 | import java.nio.file.Files;
11 | import java.nio.file.Paths;
12 |
13 | @SpringBootTest
14 | @ExtendWith(SpringExtension.class)
15 | public class GcpStorageServiceTest {
16 | @Autowired
17 | private GCPStorageComponent gcpUploadService;
18 |
19 | private String projectId = "boot-sample1";
20 | private String bucketName = "photosample-storage";
21 | private String filePath = "src/main/resources/test.jpg";
22 |
23 | @Test
24 | public void gcpUpload() {
25 | gcpUploadService.uploadGcpStorage(bucketName, "ysj-test3.jpg", filePath);
26 | }
27 |
28 | @Test
29 | public void gcpDownload() {
30 | gcpUploadService.downloadGcpStroage(bucketName, "test.jpg", "src/main/resources/test-down.jpg");
31 | }
32 |
33 | @Test
34 | public void getFiletPath() throws Exception {
35 | Files.readAllBytes(Paths.get("src/main/resources/test.jpg"));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/fastcam-resilience4j-server/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | plugins {
4 | id("org.springframework.boot") version "2.4.3"
5 | id("io.spring.dependency-management") version "1.0.11.RELEASE"
6 | kotlin("jvm") version "1.4.30"
7 | kotlin("plugin.spring") version "1.4.30"
8 | }
9 |
10 | group = "info.thecodinglive.rabbitmq"
11 | version = "0.0.1-SNAPSHOT"
12 | java.sourceCompatibility = JavaVersion.VERSION_11
13 |
14 | configurations {
15 | compileOnly {
16 | extendsFrom(configurations.annotationProcessor.get())
17 | }
18 | }
19 |
20 | repositories {
21 | jcenter()
22 | }
23 |
24 | dependencies {
25 | implementation("org.springframework.boot:spring-boot-starter-web")
26 | compileOnly("org.projectlombok:lombok")
27 | annotationProcessor("org.projectlombok:lombok")
28 | }
29 |
30 | dependencyManagement {
31 | imports {
32 | mavenBom ("org.springframework.cloud:spring-cloud-dependencies:2020.0.1")
33 | }
34 | }
35 |
36 |
37 | tasks.withType {
38 | kotlinOptions {
39 | freeCompilerArgs = listOf("-Xjsr305=strict")
40 | jvmTarget = "11"
41 | }
42 | }
43 |
44 | tasks.withType {
45 | useJUnitPlatform()
46 | }
47 |
--------------------------------------------------------------------------------
/fastcam-resilience4j-server/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/fastcam-resilience4j-server/src/main/java/info/thecodinglive/resilience4j/provide/ProvideApp.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.provide;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class ProvideApp {
8 | public static void main(String ar[]) {
9 | SpringApplication.run(ProvideApp.class, ar);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/fastcam-resilience4j-server/src/main/java/info/thecodinglive/resilience4j/provide/service/BulkHeadController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.provide.service;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.RestController;
6 |
7 | import java.util.concurrent.ThreadLocalRandom;
8 |
9 | @Slf4j
10 | @RestController
11 | public class BulkHeadController {
12 | private static final int DELAY = 100;
13 | private int count = 0;
14 |
15 | @GetMapping("/")
16 | public String okay() {
17 | return "I'm fine.";
18 | }
19 |
20 | @GetMapping("/slow")
21 | public String slow() throws InterruptedException {
22 | Thread.sleep(DELAY);
23 | return "I'm fine, just slow";
24 | }
25 |
26 | @GetMapping("/error")
27 | public String error() {
28 | throw new InternalServerErrorException("I'm absolutely not fine!");
29 | }
30 |
31 | @GetMapping("/erratic")
32 | public String erratic() throws InterruptedException {
33 | log.info(Integer.toString(count++));
34 |
35 | if(ThreadLocalRandom.current().nextInt(0 , 5) == 0) {
36 | log.error("erratic");
37 | throw new InterruptedException("erratic occured");
38 | }
39 | log.info("sucess");
40 | return "ok";
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/fastcam-resilience4j-server/src/main/java/info/thecodinglive/resilience4j/provide/service/CircuitController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.provide.service;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.web.bind.annotation.GetMapping;
5 | import org.springframework.web.bind.annotation.RequestMapping;
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | import java.util.concurrent.ThreadLocalRandom;
9 |
10 | @Slf4j
11 | @RestController
12 | @RequestMapping("/circuit")
13 | public class CircuitController {
14 | private static final int DELAY = 100;
15 | private int count = 0;
16 |
17 | @GetMapping("/")
18 | public String okay() {
19 | return "I'm fine.";
20 | }
21 |
22 | @GetMapping("/slow")
23 | public String slow() throws InterruptedException {
24 | Thread.sleep(DELAY);
25 | return "I'm fine, just slow";
26 | }
27 |
28 | @GetMapping("/error")
29 | public String error() {
30 | throw new InternalServerErrorException("I'm absolutely not fine!");
31 | }
32 |
33 | @GetMapping("/erratic")
34 | public String erratic() throws InterruptedException {
35 | log.info(Integer.toString(count++));
36 |
37 | if(ThreadLocalRandom.current().nextInt(0 , 5) == 0) {
38 | log.error("erratic");
39 | throw new InterruptedException("erratic occured");
40 | }
41 | log.info("sucess");
42 | return "ok";
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/fastcam-resilience4j-server/src/main/java/info/thecodinglive/resilience4j/provide/service/InternalServerErrorException.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.provide.service;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | /**
7 | * InternalServerErrorException
8 | */
9 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
10 | public class InternalServerErrorException extends RuntimeException {
11 |
12 | public InternalServerErrorException(String msg) {
13 | super(msg);
14 | }
15 |
16 | }
--------------------------------------------------------------------------------
/fastcam-resilience4j-server/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server.port: 7072
2 |
3 |
4 | logging:
5 | level:
6 | root: debug
--------------------------------------------------------------------------------
/fastcam-resilience4j/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | plugins {
4 | id("org.springframework.boot") version "2.4.3"
5 | id("io.spring.dependency-management") version "1.0.11.RELEASE"
6 | kotlin("jvm") version "1.4.30"
7 | kotlin("plugin.spring") version "1.4.30"
8 | }
9 |
10 | group = "info.thecodinglive.rabbitmq"
11 | version = "0.0.1-SNAPSHOT"
12 | java.sourceCompatibility = JavaVersion.VERSION_11
13 |
14 | configurations {
15 | compileOnly {
16 | extendsFrom(configurations.annotationProcessor.get())
17 | }
18 | }
19 |
20 | repositories {
21 | jcenter()
22 | }
23 |
24 | dependencies {
25 | implementation("org.springframework.boot:spring-boot-starter-web")
26 | implementation("org.springframework.boot:spring-boot-starter-aop")
27 | implementation("io.github.resilience4j:resilience4j-spring-boot2")
28 | implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j")
29 | implementation("org.springframework.boot:spring-boot-starter-actuator")
30 | implementation("io.micrometer:micrometer-core")
31 | implementation("io.micrometer:micrometer-registry-prometheus")
32 | implementation("io.github.resilience4j:resilience4j-micrometer")
33 |
34 | compileOnly("org.projectlombok:lombok")
35 | annotationProcessor("org.projectlombok:lombok")
36 | }
37 |
38 | dependencyManagement {
39 | imports {
40 | mavenBom ("org.springframework.cloud:spring-cloud-dependencies:2020.0.1")
41 | }
42 | }
43 |
44 |
45 | tasks.withType {
46 | kotlinOptions {
47 | freeCompilerArgs = listOf("-Xjsr305=strict")
48 | jvmTarget = "11"
49 | }
50 | }
51 |
52 | tasks.withType {
53 | useJUnitPlatform()
54 | }
55 |
--------------------------------------------------------------------------------
/fastcam-resilience4j/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | prometheus:
4 | image: prom/prometheus
5 | container_name: prometheus
6 | volumes:
7 | - ./prometheus.yml:/etc/prometheus/prometheus.yml
8 | expose:
9 | - 9090
10 | ports:
11 | - "9090:9090"
12 | grafana:
13 | image: grafana/grafana
14 | container_name: grafana
15 | env_file:
16 | - ./grafana.env
17 | expose:
18 | - 3000
19 | ports:
20 | - "3000:3000"
--------------------------------------------------------------------------------
/fastcam-resilience4j/docker/grafana.env:
--------------------------------------------------------------------------------
1 | # [server]
2 | # GF_SERVER_DOMAIN=localhost
3 | # GF_SERVER_HTTP_PORT=3000
4 | # GF_SERVER_PROTOCOL=http
--------------------------------------------------------------------------------
/fastcam-resilience4j/docker/prometheus.yml:
--------------------------------------------------------------------------------
1 | global:
2 | scrape_interval: 15s # By default, scrape targets every 15 seconds.
3 |
4 | # Attach these labels to any time series or alerts when communicating with
5 | # external systems (federation, remote storage, Alertmanager).
6 | external_labels:
7 | monitor: 'resilience4j-monitor'
8 |
9 | # A scrape configuration containing exactly one endpoint to scrape:
10 | # Here it's Prometheus itself.
11 | scrape_configs:
12 | # The job name is added as a label `job=` to any timeseries scraped from this config.
13 | - job_name: 'prometheus'
14 |
15 | # Override the global default and scrape targets from this job every 5 seconds.
16 | scrape_interval: 5s
17 |
18 | static_configs:
19 | - targets: ['localhost:9090']
20 |
21 | - job_name: 'resilience4j-spring-boot2-demo'
22 |
23 | # Override the global default and scrape targets from this job every 5 seconds.
24 | scrape_interval: 5s
25 |
26 | metrics_path: /actuator/prometheus
27 |
28 | static_configs:
29 | # application ip
30 | - targets: ['172.30.1.45:7075']
--------------------------------------------------------------------------------
/fastcam-resilience4j/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/fastcam-resilience4j/src/main/java/info/thecodinglive/resilience4j/ResilienceApp.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class ResilienceApp {
8 | public static void main(String ar[]) {
9 | SpringApplication.run(ResilienceApp.class, ar);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/fastcam-resilience4j/src/main/java/info/thecodinglive/resilience4j/config/CircuitConfig.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.config;
2 |
3 | import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
4 | import io.github.resilience4j.timelimiter.TimeLimiter;
5 | import io.github.resilience4j.timelimiter.TimeLimiterConfig;
6 | import io.github.resilience4j.timelimiter.TimeLimiterRegistry;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
10 | import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
11 | import org.springframework.cloud.client.circuitbreaker.Customizer;
12 | import org.springframework.context.annotation.Bean;
13 | import org.springframework.context.annotation.Configuration;
14 |
15 |
16 | import java.time.Duration;
17 |
18 | @Slf4j
19 | @Configuration
20 | public class CircuitConfig {
21 | @Value("${apiServer.maxTimeout}")
22 | private Integer maxTimeout;
23 | @Bean
24 | public Customizer defaultCustomer() {
25 | log.info("maxTimeout check: {}", maxTimeout);
26 | return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder("fastcam-timelimit")
27 | .timeLimiterConfig(TimeLimiterConfig.custom()
28 | .timeoutDuration(Duration.ofSeconds(maxTimeout))
29 | .build())
30 | .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults()).build());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/fastcam-resilience4j/src/main/java/info/thecodinglive/resilience4j/config/WebConfig.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.config;
2 |
3 | import org.springframework.boot.web.client.RestTemplateBuilder;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.web.client.RestTemplate;
7 |
8 | @Configuration
9 | public class WebConfig {
10 | @Bean
11 | RestTemplate restTemplate() {return new RestTemplateBuilder().build(); }
12 | }
13 |
--------------------------------------------------------------------------------
/fastcam-resilience4j/src/main/java/info/thecodinglive/resilience4j/service/BulkHeadController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.service;
2 |
3 | import io.github.resilience4j.bulkhead.Bulkhead;
4 | import io.github.resilience4j.bulkhead.BulkheadConfig;
5 | import io.vavr.CheckedFunction0;
6 | import io.vavr.control.Try;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import org.springframework.web.client.RestTemplate;
12 |
13 | import java.time.Duration;
14 |
15 | @RestController
16 | @Slf4j
17 | public class BulkHeadController {
18 |
19 | private final RestTemplate restTemplate;
20 | private final String provideUrl;
21 | private final Bulkhead bulkhead;
22 |
23 | public BulkHeadController(RestTemplate restTemplate, @Value("${apiServer.url}") String provideUrl,
24 | @Value("${apiServer.maxConcurrent}") int maxConcurrent) {
25 | this.restTemplate = restTemplate;
26 | this.provideUrl = provideUrl;
27 | log.info("maxCounccurent: {}", maxConcurrent);
28 | this.bulkhead = createBulkHead(maxConcurrent);
29 | }
30 |
31 | private Bulkhead createBulkHead(Integer maxConcurrent) {
32 | BulkheadConfig bulkheadConfig = BulkheadConfig.custom()
33 | .maxConcurrentCalls(maxConcurrent)
34 | .maxWaitDuration(Duration.ofMillis(500))
35 | .build();
36 |
37 | Bulkhead bulkhead = Bulkhead.of("resilience-provider", bulkheadConfig);
38 |
39 | bulkhead.getEventPublisher()
40 | .onCallPermitted(event -> log.info("Call permitted by bulkhead"))
41 | .onCallRejected(event -> log.info("Call rejected by bulkhead"));
42 |
43 | return bulkhead;
44 | }
45 |
46 |
47 | @GetMapping("/bulkhead")
48 | public String bulkhead() {
49 | CheckedFunction0 someServiceCall = Bulkhead.decorateCheckedSupplier(bulkhead,
50 | () -> "this message was" + restTemplate.getForObject(provideUrl + "/slow", String.class));
51 |
52 | Try result = Try.of(someServiceCall).recover((throwable -> "this is a bulkhead fallback"));
53 | return result.get();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/fastcam-resilience4j/src/main/java/info/thecodinglive/resilience4j/service/circuit/CircuitAnnotationService.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.service.circuit;
2 |
3 | import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
4 | import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.stereotype.Service;
9 | import org.springframework.web.client.RestTemplate;
10 |
11 | @RequiredArgsConstructor
12 | @Service
13 | @Slf4j
14 | public class CircuitAnnotationService {
15 | @Value("${apiServer.url}")
16 | private String apiUrl;
17 |
18 | private RestTemplate restTemplate;
19 |
20 | @CircuitBreaker(name = "myCircuitBreaker", fallbackMethod = "defaultFallback")
21 | public String getFailRequest() {
22 | //return restTemplate.getForObject(apiUrl + "/circuit/error", String.class);
23 | throw new MyException("myException");
24 | }
25 |
26 | @CircuitBreaker(name = "myCircuitBreaker", fallbackMethod = "defaultFallback")
27 | public String getSuccessRequest() {
28 | return "request is success";
29 | }
30 |
31 |
32 |
33 | public String defaultFallback(MyException e) {
34 | log.error("default fallback ", e);
35 | return "fallback msg";
36 | }
37 |
38 | public String defaultFallback(CallNotPermittedException callNotPermittedException) {
39 | log.error("default fallback ", callNotPermittedException);
40 | return "call not permit fallback msg";
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/fastcam-resilience4j/src/main/java/info/thecodinglive/resilience4j/service/circuit/CircuitController.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.service.circuit;
2 |
3 | import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Value;
7 | import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.PathVariable;
10 | import org.springframework.web.bind.annotation.RestController;
11 |
12 | import java.util.HashMap;
13 | import java.util.Map;
14 |
15 | @RestController
16 | @Slf4j
17 | @RequiredArgsConstructor
18 | public class CircuitController {
19 |
20 | private final CircuitAnnotationService circuitAnnotationService;
21 | private final CircuitBreakerFactory circuitBreakerFactory;
22 | private final HttpBinService httpBin;
23 |
24 | @GetMapping("/get")
25 | public Map get() {return httpBin.get();}
26 |
27 | @GetMapping("/delay/{seconds}")
28 | public Map delay(@PathVariable int seconds) {
29 | return circuitBreakerFactory
30 | .create("delay").run(httpBin.delaySuppplier(seconds),
31 | t -> {
32 | log.warn("delay call failed error", t);
33 | Map fallback = new HashMap<>();
34 | fallback.put("hello", "world");
35 | return fallback;
36 | });
37 | }
38 |
39 | @GetMapping("/circuit/fail")
40 | public String requestWithCircuitFail() {
41 | return circuitAnnotationService.getFailRequest();
42 | }
43 |
44 | @GetMapping("/circuit/success")
45 | public String requestWithCircuitSuccess() {
46 | return circuitAnnotationService.getSuccessRequest();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/fastcam-resilience4j/src/main/java/info/thecodinglive/resilience4j/service/circuit/HttpBinService.java:
--------------------------------------------------------------------------------
1 | package info.thecodinglive.resilience4j.service.circuit;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import org.springframework.stereotype.Service;
5 | import org.springframework.web.client.RestTemplate;
6 |
7 | import java.util.Map;
8 | import java.util.function.Supplier;
9 |
10 | @RequiredArgsConstructor
11 | @Service
12 | public class HttpBinService {
13 | private final RestTemplate rest;
14 |
15 | public Map get() {
16 | return rest.getForObject("https://httpbin.org/get", Map.class);
17 |
18 | }
19 |
20 | public Map delay(int seconds) {
21 | return rest.getForObject("https://httpbin.org/delay/" + seconds, Map.class);
22 | }
23 |
24 | public Supplier