├── .gitignore
├── README.md
├── common
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── cn
│ │ └── springcloud
│ │ └── book
│ │ └── common
│ │ ├── config
│ │ └── CommonConfiguration.java
│ │ ├── context
│ │ ├── HystrixThreadCallable.java
│ │ ├── HystrixThreadLocal.java
│ │ ├── SpringCloudHystrixConcurrencyStrategy.java
│ │ ├── SpringContextManager.java
│ │ └── UserContextHolder.java
│ │ ├── exception
│ │ ├── BaseException.java
│ │ ├── BaseExceptionBody.java
│ │ └── CommonError.java
│ │ ├── intercepter
│ │ ├── FeignUserContextInterceptor.java
│ │ ├── RestTemplateUserContextInterceptor.java
│ │ └── UserContextInterceptor.java
│ │ ├── util
│ │ ├── AuthUtil.java
│ │ ├── ExceptionUtil.java
│ │ └── HttpConvertUtil.java
│ │ └── vo
│ │ └── User.java
│ └── resources
│ ├── META-INF
│ └── spring.factories
│ └── logback.xml
├── config-server
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── cn
│ │ └── springcloud
│ │ └── book
│ │ └── config
│ │ └── ConfigServerApplication.java
│ └── resources
│ └── application.yml
├── data-service
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── cn
│ │ └── springcloud
│ │ └── book
│ │ └── dataservice
│ │ ├── DataServiceApplication.java
│ │ ├── config
│ │ └── DataConfig.java
│ │ └── controller
│ │ └── DataController.java
│ └── resources
│ ├── application.yml
│ └── bootstrap.yml
├── eureka-server
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── cn
│ │ └── springcloud
│ │ └── book
│ │ └── eureka
│ │ └── EurekaServerApplication.java
│ └── resources
│ └── bootstrap.yml
├── hystrix-dashboard
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── cn
│ │ └── springcloud
│ │ └── book
│ │ └── HystrixDashboardTurbineApplication.java
│ └── resources
│ ├── application.yml
│ └── bootstrap.yml
├── images
├── application-run.png
├── architecture.png
├── auth-filter.png
├── eureka.png
├── postman.png
└── source-code.png
├── pom.xml
├── user-service
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── cn
│ │ └── springcloud
│ │ └── book
│ │ └── user
│ │ ├── UserServiceApplication.java
│ │ ├── controller
│ │ └── UserController.java
│ │ └── service
│ │ ├── IUserService.java
│ │ ├── dataservice
│ │ └── DataService.java
│ │ ├── fallback
│ │ └── UserClientFallback.java
│ │ └── impl
│ │ └── UserService.java
│ └── resources
│ ├── application.yml
│ └── bootstrap.yml
└── zuul-server
├── pom.xml
└── src
└── main
├── java
└── cn
│ └── springcloud
│ └── book
│ ├── ZuulServerApplication.java
│ └── filter
│ ├── AuthFilter.java
│ └── ZuulFallback.java
└── resources
├── application.yml
└── bootstrap.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | # .gitignore
2 | .idea
3 | *.iml
4 | *.log
5 |
6 | */target/*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spring Cloud微服务项目完整示例
2 |
3 | 目的是为了演示基于Spring Cloud微服务框架,搭建一个接近业务实际场景的项目,只实现了后端项目,前端可以使用VUE或者其他框架。后端框架包括注册中心 Eureka、配置中心Spring Cloud Config、API网关Zuul、客户端负载均衡Ribbon、断路器Hystrix,同时还包括2个后端业务服务,一个用户服务sc-user-service,另一个是数据服务 sc-data-service。
4 |
5 | ## 技术架构图
6 |
7 | 用户从浏览器发起请求,经过浏览器,请求到达Nginx,打开前端页面,由前端页面发起请求后端服务,当请求到达后端Nginx后,Nginx对网关层进行负载,因为网关也需要做HA。此时网关Gateway 接收到请求后,根据请求路径进行动态路由,根据服务发现是User Service 中的服务,则从Ribbon 中选择一台 User Service的实例进行调用,由User Service 返回数据,如果此时User Service 需要使用Data Service的数据,则选择一台Data Service的实例进行调用,然后数据给前端,流程结束。
8 |
9 | 
10 |
11 | ## 具体实现
12 |
13 | 项目结构如下所示,从module名称,即可理解每个项目的作用了。
14 |
15 | 其中common是一个公共基础包,方便给后台服务引用。
16 |
17 | 
18 |
19 | ## 运行微服务应用
20 |
21 | 按顺序启动 eureka、zuul-server、data-service、user-service,另外的hystrix-dashboard和config-server 是可行的module。如下图所示,可以看到每个应用的运行端口号。
22 |
23 | 
24 |
25 | 访问 eureka UI,查看服务注册情况。
26 |
27 |
28 |
29 | 每个服务都正常注册到 eureka 注册中心了。
30 |
31 | 
32 |
33 | 通过网关,访问如下URL,获取context user 信息:
34 |
35 | http://localhost:7777/sc-user-service/getContextUserId
36 |
37 | 返回如下结果:{"exceptionType":"[cn.springcloud.book.common.exception.BaseException","code":10001,"businessId":1,"businessMessage":"the user is null, please check","codeEN":"AuthEmptyError"}
38 |
39 | 这是鉴权 filter 返回的异常信息,因为没有在请求头中获取到x-customs-user信息。
40 |
41 | 
42 |
43 | 通过Postman,在请求头中添加 x-customs-user=rickie 信息,然后再次访问URL。
44 |
45 |
46 | 如下图所示,目前返回结果正常。
47 |
48 | 
--------------------------------------------------------------------------------
/common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | cn.springcloud.book
7 | ch10-1
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 | common
12 | common
13 |
14 |
15 |
16 | org.springframework.cloud
17 | spring-cloud-starter-openfeign
18 |
19 |
20 | com.alibaba
21 | fastjson
22 | 1.2.31
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/config/CommonConfiguration.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.config;
2 |
3 | import feign.Feign;
4 |
5 | import javax.annotation.PostConstruct;
6 |
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
9 | import org.springframework.cloud.client.loadbalancer.LoadBalanced;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.Configuration;
12 | import org.springframework.web.client.RestTemplate;
13 | import org.springframework.web.servlet.config.annotation.EnableWebMvc;
14 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
15 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
16 | import org.springframework.web.servlet.mvc.Controller;
17 |
18 | import com.netflix.hystrix.strategy.HystrixPlugins;
19 | import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
20 |
21 | import cn.springcloud.book.common.context.SpringCloudHystrixConcurrencyStrategy;
22 | import cn.springcloud.book.common.intercepter.FeignUserContextInterceptor;
23 | import cn.springcloud.book.common.intercepter.RestTemplateUserContextInterceptor;
24 | import cn.springcloud.book.common.intercepter.UserContextInterceptor;
25 |
26 | @Configuration
27 | @EnableWebMvc
28 | public class CommonConfiguration extends WebMvcConfigurerAdapter{
29 | /**
30 | * 请求拦截器
31 | */
32 | @Override
33 | public void addInterceptors(InterceptorRegistry registry) {
34 | registry.addInterceptor(new UserContextInterceptor());
35 | }
36 |
37 | /**
38 | * 创建Feign请求拦截器,在发送请求前设置认证的用户上下文信息
39 | */
40 | @Bean
41 | @ConditionalOnClass(Feign.class)
42 | public FeignUserContextInterceptor feignTokenInterceptor() {
43 | return new FeignUserContextInterceptor();
44 | }
45 |
46 | /**
47 | * RestTemplate拦截器
48 | * @return
49 | */
50 | @LoadBalanced
51 | @Bean
52 | public RestTemplate restTemplate() {
53 | RestTemplate restTemplate = new RestTemplate();
54 | restTemplate.getInterceptors().add(new RestTemplateUserContextInterceptor());
55 | return restTemplate;
56 | }
57 |
58 | @Bean
59 | public SpringCloudHystrixConcurrencyStrategy springCloudHystrixConcurrencyStrategy() {
60 | return new SpringCloudHystrixConcurrencyStrategy();
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/context/HystrixThreadCallable.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.context;
2 | import java.util.concurrent.Callable;
3 |
4 | import org.springframework.web.context.request.RequestAttributes;
5 | import org.springframework.web.context.request.RequestContextHolder;
6 |
7 | public class HystrixThreadCallable implements Callable{
8 | private final RequestAttributes requestAttributes;
9 | private final Callable delegate;
10 | private String params;
11 |
12 | public HystrixThreadCallable(Callable callable, RequestAttributes requestAttributes,String params) {
13 | this.delegate = callable;
14 | this.requestAttributes = requestAttributes;
15 | this.params = params;
16 | }
17 |
18 | @Override
19 | public S call() throws Exception {
20 | try {
21 | RequestContextHolder.setRequestAttributes(requestAttributes);
22 | HystrixThreadLocal.threadLocal.set(params);
23 | return delegate.call();
24 | } finally {
25 | RequestContextHolder.resetRequestAttributes();
26 | HystrixThreadLocal.threadLocal.remove();
27 | }
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/context/HystrixThreadLocal.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.context;
2 |
3 | public class HystrixThreadLocal {
4 | public static ThreadLocal threadLocal = new ThreadLocal<>();
5 | }
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/context/SpringCloudHystrixConcurrencyStrategy.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.context;
2 |
3 | import java.util.concurrent.BlockingQueue;
4 | import java.util.concurrent.Callable;
5 | import java.util.concurrent.ThreadPoolExecutor;
6 | import java.util.concurrent.TimeUnit;
7 |
8 | import org.springframework.web.context.request.RequestContextHolder;
9 |
10 | import com.netflix.hystrix.HystrixThreadPoolKey;
11 | import com.netflix.hystrix.HystrixThreadPoolProperties;
12 | import com.netflix.hystrix.strategy.HystrixPlugins;
13 | import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
14 | import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
15 | import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
16 | import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
17 | import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
18 | import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
19 | import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
20 | import com.netflix.hystrix.strategy.properties.HystrixProperty;
21 |
22 | public class SpringCloudHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
23 | private HystrixConcurrencyStrategy delegateHystrixConcurrencyStrategy;
24 |
25 | @Override
26 | public Callable wrapCallable(Callable callable) {
27 | return new HystrixThreadCallable<>(callable, RequestContextHolder.getRequestAttributes(),HystrixThreadLocal.threadLocal.get());
28 | }
29 |
30 | public SpringCloudHystrixConcurrencyStrategy() {
31 | init();
32 | }
33 |
34 | private void init() {
35 | try {
36 | this.delegateHystrixConcurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
37 | if (this.delegateHystrixConcurrencyStrategy instanceof SpringCloudHystrixConcurrencyStrategy) {
38 | return;
39 | }
40 |
41 | HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins.getInstance().getCommandExecutionHook();
42 | HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
43 | HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
44 | HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance().getPropertiesStrategy();
45 |
46 | HystrixPlugins.reset();
47 | HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
48 | HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
49 | HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
50 | HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
51 | HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
52 | }
53 | catch (Exception e) {
54 | throw e;
55 | }
56 | }
57 |
58 |
59 | @Override
60 | public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
61 | HystrixProperty corePoolSize,
62 | HystrixProperty maximumPoolSize,
63 | HystrixProperty keepAliveTime, TimeUnit unit,
64 | BlockingQueue workQueue) {
65 | return this.delegateHystrixConcurrencyStrategy.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize,
66 | keepAliveTime, unit, workQueue);
67 | }
68 |
69 | @Override
70 | public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
71 | HystrixThreadPoolProperties threadPoolProperties) {
72 | return this.delegateHystrixConcurrencyStrategy.getThreadPool(threadPoolKey, threadPoolProperties);
73 | }
74 |
75 | @Override
76 | public BlockingQueue getBlockingQueue(int maxQueueSize) {
77 | return this.delegateHystrixConcurrencyStrategy.getBlockingQueue(maxQueueSize);
78 | }
79 |
80 | @Override
81 | public HystrixRequestVariable getRequestVariable(
82 | HystrixRequestVariableLifecycle rv) {
83 | return this.delegateHystrixConcurrencyStrategy.getRequestVariable(rv);
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/context/SpringContextManager.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.context;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 |
8 | /**
9 | * Spring上下文管理工具
10 | */
11 | @Component
12 | public class SpringContextManager implements ApplicationContextAware {
13 | private static ApplicationContext applicationContext;
14 |
15 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
16 | SpringContextManager.applicationContext = applicationContext;
17 | }
18 |
19 | /**
20 | * 获取上下文
21 | *
22 | * @return Spring上下文
23 | */
24 | public static ApplicationContext getApplicationContext() {
25 | return applicationContext;
26 | }
27 |
28 | /**
29 | * 获取Spring配置
30 | * @param key 配置名称
31 | * @return 配置值
32 | */
33 | public static String getProperties(String key) {
34 | return applicationContext.getEnvironment().getProperty(key);
35 | }
36 |
37 | /**
38 | * 获取Spring配置
39 | * 没有配置时,返回默认值
40 | * @param key 配置名称
41 | * @param defaultValue 默认值
42 | * @return 配置值
43 | */
44 | public static String getProperties(String key, String defaultValue) {
45 | return applicationContext.getEnvironment().getProperty(key, defaultValue);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/context/UserContextHolder.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.context;
2 |
3 | import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
4 | import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableDefault;
5 |
6 | import cn.springcloud.book.common.vo.User;
7 |
8 | /**
9 | * 用户上下文
10 | * @author zhudeming
11 | */
12 | public class UserContextHolder {
13 |
14 | public static ThreadLocal context = new ThreadLocal();
15 |
16 | public static User currentUser() {
17 | return context.get();
18 | }
19 |
20 | public static void set(User user) {
21 | context.set(user);
22 | }
23 |
24 | public static void shutdown() {
25 | context.remove();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/exception/BaseException.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.exception;
2 |
3 | public class BaseException extends RuntimeException {
4 |
5 | private static final long serialVersionUID = 1796731834836398434L;
6 | private Long businessId;
7 | private Integer code;
8 | private String codeEN;
9 | private String businessMessage;
10 |
11 | public Long getBusinessId() {
12 | return businessId;
13 | }
14 |
15 | public void setBusinessId(Long businessId) {
16 | this.businessId = businessId;
17 | }
18 |
19 | public Integer getCode() {
20 | return code;
21 | }
22 |
23 | public void setCode(Integer code) {
24 | this.code = code;
25 | }
26 |
27 | public String getCodeEN() {
28 | return codeEN;
29 | }
30 |
31 | public void setCodeEN(String codeEN) {
32 | this.codeEN = codeEN;
33 | }
34 |
35 | public String getBusinessMessage() {
36 | return businessMessage;
37 | }
38 |
39 | public void setBusinessMessage(String businessMessage) {
40 | this.businessMessage = businessMessage;
41 | }
42 |
43 | /**
44 | * 基础异常
45 | *
46 | * @param code 异常编码:数字
47 | * @param codeEN 异常编码:英文短语
48 | * @param message 异常信息
49 | * @param businessId 相关业务ID
50 | */
51 | public BaseException(Integer code, String codeEN, String message, Long businessId) {
52 | this(code, codeEN, message, businessId, null);
53 | }
54 |
55 | public BaseException(Integer code, String codeEN, String message, Long businessId, Throwable t) {
56 | super(message, t);
57 | this.businessId = businessId;
58 | this.code = code;
59 | this.codeEN = codeEN;
60 | this.businessMessage = message;
61 | }
62 |
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/exception/BaseExceptionBody.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.exception;
2 |
3 | import java.io.Serializable;
4 |
5 | public class BaseExceptionBody implements Serializable {
6 |
7 | /**
8 | * serialVersionUID
9 | */
10 | private static final long serialVersionUID = -1270478894426234738L;
11 |
12 | /**
13 | * 相关业务ID
14 | */
15 | private Long businessId;
16 |
17 | /**
18 | * 异常编码:数字
19 | */
20 | private Integer code;
21 |
22 | /**
23 | * 异常编码:英文短语
24 | */
25 | private String codeEN;
26 |
27 | /**
28 | * 异常信息
29 | */
30 | private String businessMessage;
31 |
32 | /**
33 | * 异常类型
34 | */
35 | private String exceptionType;
36 |
37 |
38 |
39 | public Long getBusinessId() {
40 | return businessId;
41 | }
42 |
43 | public void setBusinessId(Long businessId) {
44 | this.businessId = businessId;
45 | }
46 |
47 | public Integer getCode() {
48 | return code;
49 | }
50 |
51 | public void setCode(Integer code) {
52 | this.code = code;
53 | }
54 |
55 | public String getCodeEN() {
56 | return codeEN;
57 | }
58 |
59 | public void setCodeEN(String codeEN) {
60 | this.codeEN = codeEN;
61 | }
62 |
63 | public String getBusinessMessage() {
64 | return businessMessage;
65 | }
66 |
67 | public void setBusinessMessage(String businessMessage) {
68 | this.businessMessage = businessMessage;
69 | }
70 |
71 | public String getExceptionType() {
72 | return exceptionType;
73 | }
74 |
75 | public void setExceptionType(String exceptionType) {
76 | this.exceptionType = exceptionType;
77 | }
78 |
79 | public BaseExceptionBody() {
80 |
81 | }
82 |
83 | public BaseExceptionBody(BaseException exception) {
84 | this.businessId = exception.getBusinessId();
85 | this.code = exception.getCode();
86 | this.codeEN = exception.getCodeEN();
87 | this.businessMessage = exception.getMessage();
88 | this.exceptionType = exception.getClass().getName();
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/exception/CommonError.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.exception;
2 |
3 | import cn.springcloud.book.common.util.ExceptionUtil;
4 |
5 | /**
6 | * 通用异常信息
7 | */
8 | public enum CommonError {
9 |
10 | /**
11 | * 1001, "用户信息为空"
12 | */
13 | AUTH_EMPTY_ERROR(10001, "the user is null, please check");
14 |
15 | private Integer code;
16 | private String message;
17 |
18 | CommonError(Integer code, String message) {
19 | this.code = code;
20 | this.message = message;
21 | }
22 |
23 | public Integer getCode() {
24 | return code;
25 | }
26 |
27 | public void setCode(Integer code) {
28 | this.code = code;
29 | }
30 |
31 | public String getMessage() {
32 | return message;
33 | }
34 |
35 | public void setMessage(String message) {
36 | this.message = message;
37 | }
38 |
39 | public String getCodeEn() {
40 | return ExceptionUtil.errorToCodeEN(this);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/intercepter/FeignUserContextInterceptor.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.intercepter;
2 |
3 | import java.util.Enumeration;
4 |
5 | import javax.servlet.http.HttpServletRequest;
6 |
7 | import org.springframework.web.context.request.RequestContextHolder;
8 | import org.springframework.web.context.request.ServletRequestAttributes;
9 |
10 | import feign.RequestInterceptor;
11 | import feign.RequestTemplate;
12 |
13 | /**
14 | * Feign传递用户上下文
15 | * @author zhudeming
16 | */
17 | public class FeignUserContextInterceptor implements RequestInterceptor {
18 |
19 | @Override
20 | public void apply(RequestTemplate template) {
21 | // User user = UserContextHolder.currentUser();
22 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
23 | .getRequestAttributes();
24 | HttpServletRequest request = attributes.getRequest();
25 | Enumeration headerNames = request.getHeaderNames();
26 | if (headerNames != null) {
27 | while (headerNames.hasMoreElements()) {
28 | String name = headerNames.nextElement();
29 | String values = request.getHeader(name);
30 | template.header(name, values);
31 | }
32 | }
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/intercepter/RestTemplateUserContextInterceptor.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.intercepter;
2 |
3 | import java.io.IOException;
4 | import java.util.Map;
5 |
6 | import org.springframework.http.HttpRequest;
7 | import org.springframework.http.client.ClientHttpRequestExecution;
8 | import org.springframework.http.client.ClientHttpRequestInterceptor;
9 | import org.springframework.http.client.ClientHttpResponse;
10 |
11 | import cn.springcloud.book.common.context.UserContextHolder;
12 | import cn.springcloud.book.common.vo.User;
13 |
14 | /**
15 | * RestTemplate传递用户上下文
16 | * @author zhudeming
17 | */
18 | public class RestTemplateUserContextInterceptor implements ClientHttpRequestInterceptor {
19 |
20 | @Override
21 | public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
22 | throws IOException {
23 | User user = UserContextHolder.currentUser();
24 | Map headers = user.toHttpHeaders();
25 | for (Map.Entry header : headers.entrySet()) {
26 | request.getHeaders().add(header.getKey(), header.getValue());
27 | }
28 | // 调用
29 | return execution.execute(request, body);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/intercepter/UserContextInterceptor.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.intercepter;
2 |
3 | import javax.servlet.http.HttpServletRequest;
4 | import javax.servlet.http.HttpServletResponse;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.util.StringUtils;
9 | import org.springframework.web.servlet.HandlerInterceptor;
10 | import org.springframework.web.servlet.ModelAndView;
11 |
12 | import cn.springcloud.book.common.context.UserContextHolder;
13 | import cn.springcloud.book.common.util.HttpConvertUtil;
14 | import cn.springcloud.book.common.vo.User;
15 |
16 | public class UserContextInterceptor implements HandlerInterceptor {
17 | private static final Logger log = LoggerFactory.getLogger(UserContextInterceptor.class);
18 |
19 | @Override
20 | public boolean preHandle(HttpServletRequest request, HttpServletResponse respone, Object arg2) throws Exception {
21 | User user = new User(HttpConvertUtil.httpRequestToMap(request));
22 | if(StringUtils.isEmpty(user.getUserId()) && StringUtils.isEmpty(user.getUserName())) {
23 | log.error("the user is null, please access from gateway or check user info");
24 | return false;
25 | }
26 | UserContextHolder.set(user);
27 | return true;
28 | }
29 |
30 | @Override
31 | public void postHandle(HttpServletRequest request, HttpServletResponse respone, Object arg2, ModelAndView arg3)
32 | throws Exception {
33 | // DOING NOTHING
34 | }
35 |
36 | @Override
37 | public void afterCompletion(HttpServletRequest request, HttpServletResponse respone, Object arg2, Exception arg3)
38 | throws Exception {
39 | UserContextHolder.shutdown();
40 | }
41 |
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/util/AuthUtil.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.util;
2 | import javax.servlet.http.HttpServletResponse;
3 | import org.springframework.util.StringUtils;
4 |
5 | import cn.springcloud.book.common.vo.User;
6 |
7 | public class AuthUtil {
8 | public static boolean authUser(User user, HttpServletResponse respone) throws Exception{
9 | if(StringUtils.isEmpty(user.getUserId())) {
10 | return false;
11 | }else {
12 | return true;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/util/ExceptionUtil.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.util;
2 |
3 | import org.apache.commons.lang.StringUtils;
4 |
5 | /**
6 | */
7 | public class ExceptionUtil {
8 |
9 | /**
10 | * 异常枚举转类型换为英文code
11 | * @param error 异常枚举
12 | * @return 大驼峰编码
13 | */
14 | public static String errorToCodeEN(Enum> error) {
15 | String errorName = error.name().toLowerCase();
16 | String[] sp = errorName.split("_");
17 | StringBuffer code = new StringBuffer();
18 | for (String s : sp) {
19 | code.append(StringUtils.capitalize(s));
20 | }
21 | return code.toString();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/util/HttpConvertUtil.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.util;
2 |
3 | import javax.servlet.http.HttpServletRequest;
4 | import java.util.Enumeration;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | public class HttpConvertUtil {
9 |
10 | /**
11 | * convert the httpServletRequest headers to headers map
12 | * @param request
13 | * @return
14 | */
15 | public static Map httpRequestToMap(HttpServletRequest request) {
16 | Enumeration headerNames = request.getHeaderNames();
17 | Map headers = new HashMap<>();
18 | while (headerNames.hasMoreElements()) {
19 | String headerName = headerNames.nextElement();
20 | headers.put(headerName, request.getHeader(headerName));
21 | }
22 | return headers;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/common/src/main/java/cn/springcloud/book/common/vo/User.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.common.vo;
2 |
3 |
4 | import java.io.Serializable;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | import org.springframework.util.StringUtils;
9 |
10 | import cn.springcloud.book.common.exception.BaseException;
11 | import cn.springcloud.book.common.exception.CommonError;
12 |
13 |
14 | /**
15 | * 用户对象
16 | * @author zhudeming
17 | *
18 | */
19 | public class User implements Serializable {
20 |
21 | /**
22 | *
23 | */
24 | private static final long serialVersionUID = -4083327605430665846L;
25 |
26 | public final static String CONTEXT_KEY_USERID = "x-customs-user";
27 |
28 | /**
29 | * 用户ID
30 | */
31 | private String userId;
32 |
33 | private String userName;
34 |
35 | public String getUserName() {
36 | return userName;
37 | }
38 |
39 | public void setUserName(String userName) {
40 | this.userName = userName;
41 | }
42 |
43 | public String getUserId() {
44 | return userId;
45 | }
46 |
47 | public void setUserId(String userId) {
48 | this.userId = userId;
49 | }
50 |
51 |
52 | public User() {
53 |
54 | }
55 |
56 | public User(Map headers) {
57 | userId = headers.get(CONTEXT_KEY_USERID);
58 | }
59 |
60 |
61 | /**
62 | * 将user对象转换成为http对象头
63 | * @return http头键值对
64 | */
65 | public Map toHttpHeaders() {
66 | Map headers = new HashMap<>();
67 | headers.put(CONTEXT_KEY_USERID,userId);
68 | return headers;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/common/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | cn.springcloud.book.common.config.CommonConfiguration
--------------------------------------------------------------------------------
/common/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %d{HH:mm:ss.SSS} %-5level [%thread] %-50logger{50} - %msg%n
8 |
9 |
10 |
11 | ${LOG_FILE:-Startup}.log
12 |
13 |
14 | ${LOG_FILE:-Startup}.%d{yyyy-MM-dd}.%i.log
15 |
16 | 7
17 | 100MB
18 | 1GB
19 |
20 |
21 | %d{HH:mm:ss.SSS} %-5level [%thread] %logger{50} - %msg%n
22 | UTF-8
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/config-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | cn.springcloud.book
7 | ch10-1
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | config-server
13 |
14 |
15 |
16 | org.springframework.cloud
17 | spring-cloud-config-server
18 |
19 |
20 |
21 |
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-maven-plugin
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/config-server/src/main/java/cn/springcloud/book/config/ConfigServerApplication.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.config;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.config.server.EnableConfigServer;
6 |
7 | /**
8 | * @description : 配置中心
9 | */
10 | @SpringBootApplication
11 | @EnableConfigServer
12 | public class ConfigServerApplication {
13 |
14 | public static void main(String[] args) {
15 | SpringApplication.run(ConfigServerApplication.class, args);
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/config-server/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9090
3 | spring:
4 | cloud:
5 | config:
6 | server:
7 | git:
8 | uri: https://gitee.com/zhudeming/spring-cloud-config.git
9 | #username:
10 | #password:
11 | search-paths: SC-BOOK-CONFIG
12 | application:
13 | name: sc-configserver
14 |
--------------------------------------------------------------------------------
/data-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | cn.springcloud.book
7 | ch10-1
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 | data-service
12 | jar
13 | data-service
14 |
15 |
16 |
17 | cn.springcloud.book
18 | common
19 | ${parent.version}
20 |
21 |
22 | org.springframework.cloud
23 | spring-cloud-starter-netflix-eureka-client
24 |
25 |
26 | org.springframework.cloud
27 | spring-cloud-starter-netflix-hystrix
28 |
29 |
30 | org.springframework.cloud
31 | spring-cloud-config-client
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-web
36 |
37 |
38 |
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-maven-plugin
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/data-service/src/main/java/cn/springcloud/book/dataservice/DataServiceApplication.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.dataservice;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7 |
8 | /**
9 | * 数据服务
10 | * @author zhudeming
11 | */
12 | @SpringBootApplication
13 | @EnableDiscoveryClient
14 | @EnableCircuitBreaker
15 | public class DataServiceApplication {
16 |
17 | public static void main(String[] args) {
18 | SpringApplication.run(DataServiceApplication.class, args);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/data-service/src/main/java/cn/springcloud/book/dataservice/config/DataConfig.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.dataservice.config;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 | import org.springframework.stereotype.Component;
5 |
6 | /**
7 | * @author: zhudeming
8 | * @description : 配置信息
9 | */
10 | @Component
11 | @ConfigurationProperties(prefix = "cn.springcloud.book")
12 | public class DataConfig {
13 |
14 | private String defaultUser;
15 |
16 | public String getDefaultUser() {
17 | return defaultUser;
18 | }
19 |
20 | public void setDefaultUser(String defaultUser) {
21 | this.defaultUser = defaultUser;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/data-service/src/main/java/cn/springcloud/book/dataservice/controller/DataController.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.dataservice.controller;
2 |
3 | import cn.springcloud.book.common.context.UserContextHolder;
4 | import cn.springcloud.book.dataservice.config.DataConfig;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.beans.factory.annotation.Value;
11 | import org.springframework.web.bind.annotation.GetMapping;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RequestMethod;
14 | import org.springframework.web.bind.annotation.RestController;
15 |
16 | /**
17 | * @author: zhudeming
18 | */
19 | @RestController
20 | public class DataController {
21 |
22 | @Autowired
23 | private DataConfig dataConfig;
24 |
25 | @GetMapping("/getContextUserId")
26 | public String getContextUserId(){
27 | return UserContextHolder.currentUser().getUserId();
28 | }
29 |
30 | @GetMapping("/getDefaultUser")
31 | public String getDefaultUser(){
32 | return dataConfig.getDefaultUser();
33 | }
34 |
35 | @GetMapping("/getProviderData")
36 | public List getProviderData(){
37 | List provider = new ArrayList();
38 | provider.add("Beijing Company");
39 | provider.add("Shanghai Company");
40 | provider.add("Shenzhen Company");
41 | return provider;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/data-service/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: sc-data-service
4 | eureka:
5 | client:
6 | serviceUrl:
7 | defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
8 | instance:
9 | prefer-ip-address: true
10 | management:
11 | security:
12 | enabled: false
13 | endpoints:
14 | web:
15 | exposure:
16 | include: hystrix.stream
17 |
--------------------------------------------------------------------------------
/data-service/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8099
3 |
4 | spring:
5 | cloud:
6 | config:
7 | label: master
8 | uri: http://localhost:9090
9 | name: config-info
10 | profile: dev
11 | application:
12 | name: sc-data-service
13 |
--------------------------------------------------------------------------------
/eureka-server/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | cn.springcloud.book
6 | ch10-1
7 | 0.0.1-SNAPSHOT
8 |
9 | eureka-server
10 | jar
11 |
12 | UTF-8
13 | 1.8
14 |
15 |
16 |
17 |
18 | org.springframework.cloud
19 | spring-cloud-starter-netflix-eureka-server
20 |
21 |
22 |
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-maven-plugin
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/eureka-server/src/main/java/cn/springcloud/book/eureka/EurekaServerApplication.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.eureka;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
6 |
7 | /**
8 | * eureka server
9 | */
10 | @SpringBootApplication
11 | @EnableEurekaServer
12 | public class EurekaServerApplication {
13 |
14 | public static void main(String[] args) {
15 | SpringApplication.run(EurekaServerApplication.class, args);
16 | }
17 | }
--------------------------------------------------------------------------------
/eureka-server/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8761
3 | spring:
4 | application:
5 | name: sc-eurekaserver
6 | eureka:
7 | client:
8 | registerWithEureka: false
9 | fetchRegistry: false
--------------------------------------------------------------------------------
/hystrix-dashboard/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | cn.springcloud.book
7 | ch10-1
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 | hystrix-dashboard
12 | jar
13 | hystrix-dashboard
14 |
15 |
16 |
17 | org.springframework.cloud
18 | spring-cloud-starter-netflix-hystrix-dashboard
19 |
20 |
21 | org.springframework.cloud
22 | spring-cloud-starter-netflix-hystrix
23 |
24 |
25 | org.springframework.cloud
26 | spring-cloud-starter-netflix-turbine
27 |
28 |
29 | org.springframework.cloud
30 | spring-cloud-starter-netflix-eureka-client
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-maven-plugin
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/hystrix-dashboard/src/main/java/cn/springcloud/book/HystrixDashboardTurbineApplication.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
7 | import org.springframework.cloud.netflix.turbine.EnableTurbine;
8 |
9 | /**
10 | * @author zhudeming
11 | */
12 | @SpringBootApplication
13 | @EnableDiscoveryClient
14 | @EnableTurbine
15 | @EnableHystrixDashboard
16 | public class HystrixDashboardTurbineApplication {
17 |
18 | public static void main(String[] args) {
19 | SpringApplication.run(HystrixDashboardTurbineApplication.class, args);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/hystrix-dashboard/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
5 | instance:
6 | prefer-ip-address: true
7 | management:
8 | security:
9 | enabled: false
10 | endpoints:
11 | web:
12 | exposure:
13 | include: hystrix.stream
14 | turbine:
15 | appConfig: sc-user-service,sc-zuul-service,sc-data-service
16 | clusterNameExpression: "'default'"
--------------------------------------------------------------------------------
/hystrix-dashboard/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9099
3 | spring:
4 | cloud:
5 | config:
6 | label: master
7 | uri: http://localhost:9090
8 | name: config-info
9 | profile: dev
10 | application:
11 | name: sc-hystrix-dashboard
12 |
--------------------------------------------------------------------------------
/images/application-run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/a3d040c9657bd251060f061a20ab7848d115ac88/images/application-run.png
--------------------------------------------------------------------------------
/images/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/a3d040c9657bd251060f061a20ab7848d115ac88/images/architecture.png
--------------------------------------------------------------------------------
/images/auth-filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/a3d040c9657bd251060f061a20ab7848d115ac88/images/auth-filter.png
--------------------------------------------------------------------------------
/images/eureka.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/a3d040c9657bd251060f061a20ab7848d115ac88/images/eureka.png
--------------------------------------------------------------------------------
/images/postman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/a3d040c9657bd251060f061a20ab7848d115ac88/images/postman.png
--------------------------------------------------------------------------------
/images/source-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/a3d040c9657bd251060f061a20ab7848d115ac88/images/source-code.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | org.springframework.boot
5 | spring-boot-starter-parent
6 | 2.0.3.RELEASE
7 |
8 | 4.0.0
9 | cn.springcloud.book
10 | ch10-1
11 | pom
12 | 0.0.1-SNAPSHOT
13 | ch10-1
14 | http://springcloud.cn
15 |
16 |
17 | eureka-server
18 | config-server
19 | zuul-server
20 | user-service
21 | common
22 | data-service
23 | hystrix-dashboard
24 |
25 |
26 |
27 | UTF-8
28 | 1.8
29 | Finchley.RELEASE
30 | 0.0.1-SNAPSHOT
31 |
32 |
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-web
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-actuator
41 |
42 |
43 |
44 |
45 |
46 |
47 | org.springframework.cloud
48 | spring-cloud-dependencies
49 | ${spring-cloud.version}
50 | pom
51 | import
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/user-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | cn.springcloud.book
7 | ch10-1
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 | user-service
12 | jar
13 | user-service
14 |
15 |
16 |
17 | cn.springcloud.book
18 | common
19 | ${project.parent.version}
20 |
21 |
22 | org.springframework.cloud
23 | spring-cloud-starter-netflix-eureka-client
24 |
25 |
26 | org.springframework.cloud
27 | spring-cloud-starter-netflix-hystrix
28 |
29 |
30 | org.springframework.cloud
31 | spring-cloud-config-client
32 |
33 |
34 |
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-maven-plugin
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/user-service/src/main/java/cn/springcloud/book/user/UserServiceApplication.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.user;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7 | import org.springframework.cloud.netflix.hystrix.EnableHystrix;
8 | import org.springframework.cloud.openfeign.EnableFeignClients;
9 |
10 | /**
11 | * @author zhudeming
12 | */
13 | @SpringBootApplication
14 | @EnableDiscoveryClient
15 | @EnableFeignClients
16 | @EnableCircuitBreaker
17 | public class UserServiceApplication {
18 |
19 | public static void main(String[] args) {
20 | SpringApplication.run(UserServiceApplication.class, args);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/user-service/src/main/java/cn/springcloud/book/user/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.user.controller;
2 |
3 |
4 | import java.util.List;
5 |
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 |
10 | import cn.springcloud.book.user.service.IUserService;
11 |
12 | /**
13 | *
14 | */
15 | @RestController
16 | public class UserController {
17 |
18 | @Autowired
19 | private IUserService userService;
20 |
21 | /**
22 | * 获取配置文件中系统默认用户
23 | * @return
24 | */
25 | @GetMapping("/getDefaultUser")
26 | public String getDefaultUser(){
27 | return userService.getDefaultUser();
28 | }
29 |
30 | /**
31 | * 获取上下文用户
32 | * @return
33 | */
34 | @GetMapping("/getContextUserId")
35 | public String getContextUserId(){
36 | return userService.getContextUserId();
37 | }
38 |
39 | /**
40 | * 获取供应商数据
41 | * @return
42 | */
43 | @GetMapping("/getProviderData")
44 | public List getProviderData(){
45 | return userService.getProviderData();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/user-service/src/main/java/cn/springcloud/book/user/service/IUserService.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.user.service;
2 |
3 |
4 | import java.util.List;
5 |
6 | /**
7 | */
8 | public interface IUserService {
9 | public String getDefaultUser();
10 | public String getContextUserId();
11 | public List getProviderData();
12 | }
13 |
--------------------------------------------------------------------------------
/user-service/src/main/java/cn/springcloud/book/user/service/dataservice/DataService.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.user.service.dataservice;
2 |
3 |
4 | import org.springframework.cloud.openfeign.FeignClient;
5 | import org.springframework.web.bind.annotation.RequestMapping;
6 | import org.springframework.web.bind.annotation.RequestMethod;
7 |
8 | import cn.springcloud.book.user.service.fallback.UserClientFallback;
9 |
10 |
11 | /**
12 | * feign调用数据服务
13 | * @author zhudeming
14 | *
15 | */
16 | @FeignClient(name = "sc-data-service", fallback=UserClientFallback.class)
17 | public interface DataService {
18 |
19 | @RequestMapping(value = "/getDefaultUser", method = RequestMethod.GET)
20 | public String getDefaultUser();
21 |
22 | @RequestMapping(value = "/getContextUserId", method = RequestMethod.GET)
23 | public String getContextUserId();
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/user-service/src/main/java/cn/springcloud/book/user/service/fallback/UserClientFallback.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.user.service.fallback;
2 |
3 |
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | import org.springframework.stereotype.Component;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RequestMethod;
10 |
11 | import cn.springcloud.book.user.service.IUserService;
12 | import cn.springcloud.book.user.service.dataservice.DataService;
13 |
14 | /**
15 | */
16 | @Component
17 | public class UserClientFallback implements DataService{
18 |
19 | @Override
20 | public String getDefaultUser() {
21 | return new String("get getDefaultUser failed");
22 | }
23 | @Override
24 | public String getContextUserId() {
25 | return new String("get getContextUserId failed");
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/user-service/src/main/java/cn/springcloud/book/user/service/impl/UserService.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.user.service.impl;
2 |
3 |
4 | import java.util.List;
5 |
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Component;
8 | import org.springframework.web.client.RestTemplate;
9 |
10 | import cn.springcloud.book.user.service.IUserService;
11 | import cn.springcloud.book.user.service.dataservice.DataService;
12 |
13 | /**
14 | */
15 | @Component
16 | public class UserService implements IUserService{
17 |
18 | @Autowired
19 | private DataService dataService;
20 |
21 | @Autowired
22 | private RestTemplate restTemplate;
23 |
24 | @Override
25 | public String getDefaultUser() {
26 | return dataService.getDefaultUser();
27 | }
28 |
29 | @Override
30 | public String getContextUserId() {
31 | return dataService.getContextUserId();
32 | }
33 |
34 | @Override
35 | public List getProviderData() {
36 | List result = restTemplate.getForObject("http://sc-data-service/getProviderData", List.class);
37 | return result;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/user-service/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
5 | instance:
6 | prefer-ip-address: true
7 | management:
8 | security:
9 | enabled: false
10 | endpoints:
11 | web:
12 | exposure:
13 | include: hystrix.stream
14 | feign:
15 | hystrix:
16 | enabled: true
17 | ribbon:
18 | ConnectTimeout: 6000
19 | ReadTimeout: 6000
20 | MaxAutoRetries: 0
21 | MaxAutoRetriesNextServer: 0
22 | hystrix:
23 | command:
24 | default:
25 | execution:
26 | timeout:
27 | isolation:
28 | thread:
29 | timeoutInMilliseconds: 15000
--------------------------------------------------------------------------------
/user-service/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9092
3 | spring:
4 | cloud:
5 | config:
6 | label: master
7 | uri: http://localhost:9090
8 | name: config-info
9 | profile: dev
10 | application:
11 | name: sc-user-service
12 |
13 |
--------------------------------------------------------------------------------
/zuul-server/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | cn.springcloud.book
6 | ch10-1
7 | 0.0.1-SNAPSHOT
8 |
9 | zuul-server
10 |
11 |
12 | UTF-8
13 |
14 |
15 |
16 |
17 | org.springframework.cloud
18 | spring-cloud-starter-netflix-zuul
19 |
20 |
21 | org.springframework.cloud
22 | spring-cloud-starter-netflix-eureka-client
23 |
24 |
25 | org.springframework.cloud
26 | spring-cloud-starter-netflix-hystrix
27 |
28 |
29 | cn.springcloud.book
30 | common
31 | ${parent.version}
32 |
33 |
34 |
35 |
36 |
37 |
38 | org.springframework.boot
39 | spring-boot-maven-plugin
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/zuul-server/src/main/java/cn/springcloud/book/ZuulServerApplication.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7 | import org.springframework.cloud.netflix.hystrix.EnableHystrix;
8 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
9 | import org.springframework.context.annotation.Bean;
10 |
11 | import cn.springcloud.book.filter.AuthFilter;
12 |
13 | @SpringBootApplication
14 | @EnableDiscoveryClient
15 | @EnableZuulProxy
16 | @EnableCircuitBreaker
17 | public class ZuulServerApplication {
18 |
19 | public static void main(String[] args) {
20 | SpringApplication.run(ZuulServerApplication.class, args);
21 | }
22 |
23 | @Bean
24 | public AuthFilter preRequestFilter() {
25 | return new AuthFilter();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/zuul-server/src/main/java/cn/springcloud/book/filter/AuthFilter.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.filter;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.netflix.zuul.ZuulFilter;
5 | import com.netflix.zuul.context.RequestContext;
6 |
7 | import cn.springcloud.book.common.exception.BaseException;
8 | import cn.springcloud.book.common.exception.BaseExceptionBody;
9 | import cn.springcloud.book.common.exception.CommonError;
10 | import cn.springcloud.book.common.util.AuthUtil;
11 | import cn.springcloud.book.common.vo.User;
12 |
13 | import java.io.IOException;
14 | import java.io.PrintWriter;
15 | import java.util.Enumeration;
16 | import java.util.HashMap;
17 | import java.util.Map;
18 |
19 | import javax.servlet.http.HttpServletRequest;
20 | import javax.servlet.http.HttpServletResponse;
21 |
22 | import org.slf4j.Logger;
23 | import org.slf4j.LoggerFactory;
24 | import org.springframework.util.StringUtils;
25 |
26 | /**
27 | * 鉴权filter
28 | */
29 | public class AuthFilter extends ZuulFilter {
30 | private static final Logger logger = LoggerFactory.getLogger(AuthFilter.class);
31 |
32 | @Override
33 | public boolean shouldFilter() {
34 | // 判断是否需要进行处理
35 | return true;
36 | }
37 |
38 | @Override
39 | public Object run() {
40 | RequestContext rc = RequestContext.getCurrentContext();
41 | authUser(rc);
42 | return null;
43 | }
44 |
45 | @Override
46 | public String filterType() {
47 | return "pre";
48 | }
49 |
50 | @Override
51 | public int filterOrder() {
52 | return 0;
53 | }
54 |
55 | private static Map httpRequestToMap(HttpServletRequest request) {
56 | Enumeration headerNames = request.getHeaderNames();
57 | Map headers = new HashMap<>();
58 | while (headerNames.hasMoreElements()) {
59 | String headerName = headerNames.nextElement();
60 | headers.put(headerName, request.getHeader(headerName));
61 | }
62 | return headers;
63 | }
64 |
65 | public static void authUser(RequestContext ctx) {
66 | HttpServletRequest request = ctx.getRequest();
67 | Map header = httpRequestToMap(request);
68 | String userId = header.get(User.CONTEXT_KEY_USERID);
69 | if(StringUtils.isEmpty(userId)) {
70 | try {
71 | BaseException BaseException = new BaseException(CommonError.AUTH_EMPTY_ERROR.getCode(),CommonError.AUTH_EMPTY_ERROR.getCodeEn(),CommonError.AUTH_EMPTY_ERROR.getMessage(),1L);
72 | BaseExceptionBody errorBody = new BaseExceptionBody(BaseException);
73 | ctx.setSendZuulResponse(false);
74 | ctx.setResponseStatusCode(401);
75 | ctx.setResponseBody(JSONObject.toJSON(errorBody).toString());
76 | } catch (Exception e) {
77 | logger.error("println message error",e);
78 | }
79 | }else {
80 | for (Map.Entry entry : header.entrySet()) {
81 | ctx.addZuulRequestHeader(entry.getKey(), entry.getValue());
82 | }
83 | }
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/zuul-server/src/main/java/cn/springcloud/book/filter/ZuulFallback.java:
--------------------------------------------------------------------------------
1 | package cn.springcloud.book.filter;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
8 | import org.springframework.http.HttpHeaders;
9 | import org.springframework.http.HttpStatus;
10 | import org.springframework.http.MediaType;
11 | import org.springframework.http.client.ClientHttpResponse;
12 | import org.springframework.stereotype.Component;
13 |
14 | @Component
15 | public class ZuulFallback implements FallbackProvider{
16 |
17 | @Override
18 | public String getRoute() {
19 | return "*"; //可以配置指定的路由,值为serviceId,如sc-user-service
20 | }
21 |
22 | @Override
23 | public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
24 | return new ClientHttpResponse() {
25 | @Override
26 | public HttpStatus getStatusCode() throws IOException {
27 | return HttpStatus.INTERNAL_SERVER_ERROR;
28 | }
29 |
30 | @Override
31 | public String getStatusText() throws IOException {
32 | return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
33 | }
34 |
35 | @Override
36 | public void close() {
37 | }
38 |
39 | @Override
40 | public InputStream getBody() throws IOException {
41 | //定义自己的错误信息
42 | return new ByteArrayInputStream(("microservice error").getBytes());
43 | }
44 |
45 | @Override
46 | public HttpHeaders getHeaders() {
47 | HttpHeaders headers = new HttpHeaders();
48 | headers.setContentType(MediaType.APPLICATION_JSON);
49 | return headers;
50 | }
51 |
52 | @Override
53 | public int getRawStatusCode() throws IOException {
54 | // TODO Auto-generated method stub
55 | return HttpStatus.INTERNAL_SERVER_ERROR.value();
56 | }
57 | };
58 |
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/zuul-server/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | eureka:
2 | client:
3 | serviceUrl:
4 | defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
5 | instance:
6 | prefer-ip-address: true
7 | management:
8 | security:
9 | enabled: false
10 | endpoints:
11 | web:
12 | exposure:
13 | include: hystrix.stream
14 | feign:
15 | hystrix:
16 | enabled: true
17 | ribbon:
18 | ConnectTimeout: 6000
19 | ReadTimeout: 6000
20 | MaxAutoRetries: 0 #对第一次请求的服务的重试次数
21 | MaxAutoRetriesNextServer: 0 #要重试的下一个服务的最大数量(不包括第一个服务)
22 | OkToRetryOnAllOperations: false
23 | zuul:
24 | ribbonIsolationStrategy: THREAD
25 | threadPool:
26 | useSeparateThreadPools: true
27 | threadPoolKeyPrefix: zuulgateway
28 | max:
29 | host:
30 | max-per-route-connections: 200
31 | max-total-connections: 500
32 | host:
33 | socket-timeout-millis: 5000
34 | connect-timeout-millis: 10000
35 | hystrix:
36 | threadpool:
37 | default:
38 | coreSize: 20
39 | maximumSize: 50
40 | maxQueueSize: -1
41 | allowMaximumSizeToDivergeFromCoreSize: true
42 | command:
43 | default:
44 | execution:
45 | timeout:
46 | enabled: false
47 | isolation:
48 | thread:
49 | interruptOnTimeout: false
50 | timeoutInMilliseconds: 15000
--------------------------------------------------------------------------------
/zuul-server/src/main/resources/bootstrap.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | application:
3 | name: sc-zuul-server
4 | server:
5 | port: 7777
6 |
7 |
--------------------------------------------------------------------------------