├── .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 | ![architecuture](https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/master/images/architecture.png) 10 | 11 | ## 具体实现 12 | 13 | 项目结构如下所示,从module名称,即可理解每个项目的作用了。 14 | 15 | 其中common是一个公共基础包,方便给后台服务引用。 16 | 17 | ![source code](https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/master/images/source-code.png) 18 | 19 | ## 运行微服务应用 20 | 21 | 按顺序启动 eureka、zuul-server、data-service、user-service,另外的hystrix-dashboard和config-server 是可行的module。如下图所示,可以看到每个应用的运行端口号。 22 | 23 | ![application running](https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/master/images/application-run.png) 24 | 25 | 访问 eureka UI,查看服务注册情况。 26 | 27 | 28 | 29 | 每个服务都正常注册到 eureka 注册中心了。 30 | 31 | ![eureka](https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/master/images/eureka.png) 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 | ![auth filter](https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/master/images/auth-filter.png) 42 | 43 | 通过Postman,在请求头中添加 x-customs-user=rickie 信息,然后再次访问URL。 44 | 45 | 46 | 如下图所示,目前返回结果正常。 47 | 48 | ![postman](https://raw.githubusercontent.com/rickiechina/Spring-Cloud-Full-Demo/master/images/postman.png) -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------