pull/1/head
tanghc 5 years ago
parent bb19a34444
commit 299195e9a1
  1. 12
      doc/docs/files/90100_常见问题.md
  2. 4
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/BaseRouteCache.java
  3. 4
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/RouteLoader.java
  4. 24
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ServiceRoutesLoader.java
  5. 8
      sop-common/sop-registry-api/src/main/java/com/gitee/sop/registryapi/service/impl/RegistryServiceNacos.java
  6. 10
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/bean/OpenContextImpl.java
  7. 15
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/SpringMvcServiceConfiguration.java
  8. 10
      sop-example/sop-springmvc/pom.xml
  9. 61
      sop-example/sop-springmvc/src/main/java/com/gitee/app/config/EurekaInitAndRegisterListener.java
  10. 29
      sop-example/sop-springmvc/src/main/java/com/gitee/app/config/OpenServiceConfig.java
  11. 27
      sop-example/sop-springmvc/src/main/resources/eureka-client.properties
  12. 4
      sop-example/sop-springmvc/src/main/webapp/WEB-INF/web.xml
  13. 19
      sop-website/src/main/java/com/gitee/sop/websiteserver/manager/DocDiscovery.java
  14. 3
      sop-website/src/main/java/com/gitee/sop/websiteserver/manager/DocManager.java
  15. 4
      sop-website/src/main/java/com/gitee/sop/websiteserver/manager/DocManagerImpl.java

@ -1,5 +1,17 @@
# 常见问题 # 常见问题
## 在zuul过滤器中获取请求参数
```java
ApiParam param = ZuulContext.getApiParam();
```
## 在SpringCloudGateway中获取请求参数
```java
ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange);
```
## 微服务端如何获取appId等参数 ## 微服务端如何获取appId等参数
```java ```java

@ -9,6 +9,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer;
/** /**
* @author tanghc * @author tanghc
@ -37,7 +38,7 @@ public abstract class BaseRouteCache<T extends TargetRoute> implements RouteLoad
} }
@Override @Override
public void load(ServiceRouteInfo serviceRouteInfo) { public void load(ServiceRouteInfo serviceRouteInfo, Consumer<Object> callback) {
try { try {
String serviceId = serviceRouteInfo.getServiceId(); String serviceId = serviceRouteInfo.getServiceId();
String newMd5 = serviceRouteInfo.getMd5(); String newMd5 = serviceRouteInfo.getMd5();
@ -51,6 +52,7 @@ public abstract class BaseRouteCache<T extends TargetRoute> implements RouteLoad
T routeDefinition = this.buildRouteDefinition(serviceRouteInfo, gatewayRouteDefinition); T routeDefinition = this.buildRouteDefinition(serviceRouteInfo, gatewayRouteDefinition);
routeRepository.add(routeDefinition); routeRepository.add(routeDefinition);
} }
callback.accept(null);
} catch (Exception e) { } catch (Exception e) {
log.error("加载路由信息失败,serviceRouteInfo:{}", serviceRouteInfo, e); log.error("加载路由信息失败,serviceRouteInfo:{}", serviceRouteInfo, e);
} }

@ -2,11 +2,13 @@ package com.gitee.sop.gatewaycommon.manager;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo; import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
import java.util.function.Consumer;
/** /**
* @author tanghc * @author tanghc
*/ */
public interface RouteLoader { public interface RouteLoader {
void load(ServiceRouteInfo serviceRouteInfo); void load(ServiceRouteInfo serviceRouteInfo, Consumer<Object> callback);
void remove(String serviceId); void remove(String serviceId);
} }

