diff --git a/pom.xml b/pom.xml index 7328c53d..88f676fc 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ sop-example - sop-admin + sop-test sop-sdk @@ -47,8 +47,6 @@ 3.2.10 - - 1.2.3 4.11 1.2.83 2.5 @@ -60,11 +58,7 @@ 2.0.1.Final 6.0.13.Final 3.0.10 - 3.5.3.1 29.0-jre - 3.0.2 - 1.5.21 - 3.0.0 1.16.9 6.2 5.2.0 @@ -125,51 +119,12 @@ ${fastmybatis.version} - - io.springfox - springfox-swagger2 - ${springfox.version} - - - io.springfox - springfox-spring-web - ${springfox.version} - - - io.springfox - springfox-swagger-ui - ${springfox.version} - - - io.springfox - springfox-boot-starter - ${springfox.version} - - - - com.github.xiaoymin - knife4j-spring-boot-starter - ${knife4j.version} - - - - net.oschina.durcframework - easyopen - ${easyopen.version} - - com.squareup.okhttp3 okhttp 3.14.7 - - net.oschina.durcframework - easyopen-spring-boot-starter - ${easyopen.version} - - javax.validation validation-api @@ -181,12 +136,6 @@ ${hibernate-validator.version} - - ch.qos.logback - logback-classic - ${logback.version} - - org.apache.commons @@ -234,7 +183,7 @@ org.projectlombok lombok - 1.18.4 + 1.18.30 javax.servlet diff --git a/sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/open/StoryService.java b/sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/open/StoryService.java index 556f885e..7a68f65c 100644 --- a/sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/open/StoryService.java +++ b/sop-example/sop-story/src/main/java/com/gitee/sop/storyweb/open/StoryService.java @@ -15,4 +15,12 @@ public interface StoryService { @Open("story.get") StoryResponse getById(Integer id); + @Open("story.find") + default StoryResponse getById(Integer id, String name) { + StoryResponse storyResponse = new StoryResponse(); + storyResponse.setId(id); + storyResponse.setName(name); + return storyResponse; + } + } diff --git a/sop-index/sop-index-api/src/main/java/com/gitee/sop/index/api/RegisterDTO.java b/sop-index/sop-index-api/src/main/java/com/gitee/sop/index/api/RegisterDTO.java index 7cb03023..59fbef6e 100644 --- a/sop-index/sop-index-api/src/main/java/com/gitee/sop/index/api/RegisterDTO.java +++ b/sop-index/sop-index-api/src/main/java/com/gitee/sop/index/api/RegisterDTO.java @@ -21,9 +21,12 @@ public class RegisterDTO implements Serializable { private String methodName; - private String paramName; - - private String paramTypeName; + /** + * 字段信息 + * + * [{"name":"id": "type":"java.lang.Integer"}] + */ + private String paramInfo; private Integer isPermission; diff --git a/sop-index/sop-index-service/pom.xml b/sop-index/sop-index-service/pom.xml index 4adf9f15..3cc1a793 100644 --- a/sop-index/sop-index-service/pom.xml +++ b/sop-index/sop-index-service/pom.xml @@ -48,6 +48,7 @@ io.gitee.durcframework fastmybatis-spring-boot-starter + mysql mysql-connector-java @@ -80,13 +81,6 @@ - - - com.h2database - h2 - provided - - org.apache.dubbo diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiInfoDTO.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiInfoDTO.java index 7d091520..0d4d1ee7 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiInfoDTO.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiInfoDTO.java @@ -21,11 +21,7 @@ public class ApiInfoDTO implements Serializable { private String methodName; - private String paramName; - - private String paramTypeName; - - private Integer isIgnoreValidate; + private String paramInfo; private Integer isPermission; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiResponse.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiResponse.java index 5a3955fd..6448069b 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiResponse.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ApiResponse.java @@ -67,17 +67,17 @@ public class ApiResponse { /** * 网关异常信息 */ - private String msg; + private String msg = ""; /** * 业务异常码 */ - private String sub_code; + private String sub_code = ""; /** * 业务异常信息 */ - private String sub_msg; + private String sub_msg = ""; /** * 返回对象 diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ParamInfoDTO.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ParamInfoDTO.java new file mode 100644 index 00000000..f15631a4 --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/ParamInfoDTO.java @@ -0,0 +1,9 @@ +package com.gitee.sop.index.common; + +import lombok.Data; + +@Data +public class ParamInfoDTO { + private String name; + private String type; +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/StatusEnum.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/StatusEnum.java index 75a03b20..3bb4e71c 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/StatusEnum.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/common/StatusEnum.java @@ -10,7 +10,7 @@ import lombok.Getter; @Getter public enum StatusEnum { ENABLE(1), - DISABLE(0); + DISABLE(2); private final int value; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/config/IndexConfig.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/config/IndexConfig.java index 52c2b3a5..9200ea23 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/config/IndexConfig.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/config/IndexConfig.java @@ -3,8 +3,10 @@ package com.gitee.sop.index.config; import com.gitee.sop.index.message.ErrorFactory; import com.gitee.sop.index.service.manager.impl.LocalApiCacheManagerImpl; import com.gitee.sop.index.service.manager.impl.LocalIsvManagerImpl; +import com.gitee.sop.index.service.manager.impl.LocalSecretManagerImpl; import com.gitee.sop.index.service.manager.impl.RedisApiCacheManagerImpl; import com.gitee.sop.index.service.manager.impl.RedisIsvManagerImpl; +import com.gitee.sop.index.service.manager.impl.RedisSecretManager; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -43,6 +45,18 @@ public class IndexConfig { return new RedisIsvManagerImpl(); } + @Bean + @ConditionalOnProperty(value = "manager.secret", havingValue = "local", matchIfMissing = true) + public LocalSecretManagerImpl localSecretManager() { + return new LocalSecretManagerImpl(); + } + + @Bean + @ConditionalOnProperty(value = "manager.secret", havingValue = "redis") + public RedisSecretManager redisSecretManager() { + return new RedisSecretManager(); + } + @PostConstruct public void init() { diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/controller/IndexController.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/controller/IndexController.java index c8aa0a32..dc7f12f2 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/controller/IndexController.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/controller/IndexController.java @@ -5,13 +5,12 @@ import com.gitee.sop.index.common.ApiRequestContext; import com.gitee.sop.index.common.ApiResponse; import com.gitee.sop.index.service.RouteService; import com.gitee.sop.index.util.RequestUtil; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; /** @@ -22,7 +21,7 @@ import javax.servlet.http.HttpServletRequest; @RestController public class IndexController { - @Autowired + @Resource private RouteService routeService; @GetMapping("/") diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/ApiInfo.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/ApiInfo.java index 82674b4f..c2f6018f 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/ApiInfo.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/ApiInfo.java @@ -48,14 +48,9 @@ public class ApiInfo { private String methodName; /** - * 参数名称 + * 参数信息 */ - private String paramName; - - /** - * 参数类型名称 - */ - private String paramTypeName; + private String paramInfo; /** * 接口是否需要授权访问 @@ -70,7 +65,7 @@ public class ApiInfo { /** * 状态,1-启用,0-禁用 */ - private Integer apiStatus; + private Integer status; private LocalDateTime addTime; diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/IsvInfo.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/IsvInfo.java new file mode 100644 index 00000000..8cb81797 --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/IsvInfo.java @@ -0,0 +1,45 @@ +package com.gitee.sop.index.dao.entity; + +import java.time.LocalDateTime; +import java.util.Date; + +import com.gitee.fastmybatis.annotation.Pk; +import com.gitee.fastmybatis.annotation.PkStrategy; +import com.gitee.fastmybatis.annotation.Table; + +import lombok.Data; + + +/** + * 表名:isv_info + * 备注:isv信息表 + * + * @author tanghc + */ +@Table(name = "isv_info", pk = @Pk(name = "id", strategy = PkStrategy.INCREMENT)) +@Data +public class IsvInfo { + + private Long id; + + /** + * appKey + */ + private String appId; + + /** + * 1启用,2禁用 + */ + private Integer status; + + /** + * 备注 + */ + private String remark; + + private LocalDateTime addTime; + + private LocalDateTime updateTime; + + +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/IsvKeys.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/IsvKeys.java new file mode 100644 index 00000000..ea0870fd --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/entity/IsvKeys.java @@ -0,0 +1,57 @@ +package com.gitee.sop.index.dao.entity; + +import java.time.LocalDateTime; +import java.util.Date; + +import com.gitee.fastmybatis.annotation.Pk; +import com.gitee.fastmybatis.annotation.PkStrategy; +import com.gitee.fastmybatis.annotation.Table; + +import lombok.Data; + + +/** + * 表名:isv_keys + * 备注:ISV秘钥管理 + * + * @author tanghc + */ +@Table(name = "isv_keys", pk = @Pk(name = "id", strategy = PkStrategy.INCREMENT)) +@Data +public class IsvKeys { + + private Long id; + + private String appId; + + /** + * 秘钥格式,1:PKCS8(JAVA适用),2:PKCS1(非JAVA适用) + */ + private Integer keyFormat; + + /** + * 开发者生成的公钥 + */ + private String publicKeyIsv; + + /** + * 开发者生成的私钥(交给开发者) + */ + private String privateKeyIsv; + + /** + * 平台生成的公钥(交给开发者) + */ + private String publicKeyPlatform; + + /** + * 平台生成的私钥 + */ + private String privateKeyPlatform; + + private LocalDateTime addTime; + + private LocalDateTime updateTime; + + +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/mapper/IsvInfoMapper.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/mapper/IsvInfoMapper.java new file mode 100644 index 00000000..b0ba24a3 --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/mapper/IsvInfoMapper.java @@ -0,0 +1,15 @@ +package com.gitee.sop.index.dao.mapper; + +import com.gitee.fastmybatis.core.mapper.BaseMapper; +import com.gitee.sop.index.dao.entity.IsvInfo; + +/** + * @author tanghc + */ +public interface IsvInfoMapper extends BaseMapper { + + default IsvInfo getByAppId(String appId) { + return this.get(IsvInfo::getAppId, appId); + } + +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/mapper/IsvKeysMapper.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/mapper/IsvKeysMapper.java new file mode 100644 index 00000000..99d169e1 --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dao/mapper/IsvKeysMapper.java @@ -0,0 +1,11 @@ +package com.gitee.sop.index.dao.mapper; + +import com.gitee.fastmybatis.core.mapper.BaseMapper; +import com.gitee.sop.index.dao.entity.IsvKeys; + +/** + * @author tanghc + */ +public interface IsvKeysMapper extends BaseMapper { + +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/ApiService.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/ApiInfoService.java similarity index 73% rename from sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/ApiService.java rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/ApiInfoService.java index 6338ba14..351246d9 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/ApiService.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/ApiInfoService.java @@ -4,7 +4,7 @@ import com.gitee.sop.index.common.ApiInfoDTO; import com.gitee.sop.index.dao.entity.ApiInfo; import com.gitee.sop.index.dao.mapper.ApiInfoMapper; import com.gitee.sop.index.service.manager.ApiCacheManager; -import org.springframework.beans.BeanUtils; +import com.gitee.sop.index.util.CopyUtil; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -13,7 +13,7 @@ import javax.annotation.Resource; * @author 六如 */ @Service -public class ApiService { +public class ApiInfoService { @Resource private ApiCacheManager apiCacheManager; @@ -23,12 +23,8 @@ public class ApiService { public ApiInfoDTO getApi(String apiName, String apiVersion) { return apiCacheManager.getOrElse(apiName, apiVersion, () -> { - ApiInfoDTO record = new ApiInfoDTO(); ApiInfo apiInfo = apiInfoMapper.getByNameVersion(apiName, apiVersion); - if (apiInfo != null) { - BeanUtils.copyProperties(apiInfo, record); - } - return record; + return CopyUtil.copyBean(apiInfo, ApiInfoDTO::new); }); } diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/GenericServiceInvoker.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/GenericServiceInvoker.java index b0fede74..4460cd5b 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/GenericServiceInvoker.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/GenericServiceInvoker.java @@ -1,8 +1,10 @@ package com.gitee.sop.index.service; +import org.apache.dubbo.common.config.ReferenceCache; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ReferenceConfig; import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.utils.SimpleReferenceCache; import org.apache.dubbo.rpc.service.GenericService; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; @@ -16,10 +18,8 @@ import org.springframework.stereotype.Service; @Service public class GenericServiceInvoker implements InitializingBean { private static final String TRUE = "true"; - private ApplicationConfig applicationConfig; - @Value("${nacos.host:localhost:8848}") - private String nacosHost; + private ApplicationConfig applicationConfig; @Value("${register.address:${register.type}://${register.host}") private String registerAddress; @@ -32,13 +32,13 @@ public class GenericServiceInvoker implements InitializingBean { @Override public void afterPropertiesSet() throws Exception { - RegistryConfig registryConfig = buildRegistryConfig(nacosHost); + RegistryConfig registryConfig = buildRegistryConfig(); applicationConfig = new ApplicationConfig(); applicationConfig.setName(appName + "-generic"); applicationConfig.setRegistry(registryConfig); } - private RegistryConfig buildRegistryConfig(String nacosHost) { + private RegistryConfig buildRegistryConfig() { RegistryConfig config = new RegistryConfig(); config.setAddress(registerAddress); return config; @@ -50,25 +50,9 @@ public class GenericServiceInvoker implements InitializingBean { reference.setApplication(applicationConfig); reference.setInterface(interfaceName); reference.setTimeout(timeout); - try { - removeGenericSymbol(parameterTypes); - GenericService genericService = reference.get(); - return genericService.$invoke(method, parameterTypes, params); - } finally { - reference.destroy(); - } + ReferenceCache referenceCache = SimpleReferenceCache.getCache(); + GenericService genericService = referenceCache.get(reference); + return genericService.$invoke(method, parameterTypes, params); } - - /** - * remove generic from parameterTypes - */ - private void removeGenericSymbol(String[] parameterTypes) { - for (int i = 0; i < parameterTypes.length; i++) { - int index = parameterTypes[i].indexOf('<'); - if (index > -1) { - parameterTypes[i] = parameterTypes[i].substring(0, index); - } - } - } } diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java index 41ddb655..d06121db 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java @@ -1,91 +1,21 @@ package com.gitee.sop.index.service; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; -import com.gitee.sop.index.common.ApiInfoDTO; -import com.gitee.sop.index.common.ApiRequest; import com.gitee.sop.index.common.ApiRequestContext; import com.gitee.sop.index.common.ApiResponse; -import com.gitee.sop.index.exception.ExceptionExecutor; -import com.gitee.sop.index.service.validate.Validator; -import com.gitee.sop.index.util.ClassUtil; -import lombok.extern.slf4j.Slf4j; -import org.apache.dubbo.common.utils.ClassUtils; -import org.springframework.stereotype.Service; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -import javax.annotation.Resource; /** * 接口路由 * * @author 六如 */ -@Service -@Slf4j -public class RouteService { +public interface RouteService { - @Resource - private Validator validator; - - @Resource - private GenericServiceInvoker genericServiceInvoker; - - @Resource - private ExceptionExecutor exceptionExecutor; - - public ApiResponse route(ApiRequestContext apiRequestContext) { - ApiRequest apiRequest = apiRequestContext.getApiRequest(); - log.info("收到客户端请求, ip={}, apiRequest={}", apiRequestContext.getIp(), apiRequest); - try { - // 接口校验 - ApiInfoDTO apiInfoDTO = validator.validate(apiRequestContext); - return doRoute(apiRequestContext, apiInfoDTO); - } catch (Exception e) { - log.error("接口请求报错, , ip={}, apiRequest={}", apiRequestContext.getIp(), apiRequest, e); - return exceptionExecutor.executeException(apiRequestContext, e); - } - } - - private ApiResponse doRoute(ApiRequestContext apiRequestContext, ApiInfoDTO apiInfo) { - ApiRequest apiRequest = apiRequestContext.getApiRequest(); - Object result = genericServiceInvoker.invoke( - apiInfo.getInterfaceClassName(), - apiInfo.getMethodName(), - buildParamType(apiInfo), - buildInvokeParam(apiRequest, apiInfo) - ); - return ApiResponse.success(result); - } - - private String[] buildParamType(ApiInfoDTO apiInfo) { - String paramTypeName = apiInfo.getParamTypeName(); - if (StringUtils.hasText(paramTypeName)) { - return new String[]{apiInfo.getParamTypeName()}; - } else { - return new String[0]; - } - } - - private Object[] buildInvokeParam(ApiRequest apiRequest, ApiInfoDTO apiInfo) { - if (ObjectUtils.isEmpty(apiInfo.getParamTypeName())) { - return new Object[0]; - } - String bizContent = apiRequest.getBiz_content(); - JSONObject jsonObject = JSON.parseObject(bizContent); - if (ClassUtil.isPrimitive(apiInfo.getParamTypeName())) { - try { - Object value = jsonObject.getObject(apiInfo.getParamName(), ClassUtils.forName(apiInfo.getParamTypeName())); - return new Object[]{value}; - } catch (ClassNotFoundException e) { - log.error("找不到参数class, paramTypeName={}, apiRequest={}, apiInfo={}", - apiInfo.getParamTypeName(), apiRequest, apiInfo, e); - throw new RuntimeException(e); - } - } else { - return new Object[]{jsonObject}; - } - } + /** + * 路由 + * + * @param apiRequestContext 接口上下文 + * @return 返回结果 + */ + ApiResponse route(ApiRequestContext apiRequestContext); } diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteServiceImpl.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteServiceImpl.java new file mode 100644 index 00000000..1e6262cf --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteServiceImpl.java @@ -0,0 +1,108 @@ +package com.gitee.sop.index.service; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.gitee.sop.index.common.ApiInfoDTO; +import com.gitee.sop.index.common.ApiRequest; +import com.gitee.sop.index.common.ApiRequestContext; +import com.gitee.sop.index.common.ApiResponse; +import com.gitee.sop.index.common.ParamInfoDTO; +import com.gitee.sop.index.exception.ExceptionExecutor; +import com.gitee.sop.index.service.validate.Validator; +import com.gitee.sop.index.util.ClassUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.dubbo.common.utils.ClassUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 接口路由 + * + * @author 六如 + */ +@Service +@Slf4j +public class RouteServiceImpl implements RouteService { + + private static final String CLASS = "class"; + + @Resource + protected Validator validator; + + @Resource + protected GenericServiceInvoker genericServiceInvoker; + + @Resource + protected ExceptionExecutor exceptionExecutor; + + @Override + public ApiResponse route(ApiRequestContext apiRequestContext) { + ApiRequest apiRequest = apiRequestContext.getApiRequest(); + log.info("收到客户端请求, ip={}, apiRequest={}", apiRequestContext.getIp(), apiRequest); + try { + // 接口校验 + ApiInfoDTO apiInfoDTO = validator.validate(apiRequestContext); + // 微服务结果 + Object result = doRoute(apiRequestContext, apiInfoDTO); + return ApiResponse.success(result); + } catch (Exception e) { + log.error("接口请求报错, , ip={}, apiRequest={}", apiRequestContext.getIp(), apiRequest, e); + return exceptionExecutor.executeException(apiRequestContext, e); + } + } + + protected Object doRoute(ApiRequestContext apiRequestContext, ApiInfoDTO apiInfo) { + ApiRequest apiRequest = apiRequestContext.getApiRequest(); + String paramInfo = apiInfo.getParamInfo(); + List paramInfoList = JSON.parseArray(paramInfo, ParamInfoDTO.class); + Object result = genericServiceInvoker.invoke( + apiInfo.getInterfaceClassName(), + apiInfo.getMethodName(), + buildParamType(paramInfoList), + buildInvokeParam(apiRequest, paramInfoList) + ); + if (result instanceof Map) { + ((Map) result).remove(CLASS); + } + return result; + } + + protected String[] buildParamType(List paramInfoList) { + if (ObjectUtils.isEmpty(paramInfoList)) { + return new String[0]; + } + return paramInfoList.stream() + .map(ParamInfoDTO::getType) + .toArray(String[]::new); + } + + protected Object[] buildInvokeParam(ApiRequest apiRequest, List paramInfoList) { + if (ObjectUtils.isEmpty(paramInfoList)) { + return new Object[0]; + } + String bizContent = apiRequest.getBiz_content(); + JSONObject jsonObject = JSON.parseObject(bizContent); + List params = new ArrayList<>(); + for (ParamInfoDTO paramInfoDTO : paramInfoList) { + if (ClassUtil.isPrimitive(paramInfoDTO.getType())) { + try { + Object value = jsonObject.getObject(paramInfoDTO.getName(), ClassUtils.forName(paramInfoDTO.getType())); + params.add(value); + } catch (ClassNotFoundException e) { + log.error("找不到参数class, paramInfoDTO={}, apiRequest={}", paramInfoDTO, apiRequest, e); + throw new RuntimeException("找不到class:" + paramInfoDTO.getType(), e); + } + } else { + Object value = jsonObject.getObject(paramInfoDTO.getName(), Object.class); + params.add(value); + } + } + return params.toArray(new Object[0]); + } + +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/dubbo/ApiRegisterServiceImpl.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/dubbo/ApiRegisterServiceImpl.java index 41b8578e..ce292ffb 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/dubbo/ApiRegisterServiceImpl.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/dubbo/ApiRegisterServiceImpl.java @@ -7,14 +7,11 @@ import com.gitee.sop.index.common.StatusEnum; import com.gitee.sop.index.dao.entity.ApiInfo; import com.gitee.sop.index.dao.mapper.ApiInfoMapper; import com.gitee.sop.index.service.manager.ApiCacheManager; +import com.gitee.sop.index.util.CopyUtil; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboService; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; import javax.annotation.Resource; -import java.time.LocalDateTime; -import java.util.Date; /** * @author 六如 @@ -32,18 +29,14 @@ public class ApiRegisterServiceImpl implements ApiRegisterService { @Override public void register(RegisterDTO registerDTO) { log.info("收到接口注册, registerDTO={}", registerDTO); - ApiInfoDTO apiInfoDTO = new ApiInfoDTO(); - BeanUtils.copyProperties(registerDTO, apiInfoDTO); + ApiInfoDTO apiInfoDTO = CopyUtil.copyBean(registerDTO, ApiInfoDTO::new); + apiInfoDTO.setStatus(StatusEnum.ENABLE.getValue()); ApiInfo apiInfo = apiInfoMapper.getByNameVersion(apiInfoDTO.getApiName(), apiInfoDTO.getApiVersion()); - LocalDateTime now = LocalDateTime.now(); if (apiInfo == null) { apiInfo = new ApiInfo(); - apiInfo.setApiStatus(StatusEnum.ENABLE.getValue()); - apiInfo.setAddTime(now); } - apiInfo.setUpdateTime(now); - BeanUtils.copyProperties(apiInfoDTO, apiInfo); + CopyUtil.copyPropertiesIgnoreNull(apiInfoDTO, apiInfo); // 保存到数据库 apiInfoMapper.saveOrUpdate(apiInfo); // 保存到缓存 diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/dto/IsvDTO.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/dto/IsvDTO.java index f8461443..1c970f05 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/dto/IsvDTO.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/dto/IsvDTO.java @@ -10,9 +10,6 @@ public class IsvDTO { private String appId; - private String publicKey; - - private String privateKeyPlatform; - private Integer status; + } diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/LocalIsvManagerImpl.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/LocalIsvManagerImpl.java index a989179a..551547c6 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/LocalIsvManagerImpl.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/LocalIsvManagerImpl.java @@ -1,31 +1,29 @@ package com.gitee.sop.index.service.manager.impl; +import com.gitee.sop.index.dao.entity.IsvInfo; +import com.gitee.sop.index.dao.mapper.IsvInfoMapper; import com.gitee.sop.index.service.manager.IsvManager; import com.gitee.sop.index.service.manager.dto.IsvDTO; +import com.gitee.sop.index.util.CopyUtil; -import javax.annotation.PostConstruct; -import java.util.HashMap; -import java.util.Map; +import javax.annotation.Resource; /** * @author 六如 */ public class LocalIsvManagerImpl implements IsvManager { - private static final Map ISV_MAP = new HashMap<>(); + @Resource + private IsvInfoMapper isvInfoMapper; @Override public IsvDTO getIsv(String appId) { - return ISV_MAP.get(appId); + IsvInfo isvInfo = isvInfoMapper.getByAppId(appId); + return CopyUtil.copyBean(isvInfo, IsvDTO::new); } @Override public void reload(String appId) { - } - @PostConstruct - public void init() { - - } } diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/LocalSecretManagerImpl.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/LocalSecretManagerImpl.java index 78d7f7ed..2421df7f 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/LocalSecretManagerImpl.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/LocalSecretManagerImpl.java @@ -1,23 +1,23 @@ package com.gitee.sop.index.service.manager.impl; +import com.gitee.sop.index.dao.entity.IsvKeys; +import com.gitee.sop.index.dao.mapper.IsvKeysMapper; import com.gitee.sop.index.service.manager.SecretManager; -import java.util.HashMap; -import java.util.Map; +import javax.annotation.Resource; /** * @author 六如 */ public class LocalSecretManagerImpl implements SecretManager { - static Map PUB_KEY_MGR = new HashMap<>(); - static { - PUB_KEY_MGR.put("2019032617262200001", "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlyb9aUBaljQP/vjmBFe1mF8HsWSvyfC2NTlpT/V9E+sBxTr8TSkbzJCeeeOEm4LCaVXL0Qz63MZoT24v7AIXTuMdj4jyiM/WJ4tjrWAgnmohNOegfntTto16C3l234vXz4ryWZMR/7W+MXy5B92wPGQEJ0LKFwNEoLspDEWZ7RdE53VH7w6y6sIZUfK+YkXWSwehfKPKlx+lDw3zRJ3/yvMF+U+BAdW/MfECe1GuBnCFKnlMRh3UKczWyXWkL6ItOpYHHJi/jx85op5BWDje2pY9QowzfN94+0DB3T7UvZeweu3zlP6diwAJDzLaFQX8ULfWhY+wfKxIRgs9NoiSAQIDAQAB"); - } - + @Resource + private IsvKeysMapper isvKeysMapper; @Override public String getIsvPublicKey(String appId) { - return PUB_KEY_MGR.get(appId); + return isvKeysMapper.query() + .eq(IsvKeys::getAppId, appId) + .getValue(IsvKeys::getPublicKeyIsv); } } diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/RedisSecretManager.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/RedisSecretManager.java new file mode 100644 index 00000000..90ecd30b --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/manager/impl/RedisSecretManager.java @@ -0,0 +1,13 @@ +package com.gitee.sop.index.service.manager.impl; + +import com.gitee.sop.index.service.manager.SecretManager; + +/** + * @author 六如 + */ +public class RedisSecretManager implements SecretManager { + @Override + public String getIsvPublicKey(String appId) { + return ""; + } +} diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/ApiValidator.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/ApiValidator.java index 334e0241..8d64ce43 100644 --- a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/ApiValidator.java +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/validate/ApiValidator.java @@ -4,25 +4,26 @@ import com.gitee.sop.index.common.ApiInfoDTO; import com.gitee.sop.index.common.ApiRequest; import com.gitee.sop.index.common.ApiRequestContext; import com.gitee.sop.index.common.ParamNames; +import com.gitee.sop.index.common.StatusEnum; import com.gitee.sop.index.config.ApiConfig; import com.gitee.sop.index.exception.ApiException; import com.gitee.sop.index.message.ErrorEnum; -import com.gitee.sop.index.service.ApiService; +import com.gitee.sop.index.service.ApiInfoService; import com.gitee.sop.index.service.manager.IpBlacklistManager; import com.gitee.sop.index.service.manager.IsvApiPermissionManager; import com.gitee.sop.index.service.manager.IsvManager; +import com.gitee.sop.index.service.manager.SecretManager; import com.gitee.sop.index.service.manager.dto.IsvDTO; import com.gitee.sop.index.service.validate.alipay.AlipaySigner; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.BooleanUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import org.springframework.util.unit.DataSize; import org.springframework.web.multipart.MultipartFile; +import javax.annotation.Resource; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; @@ -36,14 +37,12 @@ import java.util.Locale; * @author tanghc */ @Slf4j -@RequiredArgsConstructor @Service public class ApiValidator implements Validator { private static final int MILLISECOND_OF_ONE_SECOND = 1000; - private static final int STATUS_FORBIDDEN = 2; - private static List FORMAT_LIST = Arrays.asList("json", "xml"); + private static final List FORMAT_LIST = Arrays.asList("json", "xml"); private final Signer signer = new AlipaySigner(); @@ -53,20 +52,24 @@ public class ApiValidator implements Validator { @Value("${upload.max-file-size:${spring.servlet.multipart.max-file-size:10MB}}") private String maxFileSize; - private final ApiConfig apiConfig; + @Resource + private ApiConfig apiConfig; - @Autowired - private ApiService apiService; + @Resource + private ApiInfoService apiInfoService; - @Autowired + @Resource private IpBlacklistManager ipBlacklistManager; - @Autowired + @Resource private IsvApiPermissionManager isvApiPermissionManager; - @Autowired + @Resource private IsvManager isvManager; + @Resource + private SecretManager secretManager; + @Override public ApiInfoDTO validate(ApiRequestContext apiRequestContext) { @@ -84,7 +87,7 @@ public class ApiValidator implements Validator { checkIP(apiRequestContext); ApiRequest apiRequest = apiRequestContext.getApiRequest(); - ApiInfoDTO apiInfo = apiService.getApi(apiRequest.getMethod(), apiRequest.getVersion()); + ApiInfoDTO apiInfo = apiInfoService.getApi(apiRequest.getMethod(), apiRequest.getVersion()); // 检查接口信息 checkApiInfo(apiRequestContext, apiInfo); @@ -189,7 +192,7 @@ public class ApiValidator implements Validator { throw new ApiException(ErrorEnum.ISV_INVALID_APP_ID, apiRequestContext.getLocale()); } // 禁止访问 - if (isv.getStatus() == null || isv.getStatus() == STATUS_FORBIDDEN) { + if (isv.getStatus() == null || isv.getStatus() == StatusEnum.DISABLE.getValue()) { throw new ApiException(ErrorEnum.ISV_ACCESS_FORBIDDEN, apiRequestContext.getLocale()); } return isv; @@ -203,7 +206,7 @@ public class ApiValidator implements Validator { apiRequest.takeNameVersion(), ParamNames.SIGN_NAME); } // ISV上传的公钥 - String publicKey = isv.getPublicKey(); + String publicKey = secretManager.getIsvPublicKey(isv.getAppId()); if (ObjectUtils.isEmpty(publicKey)) { throw new ApiException(ErrorEnum.ISV_MISSING_SIGNATURE_CONFIG, apiRequestContext.getLocale(), apiRequest.takeNameVersion()); diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/CopyUtil.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/CopyUtil.java new file mode 100644 index 00000000..53cec887 --- /dev/null +++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/CopyUtil.java @@ -0,0 +1,344 @@ +package com.gitee.sop.index.util; + +import com.alibaba.fastjson2.JSON; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +/** + * 属性拷贝工具类 + * + * @author 六如 + */ +public class CopyUtil extends BeanUtils { + + /** + * 属性拷贝,第一个参数中的属性值拷贝到第二个参数中
+ * 注意:当第一个参数中的属性有null值时,不会拷贝进去 + * + * @param from 源对象 + * @param to 目标对象 + * @param ignoreProperties 忽略的字段 + * @throws BeansException + */ + public static void copyPropertiesIgnoreNull(Object from, Object to, String... ignoreProperties) + throws BeansException { + Assert.notNull(from, "Source must not be null"); + Assert.notNull(to, "Target must not be null"); + + Class actualEditable = to.getClass(); + PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); + List ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : Collections.emptyList()); + + for (PropertyDescriptor targetPd : targetPds) { + if (ignoreList.contains(targetPd.getName())) { + continue; + } + Method writeMethod = targetPd.getWriteMethod(); + if (writeMethod != null) { + PropertyDescriptor sourcePd = getPropertyDescriptor(from.getClass(), targetPd.getName()); + if (sourcePd != null) { + Method readMethod = sourcePd.getReadMethod(); + if (readMethod != null && + ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { + try { + if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { + readMethod.setAccessible(true); + } + Object value = readMethod.invoke(from); + if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { + writeMethod.setAccessible(true); + } + // 这里判断value是否为空 当然这里也能进行一些特殊要求的处理 + // 例如绑定时格式转换等等 + if (value != null) { + writeMethod.invoke(to, value); + } + } catch (Throwable ex) { + throw new FatalBeanException( + "Could not copy property '" + targetPd.getName() + "' from source to target", ex); + } + } + } + } + } + } + + /** + * 拷贝指定的字段 + * + * @param from 源对象 + * @param to 目标对象 + * @param includeFields 指定字段 + */ + public static void copyPropertiesInclude(Object from, Object to, Set includeFields) { + Objects.requireNonNull(includeFields, "includeFields can not null"); + Assert.notNull(from, "Source must not be null"); + Assert.notNull(to, "Target must not be null"); + if (includeFields.isEmpty()) { + return; + } + Class actualEditable = to.getClass(); + PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); + + for (PropertyDescriptor targetPd : targetPds) { + if (!includeFields.contains(targetPd.getName())) { + continue; + } + Method writeMethod = targetPd.getWriteMethod(); + if (writeMethod != null) { + PropertyDescriptor sourcePd = getPropertyDescriptor(from.getClass(), targetPd.getName()); + if (sourcePd != null) { + Method readMethod = sourcePd.getReadMethod(); + if (readMethod != null && + ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) { + try { + if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { + readMethod.setAccessible(true); + } + Object value = readMethod.invoke(from); + if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { + writeMethod.setAccessible(true); + } + writeMethod.invoke(to, value); + } catch (Throwable ex) { + throw new FatalBeanException( + "Could not copy property '" + targetPd.getName() + "' from source to target", ex); + } + } + } + } + } + } + + /** + * 拷贝属性 + * + * @param from 被拷贝类 + * @param to 目标类 + */ + public static void copyProperties(Object from, Object to) { + BeanUtils.copyProperties(from, to); + } + + /** + * 拷贝bean成为一个新类 + * + * @param from 被拷贝类 + * @param supplier 新的类获取回调 + * @param 新的类 + * @return 返回新的类实例,from为null时,返回null + */ + public static T copyBean(Object from, Supplier supplier) { + if (from == null) { + return null; + } + T to = supplier.get(); + BeanUtils.copyProperties(from, to); + return to; + } + + /** + * 拷贝实例 + * + * @param from 被拷贝类 + * @param supplier 新的类获取回调 + * @param after 对新的类最后续处理回调 + * @param 新的类 + * @return 返回新的类 + */ + public static T copyBean(Object from, Supplier supplier, Consumer after) { + if (from == null) { + return null; + } + T to = supplier.get(); + BeanUtils.copyProperties(from, to); + after.accept(to); + return to; + } + + /** + * 拷贝List,将list中的类转换成新的对象 + * + * @param collection 被拷贝的集合 + * @param toElement List新元素 + * @param 新元素类型 + * @return 返回新的List + */ + public static List copyList(Collection collection, Supplier toElement) { + if (collection == null || collection.isEmpty()) { + return new ArrayList<>(); + } + return collection.stream() + .map(source -> { + T target = toElement.get(); + BeanUtils.copyProperties(source, target); + return target; + }) + .collect(Collectors.toList()); + } + + public static List copyList(Collection fromList, Function function) { + if (fromList == null) { + return new ArrayList<>(); + } + return fromList.stream() + .map(source -> { + R target = function.apply(source); + BeanUtils.copyProperties(source, target); + return target; + }) + .collect(Collectors.toList()); + } + + /** + * 拷贝List,并做后续处理 + * + * @param fromList 被拷贝的list + * @param toElement 新元素 + * @param after 对新元素做后续处理 + * @param 新类型 + * @return 返回新的List + */ + public static List copyList(Collection fromList, Supplier toElement, Consumer after) { + if (fromList == null) { + return new ArrayList<>(); + } + return fromList.stream() + .map(source -> { + T target = toElement.get(); + BeanUtils.copyProperties(source, target); + after.accept(target); + return target; + }) + .collect(Collectors.toList()); + } + + /** + * 拷贝List,并做后续处理 + * + * @param fromList 被拷贝的list + * @param toElement 新元素 + * @param after 对新元素做后续处理 + * @param 新类型 + * @return 返回新的List + */ + public static List copyList(Collection fromList, Supplier toElement, CopyConsumer after) { + if (fromList == null) { + return new ArrayList<>(); + } + return fromList.stream() + .map(source -> { + T target = toElement.get(); + BeanUtils.copyProperties(source, target); + after.apply(source, target); + return target; + }) + .collect(Collectors.toList()); + } + + /** + * 深层次拷贝,通过json转换的方式实现 + * + * @param from 待转换的类 + * @param toClass 目标类class + * @param 目标类 + * @return 返回目标类 + */ + public static T deepCopy(Object from, Class toClass) { + String json = JSON.toJSONString(from); + return JSON.parseObject(json, toClass); + } + + /** + * 深层次拷贝,通过json转换的方式实现 + * + * @param from 待转换的类 + * @param toClass 目标类class + * @param 目标类 + * @return 返回目标类 + */ + public static List deepCopyList(Object from, Class toClass) { + String json = JSON.toJSONString(from); + return JSON.parseArray(json, toClass); + } + + + /** + * 拷贝map + * + * @param srcMap 原map + * @param valueGetter 值转换 + * @param Key类型 + * @param Value类型 + * @return 返回新map + */ + public static Map copyMap(Map srcMap, Supplier valueGetter) { + Map ret = new LinkedHashMap<>(srcMap.size() * 2); + for (Map.Entry entry : srcMap.entrySet()) { + V value = copyBean(entry.getValue(), valueGetter); + ret.put(entry.getKey(), value); + } + return ret; + } + + /** + * 拷贝map + * + * @param srcMap 原map + * @param function 值转换 + * @param Key类型 + * @param Value类型 + * @return 返回新map + */ + public static Map copyMap(Map srcMap, Function function) { + Map ret = new LinkedHashMap<>(srcMap.size() * 2); + for (Map.Entry entry : srcMap.entrySet()) { + V value = function.apply(entry.getValue()); + ret.put(entry.getKey(), value); + } + return ret; + } + + /** + * 拷贝map,value是list + * + * @param srcMap 原map + * @param valueGetter 值转换 + * @param Key类型 + * @param Value类型 + * @return 返回新map + */ + public static Map> copyMapList(Map> srcMap, Function, List> valueGetter) { + Map> ret = new LinkedHashMap<>(srcMap.size() * 2); + for (Map.Entry> entry : srcMap.entrySet()) { + List value = valueGetter.apply(entry.getValue()); + ret.put(entry.getKey(), value); + } + return ret; + } + + public interface CopyConsumer { + void apply(F from, T to); + } + +} diff --git a/sop-index/sop-index-service/src/main/resources/application-dev.properties b/sop-index/sop-index-service/src/main/resources/application-dev.properties index 2b4ffeb8..8f16f232 100644 --- a/sop-index/sop-index-service/src/main/resources/application-dev.properties +++ b/sop-index/sop-index-service/src/main/resources/application-dev.properties @@ -1,7 +1,6 @@ dubbo.registry.address=zookeeper://localhost:2181 -spring.datasource.driver-class-name=org.h2.Driver -spring.datasource.url=jdbc:h2:mem:test -spring.sql.init.schema-locations=classpath:schema.sql -spring.datasource.username=${mysql.username} -spring.datasource.password=${mysql.password} +# mysql config +mysql.host=127.0.0.1:3306 +mysql.username=root +mysql.password=root diff --git a/sop-index/sop-index-service/src/main/resources/application.properties b/sop-index/sop-index-service/src/main/resources/application.properties index d86b0ca5..9d7dd677 100644 --- a/sop-index/sop-index-service/src/main/resources/application.properties +++ b/sop-index/sop-index-service/src/main/resources/application.properties @@ -12,17 +12,26 @@ dubbo.protocol.port=-1 # redis://localhost:6379 Cluster config:redis://10.20.153.10:6379?backup=10.20.153.11:6379,10.20.153.12:6379 # ------ dubbo.registry.address=nacos://localhost:8848 -####### dubbo config end ####### ####### mysql config ####### mysql.host=127.0.0.1:3306 -mysql.username=root -mysql.password=root +mysql.username= +mysql.password= mysql.db=sop spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://${mysql.host}/${mysql.db}?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai spring.datasource.username=${mysql.username} spring.datasource.password=${mysql.password} -####### mysql config end ####### + +####### mybatis config ####### +mybatis.fill.com.gitee.fastmybatis.core.support.LocalDateTimeFillInsert=add_time +mybatis.fill.com.gitee.fastmybatis.core.support.LocalDateTimeFillUpdate=update_time +# mybatis config file +mybatis.config-location=classpath:mybatis/mybatisConfig.xml + +# print SQL +logging.level.com.gitee.sop.index.dao=error +logging.level.com.gitee.fastmybatis=debug +mybatis.print-sql=true diff --git a/sop-index/sop-index-service/src/main/resources/mybatis/mybatisConfig.xml b/sop-index/sop-index-service/src/main/resources/mybatis/mybatisConfig.xml new file mode 100644 index 00000000..3c4b234f --- /dev/null +++ b/sop-index/sop-index-service/src/main/resources/mybatis/mybatisConfig.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sop-index/sop-index-service/src/main/resources/schema.sql b/sop-index/sop-index-service/src/main/resources/schema.sql deleted file mode 100644 index de994a50..00000000 --- a/sop-index/sop-index-service/src/main/resources/schema.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE `api_info` -( - `id` INTEGER PRIMARY KEY AUTO_INCREMENT, - `application` varchar(64) NOT NULL DEFAULT '' COMMENT '应用名称', - `api_name` varchar(128) NOT NULL DEFAULT '' COMMENT '接口名称', - `api_version` varchar(16) NOT NULL DEFAULT '1.0' COMMENT '版本号', - `interface_class_name` varchar(128) NOT NULL DEFAULT '' COMMENT '接口class', - `method_name` varchar(128) NOT NULL DEFAULT '' COMMENT '方法名称', - `param_name` varchar(128) NOT NULL DEFAULT '' COMMENT '参数名称', - `param_type_name` varchar(128) NOT NULL DEFAULT '' COMMENT '参数类型名称', - is_permission tinyint(4) NOT NULL DEFAULT '0' COMMENT '接口是否需要授权访问', - is_need_Token tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否需要appAuthToken', - api_status tinyint(4) NOT NULL DEFAULT '1' COMMENT '状态,1-启用,0-禁用', - `add_time` datetime NOT NULL DEFAULT null, - `update_time` datetime NOT NULL DEFAULT null -); diff --git a/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/config/SopAutoConfiguration.java b/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/config/SopAutoConfiguration.java index b9eb4942..905e207e 100644 --- a/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/config/SopAutoConfiguration.java +++ b/sop-spring-boot-starter/src/main/java/com/gitee/sop/support/config/SopAutoConfiguration.java @@ -1,8 +1,10 @@ package com.gitee.sop.support.config; +import com.alibaba.fastjson2.JSON; import com.gitee.sop.index.api.ApiRegisterService; import com.gitee.sop.index.api.RegisterDTO; import com.gitee.sop.support.annotation.Open; +import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.apache.dubbo.config.annotation.DubboService; @@ -15,10 +17,15 @@ import org.springframework.core.env.Environment; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; +import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** @@ -42,7 +49,6 @@ public class SopAutoConfiguration implements InitializingBean { String appName = environment.getProperty("spring.application.name"); Map beanMap = applicationContext.getBeansWithAnnotation(DubboService.class); for (Object serviceObj : beanMap.values()) { - Class objClass = serviceObj.getClass(); Class interfaceClass = findInterfaceClass(serviceObj); ReflectionUtils.doWithMethods(interfaceClass, method -> { regApi(appName, interfaceClass, method); @@ -64,18 +70,14 @@ public class SopAutoConfiguration implements InitializingBean { if (open == null) { return; } - Parameter[] parameters = method.getParameters(); - Optional paramOpt = filterParameter(parameters); - String paramName = paramOpt.map(Parameter::getName).orElse(""); - String paramTypeName = paramOpt.map(Parameter::getType).map(Class::getName).orElse(""); + List paramInfos = buildParamInfo(method); RegisterDTO registerDTO = new RegisterDTO(); registerDTO.setApplication(appName); registerDTO.setApiName(open.value()); registerDTO.setApiVersion(open.version()); registerDTO.setInterfaceClassName(interfaceClass.getName()); registerDTO.setMethodName(method.getName()); - registerDTO.setParamName(paramName); - registerDTO.setParamTypeName(paramTypeName); + registerDTO.setParamInfo(JSON.toJSONString(paramInfos)); registerDTO.setIsPermission(parseBoolean(open.permission())); registerDTO.setIsNeedToken(parseBoolean(open.needToken())); log.info("注册开放接口, apiInfo={}", registerDTO); @@ -86,6 +88,21 @@ public class SopAutoConfiguration implements InitializingBean { } } + private List buildParamInfo(Method method) { + Parameter[] parameters = method.getParameters(); + if (parameters.length == 0) { + return Collections.emptyList(); + } + return Stream.of(parameters) + .map(parameter -> { + ParamInfo paramInfo = new ParamInfo(); + paramInfo.setName(parameter.getName()); + paramInfo.setType(parameter.getType().getName()); + return paramInfo; + }) + .collect(Collectors.toList()); + } + private Optional filterParameter(Parameter[] parameters) { if (ObjectUtils.isEmpty(parameters)) { return Optional.empty(); @@ -96,4 +113,13 @@ public class SopAutoConfiguration implements InitializingBean { private int parseBoolean(boolean b) { return b ? 1 : 0; } + + + @Data + private static class ParamInfo implements Serializable { + private static final long serialVersionUID = -404173450677698875L; + + private String name; + private String type; + } } diff --git a/sop-test/src/test/java/com/gitee/sop/test/AlipayClientPostTest.java b/sop-test/src/test/java/com/gitee/sop/test/AlipayClientPostTest.java index 52e75089..4f5f5902 100644 --- a/sop-test/src/test/java/com/gitee/sop/test/AlipayClientPostTest.java +++ b/sop-test/src/test/java/com/gitee/sop/test/AlipayClientPostTest.java @@ -68,6 +68,41 @@ public class AlipayClientPostTest extends TestBase { System.out.println(responseData); } + @Test + public void testFind() throws Exception { + + // 公共请求参数 + Map params = new HashMap(); + params.put("app_id", appId); + params.put("method", "story.find"); + params.put("format", "json"); + params.put("charset", "utf-8"); + params.put("sign_type", "RSA2"); + params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); + params.put("version", "1.0"); + + // 业务参数 + Map bizContent = new HashMap<>(); + bizContent.put("id", "122"); + bizContent.put("name", "葫芦娃"); + + params.put("biz_content", JSON.toJSONString(bizContent)); + String content = AlipaySignature.getSignContent(params); + String sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8"); + params.put("sign", sign); + + System.out.println("----------- 请求信息 -----------"); + System.out.println("请求参数:" + buildParamQuery(params)); + System.out.println("商户秘钥:" + privateKey); + System.out.println("待签名内容:" + content); + System.out.println("签名(sign):" + sign); + System.out.println("URL参数:" + buildUrlQuery(params)); + + System.out.println("----------- 返回结果 -----------"); + String responseData = postJson(url, params);// 发送请求 + System.out.println(responseData); + } + @Test public void testSave() throws Exception {