pull/11/MERGE
tanghc 4 years ago
parent 31202908a4
commit 3804bf33a7
  1. 7
      changelog.md
  2. 50
      doc/docs/files/10011_项目接入到SOP.md
  3. 2
      doc/pom.xml
  4. 2
      pom.xml
  5. 2
      sop-admin/pom.xml
  6. 4
      sop-admin/sop-admin-server/pom.xml
  7. 4
      sop-auth/pom.xml
  8. 2
      sop-common/pom.xml
  9. 2
      sop-common/sop-bridge-eureka/pom.xml
  10. 2
      sop-common/sop-bridge-nacos/pom.xml
  11. 6
      sop-common/sop-gateway-common/pom.xml
  12. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ServiceRouteInfo.java
  13. 3
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java
  14. 25
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java
  15. 39
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/result/GatewayResultExecutor.java
  16. 16
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/GatewayRouteCache.java
  17. 15
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/InstanceManager.java
  18. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/message/ErrorEnum.java
  19. 19
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/result/BaseExecutorAdapter.java
  20. 38
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/route/ServiceRouteListener.java
  21. 1
      sop-common/sop-gateway-common/src/main/resources/i18n/open/error_en.properties
  22. 1
      sop-common/sop-gateway-common/src/main/resources/i18n/open/error_zh_CN.properties
  23. 4
      sop-common/sop-service-common/pom.xml
  24. 5
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/GlobalExceptionHandler.java
  25. 6
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/configuration/SpringmvcConfiguration.java
  26. 86
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/exception/ExceptionHolder.java
  27. 4
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/message/ServiceErrorEnum.java
  28. 21
      sop-common/sop-service-common/src/main/java/com/gitee/sop/servercommon/result/DefaultServiceResultBuilder.java
  29. 5
      sop-common/sop-service-common/src/main/resources/i18n/isp/error_en.properties
  30. 9
      sop-common/sop-service-common/src/main/resources/i18n/isp/error_zh_CN.properties
  31. 2
      sop-example/pom.xml
  32. 2
      sop-example/sop-springmvc/pom.xml
  33. 2
      sop-example/sop-story/pom.xml
  34. 48
      sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/StoryGlobalExceptionHandler.java
  35. 7
      sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/controller/Example1005_ThrowExceptionController.java
  36. 2
      sop-gateway/pom.xml
  37. 4
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbLimitConfigManager.java
  38. 26
      sop-gateway/src/main/java/com/gitee/sop/gateway/manager/DbRoutesProcessor.java
  39. 27
      sop-gateway/src/main/java/com/gitee/sop/gateway/mapper/SystemLockMapper.java
  40. 10
      sop-mysql5.6以下版本.sql
  41. 2
      sop-sdk/pom.xml
  42. 4
      sop-sdk/sdk-java/pom.xml
  43. 2
      sop-test/pom.xml
  44. 19
      sop-test/src/test/java/com/gitee/sop/test/AllInOneTest.java
  45. 2
      sop-website/pom.xml
  46. 2
      sop-website/sop-website-server/pom.xml
  47. 6
      sop-website/sop-website-vue/public/static/code.json
  48. 10
      sop.sql
  49. 19
      升级到4.4.0注意事项.md

@ -1,5 +1,12 @@
# changelog
## 4.4.0
**【重要】:升级前请阅读 [升级到4.4.0注意事项](./升级到4.4.0注意事项.md)**
- 优化异常处理
- 优化网关多实例数据库重复保存问题
## 4.3.4
- 修复Request参数在第一位导致绑定失败问题

