mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
2.0
This commit is contained in:
@@ -1,5 +1,17 @@
|
||||
# 常见问题
|
||||
|
||||
## 在zuul过滤器中获取请求参数
|
||||
|
||||
```java
|
||||
ApiParam param = ZuulContext.getApiParam();
|
||||
```
|
||||
|
||||
## 在SpringCloudGateway中获取请求参数
|
||||
|
||||
```java
|
||||
ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange);
|
||||
```
|
||||
|
||||
## 微服务端如何获取appId等参数
|
||||
|
||||
```java
|
||||
|
@@ -9,6 +9,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
@@ -37,7 +38,7 @@ public abstract class BaseRouteCache<T extends TargetRoute> implements RouteLoad
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(ServiceRouteInfo serviceRouteInfo) {
|
||||
public void load(ServiceRouteInfo serviceRouteInfo, Consumer<Object> callback) {
|
||||
try {
|
||||
String serviceId = serviceRouteInfo.getServiceId();
|
||||
String newMd5 = serviceRouteInfo.getMd5();
|
||||
@@ -51,6 +52,7 @@ public abstract class BaseRouteCache<T extends TargetRoute> implements RouteLoad
|
||||
T routeDefinition = this.buildRouteDefinition(serviceRouteInfo, gatewayRouteDefinition);
|
||||
routeRepository.add(routeDefinition);
|
||||
}
|
||||
callback.accept(null);
|
||||
} catch (Exception e) {
|
||||
log.error("加载路由信息失败,serviceRouteInfo:{}", serviceRouteInfo, e);
|
||||
}
|
||||
|
@@ -2,11 +2,13 @@ package com.gitee.sop.gatewaycommon.manager;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface RouteLoader {
|
||||
void load(ServiceRouteInfo serviceRouteInfo);
|
||||
void load(ServiceRouteInfo serviceRouteInfo, Consumer<Object> callback);
|
||||
|
||||
void remove(String serviceId);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -50,6 +51,16 @@ public class ServiceRoutesLoader<T extends TargetRoute> {
|
||||
|
||||
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) {
|
||||
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||
List<ServiceInfo> subscribes = null;
|
||||
@@ -88,15 +99,20 @@ public class ServiceRoutesLoader<T extends TargetRoute> {
|
||||
configService.removeConfig(dataId, groupId);
|
||||
} else {
|
||||
for (Instance instance : allInstances) {
|
||||
log.info("加载服务路由,serviceId:{}, instance:{}",serviceName, instance);
|
||||
String url = getRouteRequestUrl(instance);
|
||||
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
String body = responseEntity.getBody();
|
||||
log.debug("加载{}路由,路由信息:{}", serviceName, body);
|
||||
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class);
|
||||
baseRouteCache.load(serviceRouteInfo);
|
||||
configService.publishConfig(dataId, groupId, body);
|
||||
baseRouteCache.load(serviceRouteInfo, callback -> {
|
||||
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();
|
||||
|
||||
@Value("${registry.nacos-server-addr:}")
|
||||
@Value("${nacos.discovery.server-addr:${registry.nacos-server-addr:}}")
|
||||
private String nacosAddr;
|
||||
|
||||
@Value("${nacos.discovery.server-addr:}")
|
||||
private String nacosAddrNew;
|
||||
|
||||
private NamingService namingService;
|
||||
|
||||
@PostConstruct
|
||||
public void after() throws NacosException {
|
||||
if (StringUtils.isNotBlank(nacosAddrNew)) {
|
||||
nacosAddr = nacosAddrNew;
|
||||
}
|
||||
if (StringUtils.isNotBlank(nacosAddr)) {
|
||||
namingService = NamingFactory.createNamingService(nacosAddr);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.gitee.sop.servercommon.bean;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
|
||||
@@ -28,11 +29,12 @@ public class OpenContextImpl<T> implements OpenContext<T> {
|
||||
public OpenContextImpl(JSONObject rootJsonObject, Class<?> bizClass) {
|
||||
this.rootJsonObject = rootJsonObject;
|
||||
if (bizClass != null) {
|
||||
JSONObject bizJsonObj = this.rootJsonObject.getJSONObject(BIZ_CONTENT_NAME);
|
||||
if (bizJsonObj == null) {
|
||||
bizJsonObj = rootJsonObject;
|
||||
String bizContent = this.rootJsonObject.getString(BIZ_CONTENT_NAME);
|
||||
if (bizContent == null) {
|
||||
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;
|
||||
|
||||
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.message.ServiceErrorFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
@@ -36,10 +38,23 @@ public class SpringMvcServiceConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
GlobalExceptionHandler globalExceptionHandler() {
|
||||
return new GlobalExceptionHandler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ErrorController errorController() {
|
||||
return new ErrorController();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ServiceRouteController serviceRouteInfoHandler() {
|
||||
return new ServiceRouteController();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public final void after() {
|
||||
log.info("-----spring容器加载完毕-----");
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<java-version>1.8</java-version>
|
||||
<org.springframework-version>5.0.7.RELEASE</org.springframework-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>
|
||||
|
||||
<dependencies>
|
||||
@@ -22,11 +22,11 @@
|
||||
<artifactId>sop-service-common</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- eureka 服务发现 -->
|
||||
<!-- nacos -->
|
||||
<dependency>
|
||||
<groupId>com.netflix.eureka</groupId>
|
||||
<artifactId>eureka-client</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<groupId>com.alibaba.nacos</groupId>
|
||||
<artifactId>nacos-spring-context</artifactId>
|
||||
<version>0.3.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 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;
|
||||
|
||||
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.configuration.SpringMvcServiceConfiguration;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 使用支付宝开放平台功能
|
||||
*
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableNacosDiscovery(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))
|
||||
public class OpenServiceConfig extends SpringMvcServiceConfiguration {
|
||||
static {
|
||||
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>
|
||||
|
||||
<listener>
|
||||
<listener-class>com.gitee.app.config.EurekaInitAndRegisterListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<!-- Processes application requests -->
|
||||
<servlet>
|
||||
<servlet-name>appServlet</servlet-name>
|
||||
|
@@ -12,6 +12,7 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -37,6 +38,16 @@ public class DocDiscovery {
|
||||
|
||||
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) {
|
||||
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
|
||||
List<ServiceInfo> subscribes = null;
|
||||
@@ -71,13 +82,15 @@ public class DocDiscovery {
|
||||
docManager.remove(serviceName);
|
||||
} else {
|
||||
for (Instance instance : allInstances) {
|
||||
log.info("加载服务文档,instance:{}", instance);
|
||||
String url = getRouteRequestUrl(instance);
|
||||
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
|
||||
if (responseEntity.getStatusCode() == HttpStatus.OK) {
|
||||
String body = responseEntity.getBody();
|
||||
log.debug("加载{}文档,文档信息:{}", serviceName, body);
|
||||
docManager.addDocInfo(serviceName, body);
|
||||
docManager.addDocInfo(
|
||||
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 java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
public interface DocManager {
|
||||
|
||||
void addDocInfo(String serviceId, String docJson);
|
||||
void addDocInfo(String serviceId, String docJson, Consumer<DocInfo> callback);
|
||||
|
||||
DocInfo getByTitle(String title);
|
||||
|
||||
|
@@ -16,6 +16,7 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
@@ -40,7 +41,7 @@ public class DocManagerImpl implements DocManager, ApplicationListener<Heartbeat
|
||||
private DocDiscovery docDiscovery;
|
||||
|
||||
@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 oldMd5 = serviceIdMd5Map.get(serviceId);
|
||||
if (Objects.equals(newMd5, oldMd5)) {
|
||||
@@ -52,6 +53,7 @@ public class DocManagerImpl implements DocManager, ApplicationListener<Heartbeat
|
||||
DocInfo docInfo = docParser.parseJson(docRoot);
|
||||
docInfo.setServiceId(serviceId);
|
||||
docDefinitionMap.put(docInfo.getTitle(), docInfo);
|
||||
callback.accept(docInfo);
|
||||
}
|
||||
|
||||
protected DocParser buildDocParser(JSONObject rootDoc) {
|
||||
|
Reference in New Issue
Block a user