├── README.md
├── customer
├── pom.xml
├── run.cmd
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── michlb
│ │ │ └── demo
│ │ │ └── customer
│ │ │ ├── Application.java
│ │ │ ├── constant
│ │ │ ├── ApiConstants.java
│ │ │ └── GlobalBusinessCodes.java
│ │ │ ├── controller
│ │ │ ├── BuildController.java
│ │ │ ├── CustomerController.java
│ │ │ ├── HelpController.java
│ │ │ └── PingController.java
│ │ │ ├── feign
│ │ │ ├── FeignConfiguration.java
│ │ │ ├── client
│ │ │ │ └── AccountClient.java
│ │ │ └── interceptor
│ │ │ │ └── TraceRequestInterceptor.java
│ │ │ └── model
│ │ │ └── Customer.java
│ └── resources
│ │ ├── application.yml
│ │ ├── banner.txt
│ │ ├── bootstrap.yml
│ │ ├── git-build.properties
│ │ └── logback.xml
│ └── test
│ ├── java
│ └── de
│ │ └── michlb
│ │ └── demo
│ │ └── customer
│ │ ├── PingControllerIntegrationTest.java
│ │ └── PingControllerTest.java
│ └── jmeter
│ └── Microservice test plan.jmx
├── eureka
├── pom.xml
├── run.cmd
└── src
│ └── main
│ ├── java
│ └── de
│ │ └── michlb
│ │ └── demo
│ │ └── eureka
│ │ └── Application.java
│ └── resources
│ ├── application.yml
│ └── banner.txt
├── product
├── pom.xml
├── run.cmd
└── src
│ ├── main
│ ├── java
│ │ └── de
│ │ │ └── michlb
│ │ │ └── demo
│ │ │ └── product
│ │ │ ├── Application.java
│ │ │ ├── constant
│ │ │ ├── ApiConstants.java
│ │ │ └── GlobalBusinessCodes.java
│ │ │ ├── controller
│ │ │ ├── BuildController.java
│ │ │ ├── HelpController.java
│ │ │ ├── PingController.java
│ │ │ └── ProductDetailController.java
│ │ │ ├── feign
│ │ │ ├── FeignConfiguration.java
│ │ │ ├── client
│ │ │ │ └── AccountClient.java
│ │ │ └── interceptor
│ │ │ │ └── TraceRequestInterceptor.java
│ │ │ └── model
│ │ │ └── Product.java
│ └── resources
│ │ ├── application.yml
│ │ ├── banner.txt
│ │ ├── bootstrap.yml
│ │ ├── git-build.properties
│ │ └── logback.xml
│ └── test
│ ├── java
│ └── de
│ │ └── michlb
│ │ └── demo
│ │ └── product
│ │ ├── PingControllerIntegrationTest.java
│ │ └── PingControllerTest.java
│ └── jmeter
│ └── Microservice test plan.jmx
└── zuul
├── pom.xml
├── run.cmd
└── src
└── main
├── java
└── de
│ └── michlb
│ └── demo
│ └── zuul
│ ├── Application.java
│ ├── bff
│ └── controller
│ │ └── ProductController.java
│ └── feign
│ ├── CustomerClient.java
│ └── ProductClient.java
└── resources
├── banner.txt
└── bootstrap.yml
/README.md:
--------------------------------------------------------------------------------
1 | # Sample for Zuul usage with integrated BFF Pattern Controller
2 |
3 | ## eureka
4 | Netfilx Eureka Discovery Server
5 |
6 | ## zuul
7 | Netfilx Zuul Proxy Server
8 |
9 | ## product
10 | Spring Boot RESTful service for a simple sample
11 | - gives a simple Product object as JSON
12 |
13 | ## customer
14 | Spring Boot RESTful service for a simple sample
15 | - gives a simple Customer object as JSON
16 |
17 | ## Check Results
18 |
19 | [http://localhost:8071/](http://localhost:8071/) Eureka Server
20 |
21 | [http://localhost:8081/mappings](http://localhost:8081/mappings) Zuul Server mappings
22 |
23 | [http://localhost:8082/api/product/detail](http://localhost:8082/api/product/detail) Product Service direct - detail
24 |
25 | [http://localhost:8081/product/api/product/detail](http://localhost:8081/product/api/product/detail) Product Service via Zuul - detail
26 |
27 | [http://localhost:8083/api/customer/info](http://localhost:8083/api/customer/info) Customer Service direct - info
28 |
29 | [http://localhost:8081/customer/api/customer/info](http://localhost:8081/customer/api/customer/info) Customer Service via Zuul - info
30 |
31 | [http://localhost:8081/bff/product/detail](http://localhost:8081/bff/product/detail) Call Zuul for aggregated info
32 |
--------------------------------------------------------------------------------
/customer/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | 4.0.0
5 |
6 |
7 | org.springframework.cloud
8 | spring-cloud-starter-parent
9 | Brixton.RELEASE
10 |
11 |
12 |
13 |
14 | de.michlb.demo
15 | customer
16 | 1.0.0-SNAPSHOT
17 | jar
18 | customer
19 | Module contains the restful controllers.
20 |
21 |
22 | UTF-8
23 | 1.8
24 |
25 |
26 |
27 |
28 |
29 |
30 | com.shedhack.trace
31 | trace-request-api
32 | 1.0.1
33 |
34 |
35 |
36 | com.shedhack.trace
37 | trace-request-filter
38 | 1.0.3
39 |
40 |
41 |
42 | com.shedhack.trace
43 | trace-request-jpa
44 | 1.0.2
45 |
46 |
47 |
48 | com.shedhack.exception
49 | exception-controller-spring
50 | 1.0.5
51 |
52 |
53 |
54 | com.shedhack.exception
55 | exception-core
56 | 1.0.4
57 |
58 |
59 |
60 | com.shedhack.thread
61 | thread-context-aspect
62 | 1.0.8
63 |
64 |
65 |
66 | com.shedhack.spring
67 | spring-actuator
68 | 1.0.1
69 |
70 |
71 |
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-starter-web
76 |
77 |
78 |
79 | org.springframework.boot
80 | spring-boot-starter-actuator
81 |
82 |
83 |
84 | org.springframework.boot
85 | spring-boot-actuator-docs
86 |
87 |
88 |
89 | org.webjars
90 | hal-browser
91 |
92 |
93 |
94 |
96 |
97 | org.hsqldb
98 | hsqldb
99 | runtime
100 |
101 |
102 |
103 |
104 | org.springframework.cloud
105 | spring-cloud-starter-config
106 |
107 |
108 |
109 | org.springframework.cloud
110 | spring-cloud-starter-eureka
111 |
112 |
113 |
114 | org.springframework.cloud
115 | spring-cloud-starter-ribbon
116 |
117 |
118 |
119 | org.springframework.cloud
120 | spring-cloud-starter-feign
121 | compile
122 |
123 |
124 |
125 | org.springframework.cloud
126 | spring-cloud-starter-hystrix
127 |
128 |
129 |
130 | org.springframework.cloud
131 | spring-cloud-starter-hystrix-dashboard
132 |
133 |
134 |
135 |
136 | io.springfox
137 | springfox-swagger2
138 | 2.4.0
139 |
140 |
141 |
142 | io.springfox
143 | springfox-swagger-ui
144 | 2.4.0
145 |
146 |
147 |
148 |
149 |
150 | org.springframework.boot
151 | spring-boot-starter-test
152 | test
153 |
154 |
155 |
156 |
157 |
158 | org.springframework.boot
159 | spring-boot-devtools
160 |
161 |
162 |
163 |
164 |
165 | customer
166 |
167 |
168 |
169 |
170 | src/main/resources
171 | true
172 |
173 | **/*.properties
174 | **/*.yml
175 |
176 |
177 |
178 | src/main/resources
179 | false
180 |
181 | **/*.xml
182 |
183 |
184 |
185 |
186 |
187 |
189 |
190 | org.apache.maven.plugins
191 | maven-resources-plugin
192 | 2.7
193 |
194 |
195 | @
196 |
197 | false
198 |
199 |
200 |
201 |
202 |
203 | org.springframework.boot
204 | spring-boot-maven-plugin
205 |
206 |
207 |
208 | true
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
--------------------------------------------------------------------------------
/customer/run.cmd:
--------------------------------------------------------------------------------
1 | title run:customer:8083
2 | mvn spring-boot:run -Drun.jvmArguments="-Dserver.port=8083 -Xms128m -Xmx256m"
3 |
--------------------------------------------------------------------------------
/customer/src/main/java/de/michlb/demo/customer/Application.java:
--------------------------------------------------------------------------------
1 | package de.michlb.demo.customer;
2 |
3 | import de.michlb.demo.customer.constant.ApiConstants;
4 | import com.shedhack.exception.controller.spring.config.EnableExceptionController;
5 | import com.shedhack.spring.actuator.config.EnableActuatorsAndInterceptors;
6 | import com.shedhack.spring.actuator.interceptor.TraceRequestHandler;
7 | import com.shedhack.thread.context.config.EnableThreadContextAspect;
8 | import com.shedhack.trace.request.api.service.TraceRequestService;
9 | import com.shedhack.trace.request.filter.DefaultLoggingHandler;
10 | import com.shedhack.trace.request.filter.RequestTraceFilter;
11 | import com.shedhack.trace.request.jpa.config.EnableTraceRequestJpa;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.beans.factory.annotation.Value;
14 | import org.springframework.boot.SpringApplication;
15 | import org.springframework.boot.autoconfigure.SpringBootApplication;
16 | import org.springframework.boot.context.embedded.FilterRegistrationBean;
17 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
18 | import org.springframework.cloud.netflix.feign.EnableFeignClients;
19 | import org.springframework.cloud.netflix.hystrix.EnableHystrix;
20 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
21 | import org.springframework.context.annotation.Bean;
22 | import org.springframework.context.annotation.PropertySource;
23 | import org.springframework.context.annotation.PropertySources;
24 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
25 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
26 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
27 | import springfox.documentation.builders.ApiInfoBuilder;
28 | import springfox.documentation.builders.PathSelectors;
29 | import springfox.documentation.builders.RequestHandlerSelectors;
30 | import springfox.documentation.service.ApiInfo;
31 | import springfox.documentation.spi.DocumentationType;
32 | import springfox.documentation.spring.web.plugins.Docket;
33 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
34 |
35 | import java.util.Arrays;
36 |
37 | @SpringBootApplication
38 | @EnableSwagger2
39 | @EnableTraceRequestJpa
40 | @EnableExceptionController
41 | @EnableThreadContextAspect
42 | @EnableActuatorsAndInterceptors
43 | @PropertySources(value = {
44 | @PropertySource(value = "classpath:/git-build.properties")
45 | })
46 | @EnableDiscoveryClient
47 | @EnableFeignClients
48 | @EnableHystrix
49 | @EnableHystrixDashboard
50 | public class Application extends WebMvcConfigurerAdapter {
51 |
52 | // --------------------
53 | // Bean configurations:
54 | // --------------------
55 |
56 | @Value("${spring.application.name}")
57 | private String appName;
58 |
59 | /**
60 | * Service is configured via {@link EnableTraceRequestJpa}
61 | */
62 | @Autowired
63 | private TraceRequestService jpaTraceRequestService;
64 |
65 | /**
66 | * Service is configured via @EnableActuatorsAndInterceptors
67 | */
68 | @Autowired
69 | private TraceRequestHandler traceRequestHandler;
70 |
71 | /**
72 | * Filter records and logs all HTTP requests.
73 | * This requires an implementation of {@link TraceRequestService}.
74 | */
75 | @Bean
76 | public FilterRegistrationBean requestIdFilterRegistrationBean() {
77 | FilterRegistrationBean filter = new FilterRegistrationBean();
78 | filter.setFilter(new RequestTraceFilter(appName, jpaTraceRequestService,
79 | Arrays.asList(new DefaultLoggingHandler(), traceRequestHandler)));
80 | filter.addUrlPatterns(ApiConstants.API_ROOT + "/*");
81 |
82 | return filter;
83 | }
84 |
85 | // ---------------------------------------
86 | // Swagger setup for the API documentation
87 | // ---------------------------------------
88 |
89 | // If you add spring security then you can easily secure these resources.
90 |
91 | @Override
92 | public void addViewControllers(ViewControllerRegistry registry) {
93 | registry.addRedirectViewController(ApiConstants.API_DOCS_ROOT + "/v2/api-docs", "/v2/api-docs");
94 | registry.addRedirectViewController(ApiConstants.API_DOCS_ROOT + "/configuration/ui", "/configuration/ui");
95 | registry.addRedirectViewController(ApiConstants.API_DOCS_ROOT +"/configuration/security", "/configuration/security");
96 | registry.addRedirectViewController(ApiConstants.API_DOCS_ROOT +"/swagger-resources", "/swagger-resources");
97 | registry.addRedirectViewController(ApiConstants.API_DOCS_ROOT, "/swagger-ui.html");
98 | }
99 |
100 | @Override
101 | public void addResourceHandlers(ResourceHandlerRegistry registry) {
102 | registry
103 | .addResourceHandler("/" + ApiConstants.API_DOCS_ROOT + "/**")
104 | .addResourceLocations("classpath:/META-INF/resources/");
105 | }
106 |
107 | public Docket createRestApi() {
108 | return new Docket(DocumentationType.SWAGGER_2)
109 | .apiInfo(apiInfo())
110 | .select()
111 | .apis(RequestHandlerSelectors.basePackage("de.michlb.demo.customer.rest.controller"))
112 | .paths(PathSelectors.any())
113 | .build();
114 | }
115 |
116 | private ApiInfo apiInfo() {
117 | return new ApiInfoBuilder()
118 | .title("API Documentation")
119 | .description("API Documentation")
120 | .termsOfServiceUrl("")
121 | .version("1.0")
122 | .build();
123 | }
124 |
125 | /**
126 | * Future datasource beans need to marked with {@link org.springframework.context.annotation.Primary}.
127 | * to prevent conflicts with the DS used by EnableTraceRequestJpa.
128 | */
129 |
130 | // ---------------------------
131 | // Main method to start Spring
132 | // ---------------------------
133 | public static void main(String[] args) {
134 | SpringApplication.run(Application.class, args);
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/customer/src/main/java/de/michlb/demo/customer/constant/ApiConstants.java:
--------------------------------------------------------------------------------
1 | package de.michlb.demo.customer.constant;
2 |
3 | /**
4 | *
5 | * Static string representation of the API's endpoints.
6 | *
7 | */
8 | public class ApiConstants {
9 |
10 | public static final String API_ROOT = "/api";
11 |
12 | public static final String API_HELP = API_ROOT + "/help";
13 |
14 | public static final String API_PING = API_ROOT + "/ping";
15 |
16 | public static final String API_DOCS_ROOT = "/docs";
17 |
18 | // Management root URI
19 | public static final String API_MAN_ROOT ="/admin";
20 |
21 | public static final String API_MAN_BUILD= API_MAN_ROOT + "/build";
22 |
23 | // Specific URI
24 | public static final String API_CUSTOMER_INFO = API_ROOT + "/customer/info";
25 | }
26 |
--------------------------------------------------------------------------------
/customer/src/main/java/de/michlb/demo/customer/constant/GlobalBusinessCodes.java:
--------------------------------------------------------------------------------
1 | package de.michlb.demo.customer.constant;
2 |
3 | import com.shedhack.exception.core.BusinessCode;
4 |
5 | /**
6 | *
7 | * Business Codes which are shared with clients.
8 | *
9 | */
10 | public enum GlobalBusinessCodes implements BusinessCode {
11 |
12 | C001("something"),
13 | C002("something+1");
14 |
15 | private final String description;
16 |
17 | GlobalBusinessCodes(String description) {
18 | this.description = description;
19 | }
20 |
21 | public String getDescription() {
22 | return this.description;
23 | }
24 |
25 | public String getCode() {
26 | return this.name();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/customer/src/main/java/de/michlb/demo/customer/controller/BuildController.java:
--------------------------------------------------------------------------------
1 | package de.michlb.demo.customer.controller;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.web.bind.annotation.RequestMapping;
5 | import org.springframework.web.bind.annotation.RestController;
6 |
7 | import javax.annotation.PostConstruct;
8 | import java.util.Map;
9 | import java.util.TreeMap;
10 |
11 | import de.michlb.demo.customer.constant.ApiConstants;
12 |
13 | /**
14 | * Provides build/git related details
15 | */
16 | @RestController
17 | public class BuildController {
18 |
19 | private TreeMap build = new TreeMap<>();
20 |
21 | @Value("${git.commit.id.abbrev}")
22 | private String gitCommitAbbrevVal;
23 | private static String gitCommitAbbrevKey = "git.commit.id.abbrev";
24 |
25 | @Value("${git.commit.user.email}")
26 | private String gitCommitEmailVal;
27 | private static String gitCommitEmailKey = "git.commit.user.email";
28 |
29 | @Value("${git.commit.message.full}")
30 | private String gitCommitMsgVal;
31 | private static String gitCommitMsgKey = "git.commit.message.full";
32 |
33 | @Value("${git.commit.id}")
34 | private String gitCommitIdVal;
35 | private static String gitCommitIdKey = "git.commit.id";
36 |
37 | @Value("${git.commit.user.name}")
38 | private String gitCommitUsernameVal;
39 | private static String gitCommitUsernamekey = "git.commit.user.name";
40 |
41 | @Value("${git.commit.id.describe}")
42 | private String gitCommitDescVal;
43 | private static String gitCommitDescKey = "git.commit.id.describe";
44 |
45 | @Value("${git.build.user.email}")
46 | private String gitBuildEmailVal;
47 | private static String gitBuildEmailKey = "git.build.user.email";
48 |
49 | @Value("${git.branch}")
50 | private String gitBranchVal;
51 | private static String gitBranchKey = "git.branch";
52 |
53 | @Value("${git.commit.time}")
54 | private String gitCommitTimeVal;
55 | private static String gitCommitTimeKey = "git.commit.time";
56 |
57 | @Value("${git.build.time}")
58 | private String gitBuildTimeVal;
59 | private static String gitBuildTimeKey = "git.build.time";
60 |
61 | @Value("${git.remote.origin.url}")
62 | private String gitOriginVal;
63 | private static String gitOriginKey = "git.remote.origin.url";
64 |
65 | @Value("${info.app.maven.version}")
66 | private String mavenVersionVal;
67 | private static String mavenVersionKey = "maven.version";
68 |
69 | @Value("${info.app.maven.artifactId}")
70 | private String mavenArtifactIdVal;
71 | private static String mavenArtifactIdKey = "maven.artifactId";
72 |
73 | @Value("${info.app.maven.groupId}")
74 | private String mavenGroupIdVal;
75 | private static String mavenGroupIdKey = "maven.groupId";
76 |
77 | @Value("${spring.profiles.active}")
78 | private String springProfileVal;
79 | private static String springProfileKey = "spring.profiles.active";
80 |
81 | @Value("${spring.application.name}")
82 | private String springAppNameVal;
83 | private static String springAppNameKey = "spring.application.name";
84 |
85 | @Value("${server.port}")
86 | private int springPortVal;
87 | private static String springPortKey = "spring.server.port";
88 |
89 | @PostConstruct
90 | public void setup() {
91 | build.put(springProfileKey, springProfileVal);
92 | build.put(springAppNameKey, springAppNameVal);
93 | build.put(springPortKey, springPortVal);
94 | build.put(mavenVersionKey, mavenVersionVal);
95 | build.put(mavenArtifactIdKey, mavenArtifactIdVal);
96 | build.put(mavenGroupIdKey, mavenGroupIdVal);
97 | build.put(gitCommitAbbrevKey, gitCommitAbbrevVal);
98 | build.put(gitCommitEmailKey, gitCommitEmailVal);
99 | build.put(gitCommitMsgKey, gitCommitMsgVal);
100 | build.put(gitCommitIdKey, gitCommitIdVal);
101 | build.put(gitCommitUsernamekey, gitCommitUsernameVal);
102 | build.put(gitCommitDescKey, gitCommitDescVal);
103 | build.put(gitBuildEmailKey, gitBuildEmailVal);
104 | build.put(gitBranchKey, gitBranchVal);
105 | build.put(gitCommitTimeKey, gitCommitTimeVal);
106 | build.put(gitBuildTimeKey, gitBuildTimeVal);
107 | build.put(gitOriginKey, gitOriginVal);
108 | }
109 |
110 | @RequestMapping(ApiConstants.API_MAN_BUILD)
111 | public Map build() {
112 | return build;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/customer/src/main/java/de/michlb/demo/customer/controller/CustomerController.java:
--------------------------------------------------------------------------------
1 | package de.michlb.demo.customer.controller;
2 |
3 | import de.michlb.demo.customer.constant.ApiConstants;
4 | import de.michlb.demo.customer.model.Customer;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | /**
14 | * This is an example controller with a feign client.
15 | */
16 | @RestController
17 | public class CustomerController {
18 |
19 | /**
20 | * Used to provide tools a HTTP 200 OK when service is running.
21 | */
22 | @RequestMapping(path = ApiConstants.API_CUSTOMER_INFO)
23 | public ResponseEntity info() {
24 | Customer customer = new Customer();
25 |
26 | customer.setFirstname("Michael");
27 | customer.setLastname("B.");
28 |
29 | return new ResponseEntity<>(customer, HttpStatus.OK);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/customer/src/main/java/de/michlb/demo/customer/controller/HelpController.java:
--------------------------------------------------------------------------------
1 | package de.michlb.demo.customer.controller;
2 |
3 | import de.michlb.demo.customer.constant.ApiConstants;
4 | import org.springframework.http.HttpStatus;
5 | import org.springframework.http.ResponseEntity;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | import javax.annotation.PostConstruct;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import de.michlb.demo.customer.constant.GlobalBusinessCodes;
14 |
15 | /**
16 | *
17 | * Controller provides clients with a definitive list of all HTTP and Business codes.
18 | *
19 | */
20 | @RestController
21 | public class HelpController {
22 |
23 | private Map