@ -79,6 +79,56 @@ public class OpenServiceConfig extends AlipayServiceConfiguration {
}
```
- 全局异常处理
在微服务项目的全局异常处理中添加一句:`ExceptionHolder.hold(request, response, exception);`
```java
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) {
...
// 在返回前加这一句
ExceptionHolder.hold(request, response, exception);
...
return ..;
}
```
如果没有配置全局异常,可参考下面配置
```java
@ControllerAdvice
@Slf4j
public class StoryGlobalExceptionHandler {
/**
* 捕获手动抛出的异常
*
* @param request request
* @param response response
* @param exception 异常信息
* @return 返回提示信息
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) {
// 在返回前加这一句
ExceptionHolder.hold(request, response, exception);
// 下面可以实现自己的全局异常处理
return new ErrorResult(500, exception.getMessage());
}
@Data
@AllArgsConstructor
public static class ErrorResult {
private int code;
private String msg;
}
}
```
到此准备工作就完成了,接下来可前往`新增接口`查看如何新增接口。
## 非Java项目接入

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.sop</groupId>
<artifactId>doc</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<properties>
<!-- Generic properties -->

@ -11,7 +11,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<packaging>pom</packaging>
<description>一个开放平台解决方案项目,基于Spring Cloud实现,目标是能够让用户快速得搭建起自己的开放平台</description>

@ -6,7 +6,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -5,13 +5,13 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sop-admin-server</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>

@ -5,7 +5,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
@ -38,7 +38,7 @@
<dependency>
<groupId>com.gitee.sop</groupId>
<artifactId>sdk-java</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
</dependency>
<!-- http请求 -->
<dependency>

@ -6,7 +6,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -5,7 +5,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-common</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-common</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>

@ -5,7 +5,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-common</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
@ -100,6 +100,10 @@
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
</dependencies>

@ -24,6 +24,8 @@ public class ServiceRouteInfo {
private List<RouteDefinition> routeDefinitionList;
private String md5;
public String fetchServiceIdLowerCase() {
return serviceId.toLowerCase();
}

@ -40,7 +40,10 @@ public class SopConstants {
public static final String X_SERVICE_ERROR_MESSAGE = "x-service-error-message";
public static final String X_SERVICE_ERROR_RESPONSE = "x-service-error-response";
public static final int BIZ_ERROR_STATUS = 4000;
public static final int UNKNOWN_ERROR_STATUS = 5050;
public static final String UNKNOWN_SERVICE= "_sop_unknown_service_";
public static final String UNKNOWN_METHOD = "_sop_unknown_method_";

@ -19,6 +19,7 @@ import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
@ -33,6 +34,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
/**
@ -198,6 +200,29 @@ public class ServerWebExchangeUtil {
.build();
}
/**
* 返回header值
* @param exchange ServerWebExchange
* @param name header名
* @return 返回值没有返回null
*/
public static Optional<String> getHeaderValue(ServerWebExchange exchange, String name) {
List<String> values = exchange.getResponse().getHeaders().get(name);
if (CollectionUtils.isEmpty(values)) {
return Optional.empty();
}
return values.stream().findFirst();
}
/**
* 移除header
* @param exchange ServerWebExchange
* @param name header名
*/
public static void removeHeader(ServerWebExchange exchange, String name) {
exchange.getResponse().getHeaders().remove(name);
}
/**
* 获取一个文件上传request
*

@ -24,6 +24,7 @@ import org.springframework.web.util.UriUtils;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
/**
@ -36,27 +37,24 @@ public class GatewayResultExecutor extends BaseExecutorAdapter<ServerWebExchange
@Override
public int getResponseStatus(ServerWebExchange exchange) {
HttpStatus statusCode = exchange.getResponse().getStatusCode();
int responseStatus = statusCode.value();
List<String> errorCodeList = exchange.getResponse().getHeaders().get(SopConstants.X_SERVICE_ERROR_CODE);
if (!CollectionUtils.isEmpty(errorCodeList)) {
String errorCode = errorCodeList.get(0);
responseStatus = Integer.parseInt(errorCode);
}
return responseStatus;
return ServerWebExchangeUtil.getHeaderValue(exchange, SopConstants.X_SERVICE_ERROR_CODE)
.map(Integer::parseInt)
.orElse(statusCode.value());
}
@Override
public String getResponseErrorMessage(ServerWebExchange exchange) {
String errorMsg = null;
List<String> errorMessageList = exchange.getResponse().getHeaders().get(SopConstants.X_SERVICE_ERROR_MESSAGE);
if (!CollectionUtils.isEmpty(errorMessageList)) {
errorMsg = errorMessageList.get(0);
public Optional<String> getServiceResultForError(ServerWebExchange exchange, int status) {
if (status == HttpStatus.OK.value()) {
return Optional.empty();
}
if (StringUtils.hasText(errorMsg)) {
errorMsg = UriUtils.decode(errorMsg, StandardCharsets.UTF_8);
return ServerWebExchangeUtil.getHeaderValue(exchange, SopConstants.X_SERVICE_ERROR_RESPONSE);
}
exchange.getResponse().getHeaders().remove(SopConstants.X_SERVICE_ERROR_MESSAGE);
return errorMsg;
@Override
public String getResponseErrorMessage(ServerWebExchange exchange) {
return ServerWebExchangeUtil.getHeaderValue(exchange, SopConstants.X_SERVICE_ERROR_MESSAGE)
.map(msg -> UriUtils.decode(msg, StandardCharsets.UTF_8))
.orElse(null);
}
@Override
@ -71,14 +69,15 @@ public class GatewayResultExecutor extends BaseExecutorAdapter<ServerWebExchange
@Override
protected RouteInterceptorContext getRouteInterceptorContext(ServerWebExchange exchange) {
return (RouteInterceptorContext) exchange.getAttributes().get(SopConstants.CACHE_ROUTE_INTERCEPTOR_CONTEXT);
RouteInterceptorContext routeInterceptorContext = exchange.getAttribute(SopConstants.CACHE_ROUTE_INTERCEPTOR_CONTEXT);
ServiceInstance serviceInstance = exchange.getAttribute(SopConstants.TARGET_SERVICE);
DefaultRouteInterceptorContext context = (DefaultRouteInterceptorContext) routeInterceptorContext;
context.setServiceInstance(serviceInstance);
return routeInterceptorContext;
}
@Override
protected void bindRouteInterceptorContextProperties(RouteInterceptorContext routeInterceptorContext, ServerWebExchange requestContext) {
ServiceInstance serviceInstance = requestContext.getAttribute(SopConstants.TARGET_SERVICE);
DefaultRouteInterceptorContext context = (DefaultRouteInterceptorContext) routeInterceptorContext;
context.setServiceInstance(serviceInstance);
}
@Override

@ -38,7 +38,7 @@ public class GatewayRouteCache implements RouteLoader {
public void load(ServiceRouteInfo serviceRouteInfo, Consumer<Object> callback) {
try {
String serviceId = serviceRouteInfo.getServiceId();
String newMd5 = buildMd5(serviceRouteInfo.getRouteDefinitionList());
String newMd5 = serviceRouteInfo.getMd5();
String oldMd5 = serviceIdMd5Map.get(serviceId);
if (Objects.equals(newMd5, oldMd5)) {
return;
@ -78,20 +78,6 @@ public class GatewayRouteCache implements RouteLoader {
this.routeRepository.refresh();
}
/**
* 构建路由id MD5
*
* @param routeDefinitionList 路由列表
* @return 返回MD5
*/
private String buildMd5(List<RouteDefinition> routeDefinitionList) {
List<String> routeIdList = routeDefinitionList.stream()
.map(JSON::toJSONString)
.sorted()
.collect(Collectors.toList());
String md5Source = org.apache.commons.lang3.StringUtils.join(routeIdList, "");
return DigestUtils.md5DigestAsHex(md5Source.getBytes(StandardCharsets.UTF_8));
}
@Override
public void remove(String serviceId) {

@ -0,0 +1,15 @@
package com.gitee.sop.gatewaycommon.manager;
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
import com.gitee.sop.gatewaycommon.route.RegistryEvent;
import java.util.List;
/**
* @author tanghc
*/
public interface InstanceManager extends RegistryEvent {
List<InstanceDefinition> listInstance(String serviceId);
}

@ -10,6 +10,8 @@ public enum ErrorEnum {
/** 服务暂不可用 */
ISP_UNKNOWN_ERROR(Codes.CODE_UNKNOWN, "isp.unknown-error"),
/** 微服务未知错误 */
ISP_SERVICE_UNKNOWN_ERROR(Codes.CODE_UNKNOWN, "isp.service-unknown-error"),
/** 服务不可用,路由被禁用 */
ISP_API_DISABLED(Codes.CODE_UNKNOWN, "isp.service-not-available"),
/** 网关响应超时 */

@ -17,13 +17,17 @@ import com.gitee.sop.gatewaycommon.util.RouteInterceptorUtil;
import com.gitee.sop.gatewaycommon.validate.alipay.AlipaySignature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.web.util.UriUtils;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
/**
* 处理微服务返回结果
@ -44,6 +48,7 @@ public abstract class BaseExecutorAdapter<T, R> implements ResultExecutor<T, R>
static {
HTTP_STATUS_ERROR_ENUM_MAP.put(HttpStatus.OK.value(), ErrorEnum.SUCCESS);
HTTP_STATUS_ERROR_ENUM_MAP.put(SopConstants.BIZ_ERROR_STATUS, ErrorEnum.BIZ_ERROR);
HTTP_STATUS_ERROR_ENUM_MAP.put(SopConstants.UNKNOWN_ERROR_STATUS, ErrorEnum.ISP_SERVICE_UNKNOWN_ERROR);
HTTP_STATUS_ERROR_ENUM_MAP.put(HttpStatus.NOT_FOUND.value(), ErrorEnum.ISV_INVALID_METHOD);
}
@ -64,6 +69,14 @@ public abstract class BaseExecutorAdapter<T, R> implements ResultExecutor<T, R>
*/
public abstract String getResponseErrorMessage(T t);
/**
* 业务返回的错误结果
* @param t request
* @param status status
* @return 业务返回结果
*/
public abstract Optional<String> getServiceResultForError(T t, int status);
/**
* 返回Api参数
*
@ -93,6 +106,10 @@ public abstract class BaseExecutorAdapter<T, R> implements ResultExecutor<T, R>
serviceResult = formatResult(serviceResult);
boolean isMergeResult = this.isMergeResult(request);
int responseStatus = this.getResponseStatus(request);
Optional<String> serviceResultForError = this.getServiceResultForError(request, responseStatus);
if (serviceResultForError.isPresent()) {
serviceResult = UriUtils.decode(serviceResultForError.get(), StandardCharsets.UTF_8);
}
this.doAfterRoute(serviceResult, responseStatus, request);
String finalResult;
if (isMergeResult) {
@ -124,6 +141,8 @@ public abstract class BaseExecutorAdapter<T, R> implements ResultExecutor<T, R>
if (StringUtils.isEmpty(responseErrorMessage)) {
responseErrorMessage = serviceResult;
}
ServiceInstance serviceInstance = defaultRouteInterceptorContext.getServiceInstance();
log.error("微服务端报错,instance:{}:{}, errorMsg:{}", serviceInstance.getHost(), serviceInstance.getPort(), responseErrorMessage);
defaultRouteInterceptorContext.setServiceErrorMsg(responseErrorMessage);
}
}

@ -2,17 +2,24 @@ package com.gitee.sop.gatewaycommon.route;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
import com.gitee.sop.gatewaycommon.bean.RouteDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceBeanInitializer;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author tanghc
@ -30,6 +37,9 @@ public class ServiceRouteListener extends BaseServiceListener {
@Autowired
private RoutesProcessor routesProcessor;
@Autowired
private ApplicationContext applicationContext;
@Override
public void onRemoveService(String serviceId) {
log.info("服务下线,删除路由配置,serviceId: {}", serviceId);
@ -39,9 +49,9 @@ public class ServiceRouteListener extends BaseServiceListener {
@Override
public void onAddInstance(InstanceDefinition instance) {
String serviceName = instance.getServiceId();
String serviceId = instance.getServiceId();
String url = getRouteRequestUrl(instance);
log.info("拉取路由配置,serviceId: {}, url: {}", serviceName, url);
log.info("拉取路由配置,serviceId: {}, url: {}", serviceId, url);
ResponseEntity<String> responseEntity = getRestTemplate().getForEntity(url, String.class);
if (responseEntity.getStatusCode() == HttpStatus.OK) {
String body = responseEntity.getBody();
@ -53,17 +63,41 @@ public class ServiceRouteListener extends BaseServiceListener {
return;
}
gatewayRouteCache.load(serviceRouteInfo, callback -> routesProcessor.saveRoutes(serviceRouteInfo, instance));
this.initServiceBeanInitializer(serviceId);
} else {
log.error("拉取路由配置异常,url: {}, status: {}, body: {}", url, responseEntity.getStatusCodeValue(), responseEntity.getBody());
}
}
private void initServiceBeanInitializer(String serviceId) {
Map<String, ServiceBeanInitializer> serviceBeanInitializerMap = applicationContext.getBeansOfType(ServiceBeanInitializer.class);
serviceBeanInitializerMap.values().forEach(serviceBeanInitializer -> serviceBeanInitializer.load(serviceId));
}
private ServiceRouteInfo parseServiceRouteInfo(String body) {
ServiceRouteInfo serviceRouteInfo = JSON.parseObject(body, ServiceRouteInfo.class);
serviceRouteInfo.setServiceId(serviceRouteInfo.getServiceId().toLowerCase());
List<RouteDefinition> routeDefinitionList = serviceRouteInfo.getRouteDefinitionList();
String md5 = buildMd5(routeDefinitionList);
serviceRouteInfo.setMd5(md5);
return serviceRouteInfo;
}
/**
* 构建路由id MD5
*
* @param routeDefinitionList 路由列表
* @return 返回MD5
*/
private String buildMd5(List<RouteDefinition> routeDefinitionList) {
List<String> routeIdList = routeDefinitionList.stream()
.map(JSON::toJSONString)
.sorted()
.collect(Collectors.toList());
String md5Source = org.apache.commons.lang3.StringUtils.join(routeIdList, "");
return DigestUtils.md5DigestAsHex(md5Source.getBytes(StandardCharsets.UTF_8));
}
protected HttpEntity<String> getHttpEntity() {
HttpHeaders headers = new HttpHeaders();
return new HttpEntity<>(headers);

@ -6,6 +6,7 @@ open.error_10000=Success
# open.error_\uFF08\u524D\u7F00\uFF0920000\uFF08\u7F51\u5173\u9519\u8BEF\u7801\uFF09_isp.unknow-error\uFF08\u5B50\u9519\u8BEF\u7801\uFF09
open.error_20000=Service is temporarily unavailable
open.error_20000_isp.unknown-error=Service is temporarily unavailable
open.error_20000_isp.service-unknown-error=Service not available
open.error_20000_aop.unknown-error=Service is temporarily unavailable
open.error_20000_isp.service-not-available=Service is temporarily unavailable
open.error_20000_isp.gateway-response-timeout=Gateway response timeout

@ -62,6 +62,7 @@ open.error_10000=Success
# open.error_\uFF08\u524D\u7F00\uFF0920000\uFF08\u7F51\u5173\u9519\u8BEF\u7801\uFF09_isp.unknow-error\uFF08\u5B50\u9519\u8BEF\u7801\uFF09
open.error_20000=\u670D\u52A1\u4E0D\u53EF\u7528
open.error_20000_isp.unknown-error=\u670D\u52A1\u6682\u4E0D\u53EF\u7528
open.error_20000_isp.service-unknown-error=\u670D\u52A1\u4E0D\u53EF\u7528
open.error_20000_aop.unknown-error=\u670D\u52A1\u6682\u4E0D\u53EF\u7528
open.error_20000_isp.service-not-available=\u670D\u52A1\u6682\u4E0D\u53EF\u7528
open.error_20000_isp.gateway-response-timeout=\u7F51\u5173\u54CD\u5E94\u8D85\u65F6

@ -6,13 +6,13 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-common</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sop-service-common</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>

@ -14,10 +14,13 @@ import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
/**
* 全局异常处理
* 全局异常处理不在使用目的是不与原有的全局异常冲突替代方案见sop-story中的
*
* com.gitee.sop.storyweb.StoryGlobalExceptionHandler
*
* @author tanghc
*/
@Deprecated
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

@ -72,12 +72,6 @@ public class SpringmvcConfiguration implements WebMvcConfigurer, BeanPostProcess
registry.addInterceptor(new ServiceContextInterceptor());
}
@Bean
@ConditionalOnMissingBean
GlobalExceptionHandler globalExceptionHandler() {
return new GlobalExceptionHandler();
}
@Bean
@ConditionalOnMissingBean
ServiceRouteController serviceRouteInfoHandler() {

@ -0,0 +1,86 @@
package com.gitee.sop.servercommon.exception;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.servercommon.bean.ServiceConfig;
import com.gitee.sop.servercommon.result.ServiceResultBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.util.UriUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
/**
* @author tanghc
*/
@Slf4j
public class ExceptionHolder {
/**
* 与网关约定好的状态码表示业务出错
*/
private static final int BIZ_ERROR_CODE = 4000;
/**
* 与网关约定好的系统错误状态码
*/
private static final int SYSTEM_ERROR_CODE = 5050;
/**
* header中的错误code
*/
private static final String X_SERVICE_ERROR_HEADER_NAME = "x-service-error-code";
/**
* header中的错误信息
*/
private static final String X_SERVICE_ERROR_MESSAGE = "x-service-error-message";
/**
* header中的返回信息
*/
private static final String X_SERVICE_ERROR_RESPONSE = "x-service-error-response";
/**
* 处理微服务异常信息做到不与原系统的错误处理相冲突
* @param request request
* @param response response
* @param exception exception
*/
public static void hold(HttpServletRequest request, HttpServletResponse response, Exception exception) {
log.error("系统错误", exception);
int code = exception instanceof ServiceException ? BIZ_ERROR_CODE : SYSTEM_ERROR_CODE;
// 需要设置两个值,这样网关会收到错误信息
// 并且会统计到监控当中
response.setHeader(X_SERVICE_ERROR_HEADER_NAME, String.valueOf(code));
String responseBody = buildResponse(request, response, exception);
response.setHeader(X_SERVICE_ERROR_RESPONSE, UriUtils.encode(responseBody, StandardCharsets.UTF_8));
// 如果是未知错误,还需要收集异常信息
if (code == SYSTEM_ERROR_CODE) {
StringBuilder msg = new StringBuilder();
msg.append(exception.getMessage());
StackTraceElement[] stackTrace = exception.getStackTrace();
// 取5行错误内容
int lineCount = 5;
for (int i = 0; i < stackTrace.length && i < lineCount; i++) {
StackTraceElement stackTraceElement = stackTrace[i];
msg.append("\n at ").append(stackTraceElement.toString());
}
response.setHeader(X_SERVICE_ERROR_MESSAGE, UriUtils.encode(msg.toString(), StandardCharsets.UTF_8));
}
}
/**
* 处理异常
*
* @param request request
* @param response response
* @param exception 异常信息
* @return 返回最终结果
*/
private static String buildResponse(HttpServletRequest request, HttpServletResponse response, Exception exception) {
ServiceResultBuilder serviceResultBuilder = ServiceConfig.getInstance().getServiceResultBuilder();
Object result = serviceResultBuilder.buildError(request, response, exception);
return JSON.toJSONString(result);
}
}

@ -4,8 +4,8 @@ package com.gitee.sop.servercommon.message;
* @author tanghc
*/
public enum ServiceErrorEnum {
/** 系统繁忙 */
ISP_UNKNOW_ERROR("isp.unknown-error"),
/** 未知错误 */
ISP_UNKNOWN_ERROR("isp.service-unknown-error"),
/** 参数错误 */
ISV_PARAM_ERROR("isv.invalid-parameter"),
/** 通用错误 */

@ -1,6 +1,10 @@
package com.gitee.sop.servercommon.result;
import com.alibaba.fastjson.annotation.JSONField;
import com.gitee.sop.servercommon.exception.ServiceException;
import com.gitee.sop.servercommon.message.ServiceError;
import com.gitee.sop.servercommon.message.ServiceErrorEnum;
import com.gitee.sop.servercommon.message.ServiceErrorMeta;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@ -15,20 +19,17 @@ import javax.servlet.http.HttpServletResponse;
@Slf4j
public class DefaultServiceResultBuilder implements ServiceResultBuilder {
public static final String ISP_UNKNOWN_ERROR = "isp.unknown-error";
@Override
public Object buildError(HttpServletRequest request, HttpServletResponse response, Throwable throwable) {
String subCode, subMsg;
ServiceError error;
if (throwable instanceof ServiceException) {
ServiceException ex = (ServiceException) throwable;
subCode = ex.getError().getSub_code();
subMsg = ex.getError().getSub_msg();
ServiceException serviceException = (ServiceException) throwable;
error = serviceException.getError();
} else {
subCode = ISP_UNKNOWN_ERROR;
subMsg = throwable.getMessage();
ServiceErrorMeta errorMeta = ServiceErrorEnum.ISP_UNKNOWN_ERROR.getErrorMeta();
error = errorMeta.getError();
}
return this.buildError(subCode, subMsg);
return this.buildError(error.getSub_code(), error.getSub_msg());
}
@Override
@ -41,7 +42,9 @@ public class DefaultServiceResultBuilder implements ServiceResultBuilder {
@Data
public static class AlipayResult {
@JSONField(ordinal = 1)
private String sub_code;
@JSONField(ordinal = 2)
private String sub_msg;
}
}

@ -1,4 +1,5 @@
# 错误配置
# \u9519\u8BEF\u914D\u7F6E
isp.error_isp.unknown-error=Service is temporarily unavailable
isp.error_isp.service-unknown-error=Service not unavailable
isp.error_isv.invalid-parameter=Invalid parameter
isp.error_isv.common-error=Service error

@ -1,5 +1,6 @@
# 错误配置
# \u9519\u8BEF\u914D\u7F6E
isp.error_isp.unknown-error=\u670d\u52a1\u6682\u4e0d\u53ef\u7528
# 参数无效
isp.error_isv.invalid-parameter=\u53c2\u6570\u65e0\u6548
isp.error_isp.service-unknown-error=\u672A\u77E5\u9519\u8BEF
# \u53C2\u6570\u65E0\u6548
isp.error_isv.invalid-parameter=\u53C2\u6570\u65E0\u6548
isp.error_isv.common-error=\u7CFB\u7EDF\u9519\u8BEF

@ -5,7 +5,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -5,7 +5,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -4,7 +4,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -0,0 +1,48 @@
package com.gitee.sop.storyweb;
import com.gitee.sop.servercommon.exception.ExceptionHolder;
import com.gitee.sop.servercommon.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 全局异常处理
*
* @author tanghc
*/
@ControllerAdvice
@Slf4j
public class StoryGlobalExceptionHandler {
/**
* 捕获手动抛出的异常
*
* @param request request
* @param response response
* @param exception 异常信息
* @return 返回提示信息
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) {
// 在返回前加这一句
ExceptionHolder.hold(request, response, exception);
// 下面可以实现自己的全局异常处理
return new ErrorResult(500, exception.getMessage());
}
@Data
@AllArgsConstructor
public static class ErrorResult {
private int code;
private String msg;
}
}

@ -32,4 +32,11 @@ public class Example1005_ThrowExceptionController {
}
return param;
}
@Open("goods.update2")
@RequestMapping("ex2")
public Object updateGoods2(GoodsUpdateParam param) {
int i = 1/0;
return param;
}
}

@ -4,7 +4,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -10,7 +10,6 @@ import com.gitee.sop.gatewaycommon.util.MyBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
/**
@ -24,9 +23,6 @@ public class DbLimitConfigManager extends DefaultLimitConfigManager {
@Autowired
ConfigLimitMapper configLimitMapper;
@Autowired
Environment environment;
@Override
public void load(String serviceId) {
Query query = new Query();

@ -4,19 +4,19 @@ import com.alibaba.fastjson.JSON;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.sop.gateway.entity.ConfigServiceRoute;
import com.gitee.sop.gateway.mapper.ConfigServiceRouteMapper;
import com.gitee.sop.gatewaycommon.bean.BeanInitializer;
import com.gitee.sop.gateway.mapper.SystemLockMapper;
import com.gitee.sop.gatewaycommon.bean.InstanceDefinition;
import com.gitee.sop.gatewaycommon.bean.ServiceBeanInitializer;
import com.gitee.sop.gatewaycommon.bean.ServiceRouteInfo;
import com.gitee.sop.gatewaycommon.route.RoutesProcessor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -30,7 +30,7 @@ public class DbRoutesProcessor implements RoutesProcessor {
private ConfigServiceRouteMapper configServiceRouteMapper;
@Autowired
private ApplicationContext applicationContext;
private SystemLockMapper systemLockMapper;
@Override
public void removeAllRoutes(String serviceId) {
@ -39,8 +39,17 @@ public class DbRoutesProcessor implements RoutesProcessor {
configServiceRouteMapper.deleteByQuery(delServiceQuery);
}
@Transactional(rollbackFor = Exception.class)
@Override
public synchronized void saveRoutes(ServiceRouteInfo serviceRouteInfo, InstanceDefinition instance) {
// 抢锁,没抢到阻塞在这里
systemLockMapper.lock();
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
int result = systemLockMapper.insert(time + serviceRouteInfo.getMd5());
// 抢到锁,插入失败,表示其它实例已经处理完毕,这里直接返回
if (result == 0) {
return;
}
log.info("保存路由信息到数据库,instance: {}", instance);
String serviceId = serviceRouteInfo.getServiceId();
List<ConfigServiceRoute> configServiceRoutes = serviceRouteInfo
@ -72,13 +81,6 @@ public class DbRoutesProcessor implements RoutesProcessor {
if (CollectionUtils.isNotEmpty(configServiceRoutes)) {
// 批量保存
configServiceRouteMapper.saveBatch(configServiceRoutes);
// 后续处理操作
this.initServiceBeanInitializer(serviceId);
}
}
private void initServiceBeanInitializer(String serviceId) {
Map<String, ServiceBeanInitializer> serviceBeanInitializerMap = applicationContext.getBeansOfType(ServiceBeanInitializer.class);
serviceBeanInitializerMap.values().forEach(serviceBeanInitializer -> serviceBeanInitializer.load(serviceId));
}
}

@ -0,0 +1,27 @@
package com.gitee.sop.gateway.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.ResultType;
import org.apache.ibatis.annotations.Select;
/**
* @author tanghc
*/
@Mapper
public interface SystemLockMapper {
/**
* 插入唯一值
* @param content 唯一值
* @return 1返回成功0插入失败
*/
@Insert("INSERT IGNORE INTO system_lock(content) VALUES (#{content})")
@ResultType(int.class)
int insert(@Param("content") String content);
@Select("SELECT id FROM system_lock WHERE id=1 FOR UPDATE")
@ResultType(long.class)
long lock();
}

@ -21,6 +21,14 @@ DROP TABLE IF EXISTS `monitor_info`;
DROP TABLE IF EXISTS `monitor_info_error`;
DROP TABLE IF EXISTS `user_account`;
DROP TABLE IF EXISTS `isp_resource`;
DROP TABLE IF EXISTS `system_lock`;
CREATE TABLE `system_lock` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`content` varchar(64) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_content` (`content`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `admin_user_info` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
@ -347,3 +355,5 @@ INSERT INTO `isp_resource` (`id`, `name`, `content`, `ext_content`, `version`, `
(3,'Python','http://www.bilibili.com','```python\n # 创建请求\n request = MemberInfoGetRequest()\n # 请求参数\n model = MemberInfoGetModel()\n model.age = 22\n model.name = \'jim\'\n model.address = \'xx\'\n # 添加请求参数\n request.biz_model = model\n\n # 添加上传文件\n # files = {\n # \'file1\': open(\'aa.txt\', \'rb\'),\n # \'file2\': open(\'bb.txt\', \'rb\')\n # }\n # request.files = files\n\n # 调用请求\n response = self.client.execute(request)\n\n if response.is_success():\n print \'response: \', response\n print \'is_vip:\', response.get(\'member_info\').get(\'is_vip\', 0)\n else:\n print \',code:%s, msg:%s, sub_code:%s, sub_msg:%s\' % \\\n (response.code, response.msg, response.sub_code, response.sub_msg)\n```','1.0',0,0,'2020-11-07 14:30:16','2020-11-07 14:31:41'),
(4,'Go','http://www.baidu.com','```go\n\n// 应用ID\nconst appId string = "xx"\n// 应用私钥\nconst privateKey string = "xx"\n// 请求地址\nconst url string = "http://localhost:7071/prod/gw68uy85"\n\n// 请求客户端\nvar openClient = common.OpenClient{AppId: appId, PrivateKey: privateKey, Url: url}\n\nfunc main() {\n // 创建请求\n memberInfoGetRequest := request.MemberInfoGetRequest{}\n // 请求参数\n memberInfoGetRequest.BizModel = model.MemberInfoGetModel{Name: "jim", Age: 22, Address: "xx"}\n \n // 添加上传文件\n //path, _ := os.Getwd()\n //files := []common.UploadFile{\n // {Name:"file1", Filepath:path + "/test/aa.txt"},\n // {Name:"file2", Filepath:path + "/test/bb.txt"},\n //}\n //memberInfoGetRequest.Files = files\n \n // 发送请求,返回json bytes\n var jsonBytes = openClient.Execute(memberInfoGetRequest)\n fmt.Printf("data:%s\\n", string(jsonBytes))\n // 转换结果\n var memberInfoGetResponse response.MemberInfoGetResponse\n response.ConvertResponse(jsonBytes, &memberInfoGetResponse)\n\n if memberInfoGetResponse.IsSuccess() {\n fmt.Printf("is_vip:%d, vip_endtime:%s\\n", memberInfoGetResponse.MemberInfo.IsVip, memberInfoGetResponse.MemberInfo.VipEndtime)\n } else {\n fmt.Printf("code:%s, msg:%s, subCode:%s, subMsg:%s\\n",\n memberInfoGetResponse.Code, memberInfoGetResponse.Msg, memberInfoGetResponse.SubCode, memberInfoGetResponse.SubMsg)\n }\n}\n```','1.0',0,0,'2020-11-07 14:31:21','2020-11-07 14:31:21'),
(5,'C++','http://pan.baidu.com','#include <iostream>\n\n#include "common/OpenClient.h"\n#include "request/BaseRequest.h"\n#include "request/MemberInfoGetRequest.hpp"\n\n// 应用ID\nstring appId = "2020051325943082302177280";\n// 存放私钥的文件路径\nstring privateKeyFile = "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/privateEx.pem";\n// 请求接口\nstring url = "http://localhost:7071/prod/gw68uy85";\n\nOpenClient openClient(appId, privateKeyFile, url);\n\nint main() {\n // 创建请求\n MemberInfoGetRequest request;\n\n // 业务参数\n map<string, string> bizModel;\n bizModel["name"] = "jim";\n bizModel["age"] = "22";\n bizModel["address"] = "xx";\n\n request.bizModel = bizModel;\n\n // 添加上传文件\n// request->setFiles({\n// FileInfo{"aa", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/aa.txt"},\n// FileInfo{"bb", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/bb.txt"}\n// });\n\n // 发送请求\n neb::CJsonObject jsonObj = openClient.execute(&request);\n std::cout << jsonObj.ToString() << std::endl;\n std::cout << "id:" << jsonObj["id"].ToString() << std::endl;\n std::cout << "is_vip:" << jsonObj["member_info"]["is_vip"].ToString() << std::endl;\n return 0;\n}\n\n','1.0',0,0,'2020-11-07 14:32:55','2020-11-07 14:32:55');
INSERT INTO `system_lock` (`id`, `content`) VALUES (1,'lock');

@ -6,7 +6,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -4,13 +4,13 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sdk-java</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<properties>
<!-- Generic properties -->

@ -5,7 +5,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -422,6 +422,25 @@ public class AllInOneTest extends TestBase {
client.execute(requestBuilder);
}
/**
* 未知异常
*/
public void testException() {
Client.RequestBuilder requestBuilder = new Client.RequestBuilder()
.method("goods.update2")
.version("1.0")
.bizContent(new BizContent().add("goods_name", "Apple"))
.httpMethod(HttpTool.HTTPMethod.POST)
.callback((requestInfo, responseData) -> {
System.out.println(responseData);
String node = requestInfo.getDataNode();
JSONObject jsonObject = JSON.parseObject(responseData).getJSONObject(node);
Assert.assertEquals("isp.service-unknown-error", jsonObject.getString("sub_code"));
});
client.execute(requestBuilder);
}
static class BizContent extends HashMap<String, Object> {
public BizContent add(String key, Object value) {
this.put(key, value);

@ -6,7 +6,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-parent</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -5,7 +5,7 @@
<parent>
<groupId>com.gitee.sop</groupId>
<artifactId>sop-website</artifactId>
<version>4.3.4-SNAPSHOT</version>
<version>4.4.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <!-- lookup parent from repository -->
</parent>

@ -50,6 +50,12 @@
"sub_code": "isp.exec-gzip-error",
"sub_msg": "处理gzip异常",
"solution": "联系客服排查日志"
},
{
"id": 1208,
"sub_code": "isp.service-unknown-error",
"sub_msg": "服务不可用",
"solution": "联系客服排查日志"
}
]
},

@ -23,6 +23,7 @@ DROP TABLE IF EXISTS `monitor_info`;
DROP TABLE IF EXISTS `monitor_info_error`;
DROP TABLE IF EXISTS `user_account`;
DROP TABLE IF EXISTS `isp_resource`;
DROP TABLE IF EXISTS `system_lock`;
CREATE TABLE `admin_user_info` (
@ -280,6 +281,13 @@ CREATE TABLE `isp_resource` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ISP资源表';
CREATE TABLE `system_lock` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`content` varchar(64) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_content` (`content`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `admin_user_info` (`id`, `username`, `password`, `status`, `gmt_create`, `gmt_modified`) VALUES
(1,'admin','a62cd510fb9a8a557a27ef279569091f',1,'2019-04-02 19:55:26','2019-04-02 19:55:26');
@ -350,3 +358,5 @@ INSERT INTO `isp_resource` (`id`, `name`, `content`, `ext_content`, `version`, `
(3,'Python','http://www.bilibili.com','```python\n # 创建请求\n request = MemberInfoGetRequest()\n # 请求参数\n model = MemberInfoGetModel()\n model.age = 22\n model.name = \'jim\'\n model.address = \'xx\'\n # 添加请求参数\n request.biz_model = model\n\n # 添加上传文件\n # files = {\n # \'file1\': open(\'aa.txt\', \'rb\'),\n # \'file2\': open(\'bb.txt\', \'rb\')\n # }\n # request.files = files\n\n # 调用请求\n response = self.client.execute(request)\n\n if response.is_success():\n print \'response: \', response\n print \'is_vip:\', response.get(\'member_info\').get(\'is_vip\', 0)\n else:\n print \',code:%s, msg:%s, sub_code:%s, sub_msg:%s\' % \\\n (response.code, response.msg, response.sub_code, response.sub_msg)\n```','1.0',0,0,'2020-11-07 14:30:16','2020-11-07 14:31:41'),
(4,'Go','http://www.baidu.com','```go\n\n// 应用ID\nconst appId string = "xx"\n// 应用私钥\nconst privateKey string = "xx"\n// 请求地址\nconst url string = "http://localhost:7071/prod/gw68uy85"\n\n// 请求客户端\nvar openClient = common.OpenClient{AppId: appId, PrivateKey: privateKey, Url: url}\n\nfunc main() {\n // 创建请求\n memberInfoGetRequest := request.MemberInfoGetRequest{}\n // 请求参数\n memberInfoGetRequest.BizModel = model.MemberInfoGetModel{Name: "jim", Age: 22, Address: "xx"}\n \n // 添加上传文件\n //path, _ := os.Getwd()\n //files := []common.UploadFile{\n // {Name:"file1", Filepath:path + "/test/aa.txt"},\n // {Name:"file2", Filepath:path + "/test/bb.txt"},\n //}\n //memberInfoGetRequest.Files = files\n \n // 发送请求,返回json bytes\n var jsonBytes = openClient.Execute(memberInfoGetRequest)\n fmt.Printf("data:%s\\n", string(jsonBytes))\n // 转换结果\n var memberInfoGetResponse response.MemberInfoGetResponse\n response.ConvertResponse(jsonBytes, &memberInfoGetResponse)\n\n if memberInfoGetResponse.IsSuccess() {\n fmt.Printf("is_vip:%d, vip_endtime:%s\\n", memberInfoGetResponse.MemberInfo.IsVip, memberInfoGetResponse.MemberInfo.VipEndtime)\n } else {\n fmt.Printf("code:%s, msg:%s, subCode:%s, subMsg:%s\\n",\n memberInfoGetResponse.Code, memberInfoGetResponse.Msg, memberInfoGetResponse.SubCode, memberInfoGetResponse.SubMsg)\n }\n}\n```','1.0',0,0,'2020-11-07 14:31:21','2020-11-07 14:31:21'),
(5,'C++','http://pan.baidu.com','#include <iostream>\n\n#include "common/OpenClient.h"\n#include "request/BaseRequest.h"\n#include "request/MemberInfoGetRequest.hpp"\n\n// 应用ID\nstring appId = "2020051325943082302177280";\n// 存放私钥的文件路径\nstring privateKeyFile = "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/privateEx.pem";\n// 请求接口\nstring url = "http://localhost:7071/prod/gw68uy85";\n\nOpenClient openClient(appId, privateKeyFile, url);\n\nint main() {\n // 创建请求\n MemberInfoGetRequest request;\n\n // 业务参数\n map<string, string> bizModel;\n bizModel["name"] = "jim";\n bizModel["age"] = "22";\n bizModel["address"] = "xx";\n\n request.bizModel = bizModel;\n\n // 添加上传文件\n// request->setFiles({\n// FileInfo{"aa", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/aa.txt"},\n// FileInfo{"bb", "/Users/thc/IdeaProjects/opc/opc-sdk/sdk-c++/bb.txt"}\n// });\n\n // 发送请求\n neb::CJsonObject jsonObj = openClient.execute(&request);\n std::cout << jsonObj.ToString() << std::endl;\n std::cout << "id:" << jsonObj["id"].ToString() << std::endl;\n std::cout << "is_vip:" << jsonObj["member_info"]["is_vip"].ToString() << std::endl;\n return 0;\n}\n\n','1.0',0,0,'2020-11-07 14:32:55','2020-11-07 14:32:55');
INSERT INTO `system_lock` (`id`, `content`) VALUES (1,'lock');

@ -0,0 +1,19 @@
从之前版本升级到4.4.0必须看,如果直接从4.4.0开始使用,不用看。
- 首先执行升级脚本
```sql
use sop;
CREATE TABLE `system_lock` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`content` varchar(64) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_content` (`content`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `system_lock` (`id`, `content`) VALUES (1,'lock');
```
类`com.gitee.sop.servercommon.configuration.GlobalExceptionHandler`已被废弃,替代方案改用自己的全局异常处理
参考:`com.gitee.sop.storyweb.StoryGlobalExceptionHandler`。这样改的目的是对于老项目的全局异常无入侵。
Loading…
Cancel
Save