@ -18,6 +18,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.HashMap; import java.util.HashMap;
@ -50,6 +51,16 @@ public class ServiceRoutesLoader<T extends TargetRoute> {
private Map<String, Long> updateTimeMap = new HashMap<>(16); private Map<String, Long> updateTimeMap = new HashMap<>(16);
public ServiceRoutesLoader() {
// 解决statusCode不等于200,就抛异常问题
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
@Override
protected boolean hasError(HttpStatus statusCode) {
return statusCode == null;
}
});
}
public synchronized void load(ApplicationEvent event) { public synchronized void load(ApplicationEvent event) {
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
List<ServiceInfo> subscribes = null; List<ServiceInfo> subscribes = null;
@ -88,15 +99,20 @@ public class ServiceRoutesLoader<T extends TargetRoute> {
configService.removeConfig(dataId, groupId); configService.removeConfig(dataId, groupId);
} else { } else {
for (Instance instance : allInstances) { for (Instance instance : allInstances) {
log.info("加载服务路由,serviceId:{}, instance:{}",serviceName, instance);
String url = getRouteRequestUrl(instance); String url = getRouteRequestUrl(instance);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class); ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
if (responseEntity.getStatusCode() == HttpStatus.OK) { if (responseEntity.getStatusCode() == HttpStatus.OK) {
String body = responseEntity.getBody(); String body = responseEntity.getBody();
log.debug("加载{}路由,路由信息:{}", serviceName, body);
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class); ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class);
baseRouteCache.load(serviceRouteInfo); baseRouteCache.load(serviceRouteInfo, callback -> {
configService.publishConfig(dataId, groupId, body); try {
log.info("加载服务路由,serviceId:{}, instance:{}",serviceName, instance);
configService.publishConfig(dataId, groupId, body);
} catch (NacosException e) {
log.error("nacos推送失败,serviceId:{}, instance:{}",serviceName, instance);
}
});
} }
} }
} }

