mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 12:56:28 +08:00
4.4.0
This commit is contained in:
@@ -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 -->
|
||||
|
2
pom.xml
2
pom.xml
@@ -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 ServerWebExchangeUtil.getHeaderValue(exchange, SopConstants.X_SERVICE_ERROR_CODE)
|
||||
.map(Integer::parseInt)
|
||||
.orElse(statusCode.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getServiceResultForError(ServerWebExchange exchange, int status) {
|
||||
if (status == HttpStatus.OK.value()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return responseStatus;
|
||||
return ServerWebExchangeUtil.getHeaderValue(exchange, SopConstants.X_SERVICE_ERROR_RESPONSE);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
if (StringUtils.hasText(errorMsg)) {
|
||||
errorMsg = UriUtils.decode(errorMsg, StandardCharsets.UTF_8);
|
||||
}
|
||||
exchange.getResponse().getHeaders().remove(SopConstants.X_SERVICE_ERROR_MESSAGE);
|
||||
return errorMsg;
|
||||
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_isv.invalid-parameter=Invalid parameter
|
||||
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": "联系客服排查日志"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
10
sop.sql
10
sop.sql
@@ -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');
|
||||
|
19
升级到4.4.0注意事项.md
Normal file
19
升级到4.4.0注意事项.md
Normal file
@@ -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`。这样改的目的是对于老项目的全局异常无入侵。
|
Reference in New Issue
Block a user