@ -33,19 +33,13 @@ public class RegistryServiceNacos implements RegistryService {
static HttpTool httpTool = new HttpTool(); static HttpTool httpTool = new HttpTool();
@Value("${registry.nacos-server-addr:}") @Value("${nacos.discovery.server-addr:${registry.nacos-server-addr:}}")
private String nacosAddr; private String nacosAddr;
@Value("${nacos.discovery.server-addr:}")
private String nacosAddrNew;
private NamingService namingService; private NamingService namingService;
@PostConstruct @PostConstruct
public void after() throws NacosException { public void after() throws NacosException {
if (StringUtils.isNotBlank(nacosAddrNew)) {
nacosAddr = nacosAddrNew;
}
if (StringUtils.isNotBlank(nacosAddr)) { if (StringUtils.isNotBlank(nacosAddr)) {
namingService = NamingFactory.createNamingService(nacosAddr); namingService = NamingFactory.createNamingService(nacosAddr);
} }

@ -1,5 +1,6 @@
package com.gitee.sop.servercommon.bean; package com.gitee.sop.servercommon.bean;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.time.DateUtils;
@ -28,11 +29,12 @@ public class OpenContextImpl<T> implements OpenContext<T> {
public OpenContextImpl(JSONObject rootJsonObject, Class<?> bizClass) { public OpenContextImpl(JSONObject rootJsonObject, Class<?> bizClass) {
this.rootJsonObject = rootJsonObject; this.rootJsonObject = rootJsonObject;
if (bizClass != null) { if (bizClass != null) {
JSONObject bizJsonObj = this.rootJsonObject.getJSONObject(BIZ_CONTENT_NAME); String bizContent = this.rootJsonObject.getString(BIZ_CONTENT_NAME);
if (bizJsonObj == null) { if (bizContent == null) {
bizJsonObj = rootJsonObject; bizObject = (T) rootJsonObject.toJavaObject(bizClass);
} else {
bizObject = (T) JSON.parseObject(bizContent, bizClass);
} }
bizObject = (T) bizJsonObj.toJavaObject(bizClass);
} }
} }

@ -1,9 +1,11 @@
package com.gitee.sop.servercommon.configuration; package com.gitee.sop.servercommon.configuration;
import com.gitee.sop.servercommon.bean.ServiceConfig; import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.manager.ServiceRouteController;
import com.gitee.sop.servercommon.mapping.ApiMappingHandlerMapping; import com.gitee.sop.servercommon.mapping.ApiMappingHandlerMapping;
import com.gitee.sop.servercommon.message.ServiceErrorFactory; import com.gitee.sop.servercommon.message.ServiceErrorFactory;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@ -36,10 +38,23 @@ public class SpringMvcServiceConfiguration {
@Bean @Bean
@ConditionalOnMissingBean
GlobalExceptionHandler globalExceptionHandler() { GlobalExceptionHandler globalExceptionHandler() {
return new GlobalExceptionHandler(); return new GlobalExceptionHandler();
} }
@Bean
@ConditionalOnMissingBean
ErrorController errorController() {
return new ErrorController();
}
@Bean
@ConditionalOnMissingBean
ServiceRouteController serviceRouteInfoHandler() {
return new ServiceRouteController();
}
@PostConstruct @PostConstruct
public final void after() { public final void after() {
log.info("-----spring容器加载完毕-----"); log.info("-----spring容器加载完毕-----");

@ -12,7 +12,7 @@
<java-version>1.8</java-version> <java-version>1.8</java-version>
<org.springframework-version>5.0.7.RELEASE</org.springframework-version> <org.springframework-version>5.0.7.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version> <org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version> <org.slf4j-version>1.7.25</org.slf4j-version>
</properties> </properties>
<dependencies> <dependencies>
@ -22,11 +22,11 @@
<artifactId>sop-service-common</artifactId> <artifactId>sop-service-common</artifactId>
<version>2.0.0-SNAPSHOT</version> <version>2.0.0-SNAPSHOT</version>
</dependency> </dependency>
<!-- eureka 服务发现 --> <!-- nacos -->
<dependency> <dependency>
<groupId>com.netflix.eureka</groupId> <groupId>com.alibaba.nacos</groupId>
<artifactId>eureka-client</artifactId> <artifactId>nacos-spring-context</artifactId>
<version>1.7.0</version> <version>0.3.3</version>
</dependency> </dependency>
<!-- sop接入依赖 end --> <!-- sop接入依赖 end -->

@ -1,61 +0,0 @@
package com.gitee.app.config;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.MyDataCenterInstanceConfig;
import com.netflix.discovery.DefaultEurekaClientConfig;
import com.netflix.discovery.DiscoveryManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 初始化Eureka Client
* @author tanghc
*/
@Slf4j
public class EurekaInitAndRegisterListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 初始化Eureka Client
log.info("Eureka初始化完成,正在注册Eureka Server");
DiscoveryManager.getInstance().initComponent(new MyInstanceConfig(), new DefaultEurekaClientConfig());
ApplicationInfoManager.getInstance().setInstanceStatus(InstanceInfo.InstanceStatus.UP);
}
/**
* * Notification that the servlet context is about to be shut down.
* * All servlets and filters have been destroy()ed before any
* * ServletContextListeners are notified of context
* * destruction.
*
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
DiscoveryManager.getInstance().shutdownComponent();
}
@Configuration
@PropertySource(value = "classpath:eureka-client.properties")
public static class AppConfig {
}
public static class MyInstanceConfig extends MyDataCenterInstanceConfig {
@Override
public String getHostName(boolean refresh) {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
return super.getHostName(refresh);
}
}
}
}

@ -1,15 +1,44 @@
package com.gitee.app.config; package com.gitee.app.config;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.client.naming.utils.NetUtils;
import com.alibaba.nacos.spring.context.annotation.discovery.EnableNacosDiscovery;
import com.gitee.sop.servercommon.bean.ServiceConfig; import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.configuration.SpringMvcServiceConfiguration; import com.gitee.sop.servercommon.configuration.SpringMvcServiceConfiguration;
import lombok.extern.slf4j.Slf4j;
/** /**
* 使用支付宝开放平台功能 * 使用支付宝开放平台功能
* *
* @author tanghc * @author tanghc
*/ */
@Slf4j
@EnableNacosDiscovery(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
public class OpenServiceConfig extends SpringMvcServiceConfiguration { public class OpenServiceConfig extends SpringMvcServiceConfiguration {
static { static {
ServiceConfig.getInstance().setDefaultVersion("1.0"); ServiceConfig.getInstance().setDefaultVersion("1.0");
} }
// 这两个参数需要从配置文件中获取
private String serviceId = "sop-springmvc";
private int port = 2223;
@NacosInjected
private NamingService namingService;
@Override
protected void doAfter() {
super.doAfter();
try {
String ip = NetUtils.localIP();
namingService.registerInstance(serviceId, ip, port);
log.info("注册到nacos, serviceId:{}, ip:{}, port:{}", serviceId, ip, port);
} catch (NacosException e) {
log.error("注册nacos失败", e);
throw new RuntimeException("注册nacos失败", e);
}
}
} }

@ -1,27 +0,0 @@
# tomcat端口,根据实际情况填
server.port=2223
# 应用名称serviceId,根据实际情况填
spring.application.name=sop-springmvc
# 注册中心地址,根据实际情况填
eureka.url=http://localhost:1111/eureka/
# zookeeper地址,根据实际情况填
spring.cloud.zookeeper.connect-string=localhost:2181
# ----------- 以下内容不用改 -----------
# 控制是否注册自身到eureka中,本项目虽然不对外提供服务,但需要Eureka监控,在Eureka列表上显示
eureka.registration.enabled=true
# eureka相关配置
# 默认为true,以实现更好的基于区域的负载平衡。
eureka.preferSameZone=true
# 是否要使用基于DNS的查找来确定其他eureka服务器
eureka.shouldUseDns=false
# 由于shouldUseDns为false,因此我们使用以下属性来明确指定到eureka服务器的路由(eureka Server地址)
eureka.serviceUrl.default=${eureka.url}
eureka.decoderName=JacksonJson
# 客户识别此服务的虚拟主机名,这里指的是eureka服务本身
eureka.vipAddress=${spring.application.name}
#服务指定应用名,这里指的是eureka服务本身
eureka.name=${spring.application.name}
#服务将被识别并将提供请求的端口
eureka.port=${server.port}

@ -14,10 +14,6 @@
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> </listener>
<listener>
<listener-class>com.gitee.app.config.EurekaInitAndRegisterListener</listener-class>
</listener>
<!-- Processes application requests --> <!-- Processes application requests -->
<servlet> <servlet>
<servlet-name>appServlet</servlet-name> <servlet-name>appServlet</servlet-name>

@ -12,6 +12,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.HashMap; import java.util.HashMap;
@ -37,6 +38,16 @@ public class DocDiscovery {
private Map<String, Long> updateTimeMap = new HashMap<>(16); private Map<String, Long> updateTimeMap = new HashMap<>(16);
public DocDiscovery() {
// 解决statusCode不等于200,就抛异常问题
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
@Override
protected boolean hasError(HttpStatus statusCode) {
return statusCode == null;
}
});
}
public synchronized void refresh(DocManager docManager) { public synchronized void refresh(DocManager docManager) {
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance(); NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
List<ServiceInfo> subscribes = null; List<ServiceInfo> subscribes = null;
@ -71,13 +82,15 @@ public class DocDiscovery {
docManager.remove(serviceName); docManager.remove(serviceName);
} else { } else {
for (Instance instance : allInstances) { for (Instance instance : allInstances) {
log.info("加载服务文档,instance:{}", instance);
String url = getRouteRequestUrl(instance); String url = getRouteRequestUrl(instance);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class); ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
if (responseEntity.getStatusCode() == HttpStatus.OK) { if (responseEntity.getStatusCode() == HttpStatus.OK) {
String body = responseEntity.getBody(); String body = responseEntity.getBody();
log.debug("加载{}文档,文档信息:{}", serviceName, body); docManager.addDocInfo(
docManager.addDocInfo(serviceName, body); serviceName
, body
, callback -> log.info("加载服务文档,instance:{}", instance)
);
} }
} }
} }

@ -3,13 +3,14 @@ package com.gitee.sop.websiteserver.manager;
import com.gitee.sop.websiteserver.bean.DocInfo; import com.gitee.sop.websiteserver.bean.DocInfo;
import java.util.Collection; import java.util.Collection;
import java.util.function.Consumer;
/** /**
* @author tanghc * @author tanghc
*/ */
public interface DocManager { public interface DocManager {
void addDocInfo(String serviceId, String docJson); void addDocInfo(String serviceId, String docJson, Consumer<DocInfo> callback);
DocInfo getByTitle(String title); DocInfo getByTitle(String title);

@ -16,6 +16,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer;
/** /**
* @author tanghc * @author tanghc
@ -40,7 +41,7 @@ public class DocManagerImpl implements DocManager, ApplicationListener<Heartbeat
private DocDiscovery docDiscovery; private DocDiscovery docDiscovery;
@Override @Override
public void addDocInfo(String serviceId, String docInfoJson) { public void addDocInfo(String serviceId, String docInfoJson, Consumer<DocInfo> callback) {
String newMd5 = DigestUtils.md5DigestAsHex(docInfoJson.getBytes(StandardCharsets.UTF_8)); String newMd5 = DigestUtils.md5DigestAsHex(docInfoJson.getBytes(StandardCharsets.UTF_8));
String oldMd5 = serviceIdMd5Map.get(serviceId); String oldMd5 = serviceIdMd5Map.get(serviceId);
if (Objects.equals(newMd5, oldMd5)) { if (Objects.equals(newMd5, oldMd5)) {
@ -52,6 +53,7 @@ public class DocManagerImpl implements DocManager, ApplicationListener<Heartbeat
DocInfo docInfo = docParser.parseJson(docRoot); DocInfo docInfo = docParser.parseJson(docRoot);
docInfo.setServiceId(serviceId); docInfo.setServiceId(serviceId);
docDefinitionMap.put(docInfo.getTitle(), docInfo); docDefinitionMap.put(docInfo.getTitle(), docInfo);
callback.accept(docInfo);
} }
protected DocParser buildDocParser(JSONObject rootDoc) { protected DocParser buildDocParser(JSONObject rootDoc) {

Loading…
Cancel
Save