The time on the server is ${serverTime}.
- - diff --git a/sop-example/sop-springmvc/src/main/webapp/WEB-INF/web.xml b/sop-example/sop-springmvc/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 630564eb..00000000 --- a/sop-example/sop-springmvc/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,61 +0,0 @@ - -+ * + * xml返回结果: + *+ *+ * + * 成功情况: + *50
+ *Remote service error + *isv.invalid-parameter + *非法参数 + *+ * + * + * json返回格式: + * { + * "code":"50", + * "msg":"Remote service error", + * "sub_code":"isv.invalid-parameter", + * "sub_msg":"非法参数" + * } + * 成功情况: + * { + * "code":"0", + * "msg":"成功消息内容。。。", + * "data":{ + * ...返回内容 + * } + * } + *0
+ *成功消息 + * + * ...返回内容 + * + *
+ * 字段说明:
+ * code:网关异常码
- * 字段说明:
- * code:网关异常码
+ * msg:网关异常信息
+ * sub_code:业务异常码
+ * sub_msg:业务异常信息
+ *
+ * @author tanghc
+ */
+@Data
+public class ApiResponse {
+
+ public static final String SUCCESS_CODE = "0";
+ public static final String SUCCESS_MSG = "success";
+ /**
+ * 网关异常码,范围0~100 成功返回"0"
+ */
+ private String code = SUCCESS_CODE;
+
+ /**
+ * 网关异常信息
+ */
+ private String msg;
+
+ /**
+ * 业务异常码
+ */
+ private String sub_code;
+
+ /**
+ * 业务异常信息
+ */
+ private String sub_msg;
+
+ /**
+ * 返回对象
+ */
+ private Object data;
+
+ public static ApiResponse success(Object data) {
+ ApiResponse apiResponse = new ApiResponse();
+ apiResponse.setCode(SUCCESS_CODE);
+ apiResponse.setMsg(SUCCESS_MSG);
+ apiResponse.setData(data);
+ return apiResponse;
+ }
+
+
+ public static ApiResponse error(ErrorEnum errorEnum) {
+ ApiResponse apiResponse = new ApiResponse();
+ ErrorMeta errorMeta = errorEnum.getErrorMeta();
+ IError error = errorMeta.getError(Locale.SIMPLIFIED_CHINESE);
+ apiResponse.setCode(error.getCode());
+ apiResponse.setMsg(error.getMsg());
+ apiResponse.setSub_code(error.getSub_code());
+ apiResponse.setSub_msg(error.getSub_msg());
+ return apiResponse;
+ }
+
+ public static ApiResponse error(ErrorEnum errorEnum, String subMsg) {
+ ApiResponse apiResponse = new ApiResponse();
+ ErrorMeta errorMeta = errorEnum.getErrorMeta();
+ IError error = errorMeta.getError(Locale.SIMPLIFIED_CHINESE);
+ apiResponse.setCode(error.getCode());
+ apiResponse.setMsg(error.getMsg());
+ apiResponse.setSub_code(error.getSub_code());
+ apiResponse.setSub_msg(subMsg);
+ return apiResponse;
+ }
+
+}
diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dubbo/ApiRegisterServiceImpl.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dubbo/ApiRegisterServiceImpl.java
new file mode 100644
index 00000000..835398cf
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/dubbo/ApiRegisterServiceImpl.java
@@ -0,0 +1,29 @@
+package com.gitee.sop.index.dubbo;
+
+import com.gitee.sop.index.api.ApiRegisterService;
+import com.gitee.sop.index.api.RegisterDTO;
+import com.gitee.sop.index.common.ApiInfoDTO;
+import com.gitee.sop.index.service.manager.ApiCacheManager;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author 六如
+ */
+@Slf4j
+@DubboService
+public class ApiRegisterServiceImpl implements ApiRegisterService {
+
+ @Autowired
+ private ApiCacheManager apiCache;
+
+ @Override
+ public void register(RegisterDTO registerDTO) {
+ log.info("收到接口注册, registerDTO={}", registerDTO);
+ ApiInfoDTO apiInfoDTO = new ApiInfoDTO();
+ BeanUtils.copyProperties(registerDTO, apiInfoDTO);
+ apiCache.save(apiInfoDTO);
+ }
+}
diff --git a/sop-index/src/main/java/com/gitee/sop/index/exception/ApiException.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/ApiException.java
similarity index 83%
rename from sop-index/src/main/java/com/gitee/sop/index/exception/ApiException.java
rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/ApiException.java
index fd543e1d..87c2c4cf 100644
--- a/sop-index/src/main/java/com/gitee/sop/index/exception/ApiException.java
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/exception/ApiException.java
@@ -1,9 +1,9 @@
package com.gitee.sop.index.exception;
-
import com.gitee.sop.index.message.ErrorFactory;
import com.gitee.sop.index.message.ErrorMeta;
+import com.gitee.sop.index.message.IError;
import java.util.Locale;
@@ -11,8 +11,9 @@ import java.util.Locale;
* @author tanghc
*/
public class ApiException extends RuntimeException {
+ private static final long serialVersionUID = 8278005515613227643L;
- private transient Error error;
+ private transient IError error;
private transient ErrorMeta errorMeta;
private transient Object[] params;
@@ -28,7 +29,7 @@ public class ApiException extends RuntimeException {
this.params = params;
}
- public Error getError(Locale locale) {
+ public IError getError(Locale locale) {
if (error == null) {
error = ErrorFactory.getError(this.errorMeta, locale, params);
}
diff --git a/sop-index/src/main/java/com/gitee/sop/index/message/ErrorEnum.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorEnum.java
similarity index 98%
rename from sop-index/src/main/java/com/gitee/sop/index/message/ErrorEnum.java
rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorEnum.java
index b9ab6791..00b44861 100644
--- a/sop-index/src/main/java/com/gitee/sop/index/message/ErrorEnum.java
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorEnum.java
@@ -51,6 +51,8 @@ public enum ErrorEnum {
/** 参数无效 */
ISV_INVALID_PARAMETER(Codes.CODE_INVALID, "isv.invalid-parameter"),
+ /** 参数不正确 */
+ ISV_ERROR_PARAMETER(Codes.CODE_INVALID, "isv.error-parameter"),
/** 文件上传失败 */
ISV_UPLOAD_FAIL(Codes.CODE_INVALID, "isv.upload-fail"),
/** 文件扩展名无效 */
diff --git a/sop-index/src/main/java/com/gitee/sop/index/message/ErrorFactory.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorFactory.java
similarity index 100%
rename from sop-index/src/main/java/com/gitee/sop/index/message/ErrorFactory.java
rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorFactory.java
diff --git a/sop-index/src/main/java/com/gitee/sop/index/message/ErrorImpl.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorImpl.java
similarity index 100%
rename from sop-index/src/main/java/com/gitee/sop/index/message/ErrorImpl.java
rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorImpl.java
diff --git a/sop-index/src/main/java/com/gitee/sop/index/message/ErrorMeta.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorMeta.java
similarity index 100%
rename from sop-index/src/main/java/com/gitee/sop/index/message/ErrorMeta.java
rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/ErrorMeta.java
diff --git a/sop-index/src/main/java/com/gitee/sop/index/message/IError.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/IError.java
similarity index 100%
rename from sop-index/src/main/java/com/gitee/sop/index/message/IError.java
rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/message/IError.java
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/ApiService.java
new file mode 100644
index 00000000..272fa7b6
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/ApiService.java
@@ -0,0 +1,25 @@
+package com.gitee.sop.index.service;
+
+import com.gitee.sop.index.common.ApiInfoDTO;
+import com.gitee.sop.index.service.manager.ApiCacheManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author 六如
+ */
+@Service
+public class ApiService {
+
+ @Autowired
+ private ApiCacheManager apiCacheManager;
+
+ public ApiInfoDTO getApi(String apiName, String apiVersion) {
+ return apiCacheManager.getOrElse(apiName, apiVersion, () -> {
+ ApiInfoDTO record = new ApiInfoDTO();
+
+ return record;
+ });
+ }
+
+}
diff --git a/sop-index/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
similarity index 82%
rename from sop-index/src/main/java/com/gitee/sop/index/service/GenericServiceInvoker.java
rename to sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/GenericServiceInvoker.java
index 85984d9b..73ac1647 100644
--- a/sop-index/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
@@ -4,41 +4,38 @@ import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.service.GenericService;
+import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
-
-import javax.annotation.PostConstruct;
+import org.springframework.stereotype.Service;
/**
* dubbo泛化调用
*
* @author 六如
*/
-public class GenericServiceInvoker {
+@Service
+public class GenericServiceInvoker implements InitializingBean {
private ApplicationConfig applicationConfig;
@Value("${nacos.host:localhost:8848}")
private String nacosHost;
- @Value("${nacos.group:DEFAULT}")
- private String group;
-
@Value("${spring.application.name}")
private String appName;
@Value("${generic.timeout:5000}")
private int timeout;
- @PostConstruct
- public void init() {
- RegistryConfig registryConfig = buildRegistryConfig(nacosHost, group);
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ RegistryConfig registryConfig = buildRegistryConfig(nacosHost);
applicationConfig = new ApplicationConfig();
applicationConfig.setName(appName + "-generic");
applicationConfig.setRegistry(registryConfig);
}
- private RegistryConfig buildRegistryConfig(String nacosHost, String group) {
+ private RegistryConfig buildRegistryConfig(String nacosHost) {
RegistryConfig config = new RegistryConfig();
- config.setGroup(group);
config.setAddress("nacos://" + nacosHost);
return config;
}
@@ -48,10 +45,7 @@ public class GenericServiceInvoker {
reference.setGeneric("true");
reference.setApplication(applicationConfig);
reference.setInterface(interfaceName);
- reference.setGroup(group);
reference.setTimeout(timeout);
- reference.setSticky(false);
- reference.setCheck(false);
try {
removeGenericSymbol(parameterTypes);
GenericService genericService = reference.get();
@@ -61,6 +55,7 @@ public class GenericServiceInvoker {
}
}
+
/**
* remove generic from parameterTypes
*/
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
new file mode 100644
index 00000000..8172f433
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/service/RouteService.java
@@ -0,0 +1,122 @@
+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.controller.param.ApiRequest;
+import com.gitee.sop.index.controller.param.ApiResponse;
+import com.gitee.sop.index.message.ErrorEnum;
+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.apache.dubbo.rpc.service.GenericException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 接口路由
+ *
+ * @author 六如
+ */
+@Service
+@Slf4j
+public class RouteService {
+
+ private static final String CONSTRAINT_VIOLATION_EXCEPTION = "ConstraintViolationException";
+
+ @Autowired
+ private Validator validator;
+
+ @Autowired
+ private GenericServiceInvoker genericServiceInvoker;
+
+ @Autowired
+ private ApiService apiService;
+
+ public ApiResponse route(ApiRequest apiRequest) {
+ // 校验
+ validator.validate(apiRequest);
+ return doRoute(apiRequest);
+ }
+
+ private ApiResponse doRoute(ApiRequest apiRequest) {
+ ApiInfoDTO apiInfo = apiService.getApi(apiRequest.getMethod(), apiRequest.getVersion());
+ Object result = null;
+ Exception error = null;
+
+ beforeRoute(apiRequest, apiInfo);
+ try {
+ result = genericServiceInvoker.invoke(
+ apiInfo.getInterfaceClassName(),
+ apiInfo.getMethodName(),
+ new String[]{apiInfo.getParamTypeName()},
+ new Object[]{buildInvokeParam(apiRequest, apiInfo)}
+ );
+ } catch (Exception e) {
+ error = e;
+ log.error("请求服务出错, apiRequest={}, apiInfo={}", apiInfo, apiInfo, e);
+ return buildApiResponse(e);
+ } finally {
+ afterRoute(result, apiRequest, error);
+ }
+ return ApiResponse.success(result);
+ }
+
+ private ApiResponse buildApiResponse(Exception e) {
+ if (e instanceof GenericException) {
+ GenericException genericException = (GenericException) e;
+ String exceptionClass = genericException.getExceptionClass();
+ if (exceptionClass.contains(CONSTRAINT_VIOLATION_EXCEPTION)) {
+ String exceptionMessage = genericException.getExceptionMessage();
+ // 参数校验:Failed to validate service: com.gitee.sop.storyweb.open.StoryService, method: save, cause: [ConstraintViolationImpl{interpolatedMessage='故事名称必填', propertyPath=storyName, rootBeanClass=class com.gitee.sop.storyweb.open.req.StorySaveDTO, messageTemplate='故事名称必填'}]
+ Set
+ *
+ *
+ * 字符集:UTF-8
+ * 算法模式:ECB
+ * 数据块:128位
+ * 补码方式:PKCS5Padding
+ * 加密结果编码方式:Base64
+ *
+ *
+ * @author tanghc
+ *
+ */
+public class AESUtil {
+ private static final String UTF8 = "UTF-8";
+ private static final String ALGORITHM = "AES";
+ /** 默认的加密算法 */
+ private static final String ALGORITHM_CIPHER = "AES/ECB/PKCS5Padding";
+
+ private static final int LIMIT_LEN = 16;
+
+ /**
+ * 生成一个SecretKey
+ * @param password 长度必须小于等于16
+ * @return 返回SecretKey
+ */
+ public static SecretKey getSecretKey(String password) {
+ byte[] passwordData = password.getBytes();
+ if(passwordData.length > LIMIT_LEN) {
+ throw new IllegalArgumentException("password 长度必须小于等于16");
+ }
+ // 创建一个空的16位字节数组(默认值为0),16byte(128bit)
+ byte[] keyData = new byte[16];
+ System.arraycopy(passwordData, 0, keyData, 0, passwordData.length);
+
+ return new SecretKeySpec(keyData, ALGORITHM);
+ }
+
+ /**
+ * 加密
+ * @param data 待加密数据
+ * @param password 密码
+ * @return 返回加密成功后数据
+ * @throws Exception
+ */
+ public static byte[] encrypt(byte[] data, String password) throws Exception {
+ SecretKey secretKey = getSecretKey(password);
+ // Ciphr完成加密或解密工作类
+ Cipher cipher = Cipher.getInstance(ALGORITHM_CIPHER);
+ // 对Cipher初始化,解密模式
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ // 加密data
+ return cipher.doFinal(data);
+ }
+
+ /**
+ * 解密
+ * @param data 待解密数据
+ * @param password 密码
+ * @return 返回解密后的数据
+ * @throws Exception
+ */
+ public static byte[] decrypt(byte[] data, String password) throws Exception {
+ SecretKey secretKey = getSecretKey(password);
+ // Cipher完成加密或解密工作类
+ Cipher cipher = Cipher.getInstance(ALGORITHM_CIPHER);
+ // 对Cipher初始化,解密模式
+ cipher.init(Cipher.DECRYPT_MODE, secretKey);
+ // 解密data
+ return cipher.doFinal(data);
+ }
+
+ /**
+ * 文本加密
+ * @param content 明文
+ * @param password 密码
+ * @return 返回base64内容
+ * @throws Exception
+ */
+ public static String encryptToBase64String(String content, String password) throws Exception {
+ byte[] data = content.getBytes(UTF8);
+ byte[] result = encrypt(data, password);
+ return Base64.encodeBase64String(result);
+ }
+
+ /**
+ * 文本解密
+ * @param base64String 待解密文本
+ * @param password 密码
+ * @return 返回明文
+ * @throws Exception
+ */
+ public static String decryptFromBase64String(String base64String, String password) throws Exception {
+ byte[] data = Base64.decodeBase64(base64String);
+ byte[] contentData = decrypt(data, password);
+ return new String(contentData, UTF8);
+ }
+
+ /**
+ * 文本加密
+ * @param content 明文
+ * @param password 密码
+ * @return 返回16进制内容
+ * @throws Exception
+ */
+ public static String encryptToHex(String content, String password) throws Exception {
+ byte[] data = content.getBytes(UTF8);
+ byte[] result = encrypt(data, password);
+ return Hex.encodeHexString(result);
+ }
+
+ /**
+ * 文本解密
+ * @param hex 待解密文本
+ * @param password 密码
+ * @return 返回明文
+ * @throws Exception
+ */
+ public static String decryptFromHex(String hex, String password) throws Exception {
+ byte[] data = Hex.decodeHex(hex);
+ byte[] contentData = decrypt(data, password);
+ return new String(contentData,UTF8);
+ }
+
+ /*public static void main(String[] args) throws Exception {
+ String content = "我爱你";
+ String password = "1234567890123456";
+ System.out.println("password:" + password);
+
+ String ret2 = encryptToBase64String(content, password);
+ System.out.println("密文:" + ret2);
+ String content3 = decryptFromBase64String(ret2, password);
+ System.out.println(content.equals(content3));
+ }*/
+
+}
diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/ClassUtil.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/ClassUtil.java
new file mode 100644
index 00000000..1838f40c
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/ClassUtil.java
@@ -0,0 +1,64 @@
+package com.gitee.sop.index.util;
+
+import java.util.Objects;
+
+
+/**
+ *
+ */
+public class ClassUtil {
+
+ public static final String PREFIX_JAVA_LANG = "java.lang.";
+
+ /**
+ * Check if it is the basic data type of json data
+ *
+ * @param type0 java class name
+ * @return boolean
+ */
+ public static boolean isPrimitive(String type0) {
+ if (Objects.isNull(type0)) {
+ return true;
+ }
+ String type = type0.startsWith(PREFIX_JAVA_LANG) ? type0.substring(type0.lastIndexOf(".") + 1) : type0;
+ type = type.toLowerCase();
+ switch (type) {
+ case "string":
+ case "integer":
+ case "int":
+ case "object":
+ case "void":
+ case "long":
+ case "double":
+ case "float":
+ case "short":
+ case "bigdecimal":
+ case "char":
+ case "character":
+ case "number":
+ case "boolean":
+ case "byte":
+ case "uuid":
+ case "biginteger":
+ case "java.sql.timestamp":
+ case "java.util.date":
+ case "java.time.localdatetime":
+ case "java.time.localtime":
+ case "localtime":
+ case "date":
+ case "localdatetime":
+ case "localdate":
+ case "zoneddatetime":
+ case "java.time.localdate":
+ case "java.time.zoneddatetime":
+ case "java.math.bigdecimal":
+ case "java.math.biginteger":
+ case "java.util.uuid":
+ case "java.io.serializable":
+ return true;
+ default:
+ return false;
+ }
+ }
+
+}
diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/KeyStore.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/KeyStore.java
new file mode 100644
index 00000000..42a2f7c9
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/KeyStore.java
@@ -0,0 +1,25 @@
+package com.gitee.sop.index.util;
+
+/**
+ * @author tanghc
+ */
+public class KeyStore {
+ private String publicKey;
+ private String privateKey;
+
+ public String getPublicKey() {
+ return publicKey;
+ }
+
+ public void setPublicKey(String publicKey) {
+ this.publicKey = publicKey;
+ }
+
+ public String getPrivateKey() {
+ return privateKey;
+ }
+
+ public void setPrivateKey(String privateKey) {
+ this.privateKey = privateKey;
+ }
+}
diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RSANewUtil.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RSANewUtil.java
new file mode 100644
index 00000000..e31d0d1e
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RSANewUtil.java
@@ -0,0 +1,208 @@
+package com.gitee.sop.index.util;
+
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * RSA加解密工具
+ * @author tanghc
+ */
+public class RSANewUtil {
+ public static final String RSA_ALGORITHM = "RSA";
+ public static final String UTF8 = "UTF-8";
+
+ /**
+ * 创建公钥私钥
+ *
+ * @return 返回公私钥对
+ * @throws Exception
+ */
+ public static KeyStore createKeys() throws Exception {
+ KeyPairGenerator keyPairGeno = KeyPairGenerator.getInstance(RSA_ALGORITHM);
+ keyPairGeno.initialize(1024);
+ KeyPair keyPair = keyPairGeno.generateKeyPair();
+
+ RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+ RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+
+ KeyStore keyStore = new KeyStore();
+ keyStore.setPublicKey(Base64.encodeBase64String(publicKey.getEncoded()));
+ keyStore.setPrivateKey(Base64.encodeBase64String(privateKey.getEncoded()));
+ return keyStore;
+ }
+
+ /**
+ * 获取公钥对象
+ *
+ * @param pubKeyData 公钥数据
+ * @return 公钥对象
+ * @throws Exception
+ */
+ public static RSAPublicKey getPublicKey(byte[] pubKeyData) throws Exception {
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyData);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
+ return (RSAPublicKey) keyFactory.generatePublic(keySpec);
+ }
+
+ /**
+ * 获取公钥对象
+ *
+ * @param pubKey
+ * 公钥
+ * @return 返回公钥对象
+ * @throws Exception
+ */
+ public static RSAPublicKey getPublicKey(String pubKey) throws Exception {
+ return getPublicKey(Base64.decodeBase64(pubKey));
+
+ }
+
+ /**
+ * 获取私钥对象
+ *
+ * @param priKey
+ * 私钥
+ * @return 返回私钥对象
+ * @throws Exception
+ */
+ public static RSAPrivateKey getPrivateKey(String priKey) throws Exception {
+ return getPrivateKey(Base64.decodeBase64(priKey));
+ }
+
+ /**
+ * 通过私钥byte[]将公钥还原,适用于RSA算法
+ *
+ * @param keyBytes 私钥数据
+ * @return 返回公钥对象
+ * @throws Exception
+ */
+ public static RSAPrivateKey getPrivateKey(byte[] keyBytes) throws Exception {
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
+ return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
+
+ }
+
+ public static String encryptByPublicKey(String data, String publicKey) throws Exception {
+ return encryptByPublicKey(data, getPublicKey(publicKey));
+ }
+
+ /**
+ * 公钥加密
+ *
+ * @param data 内容
+ * @param publicKey 公钥
+ * @return 返回密文
+ * @throws Exception
+ */
+ public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ byte[] bytes = cipher.doFinal(data.getBytes(UTF8));
+ return Base64.encodeBase64String(bytes);
+ }
+
+ public static String decryptByPublicKey(String data, String rsaPublicKey) throws Exception {
+ return decryptByPublicKey(data, getPublicKey(rsaPublicKey));
+ }
+
+ /**
+ * 公钥解密
+ *
+ * @param data 待解密内容
+ * @param rsaPublicKey 公钥
+ * @return 返回明文
+ * @throws Exception
+ */
+ public static String decryptByPublicKey(String data, RSAPublicKey rsaPublicKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+ cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey);
+ byte[] inputData = Base64.decodeBase64(data);
+ byte[] bytes = cipher.doFinal(inputData);
+ return new String(bytes, UTF8);
+ }
+
+ public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
+ return encryptByPrivateKey(data, getPrivateKey(privateKey));
+ }
+
+ /**
+ * 私钥加密
+ *
+ * @param data 内容
+ * @param privateKey 私钥
+ * @return 返回密文
+ * @throws Exception
+ */
+ public static String encryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, privateKey);
+ byte[] bytes = cipher.doFinal(data.getBytes(UTF8));
+ return Base64.encodeBase64String(bytes);
+ }
+
+ public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
+ return decryptByPrivateKey(data, getPrivateKey(privateKey));
+ }
+
+ /**
+ * 私钥解密
+ *
+ * @param data 待解密内容
+ * @param privateKey 私钥
+ * @return 返回明文
+ * @throws Exception
+ */
+ public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
+ byte[] inputData = Base64.decodeBase64(data);
+ byte[] bytes = cipher.doFinal(inputData);
+ return new String(bytes, UTF8);
+ }
+
+
+ /*
+ pubKey:
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCG/iIZZzb16PxKqslkDMYa4tVFb3IVPBpLj4BgHQmDfe843sG4gkJIPXCm7+t6QxIbfDfynBpqZJLvu0c6E7TqlCtynBIlRFOBZrQVNEFkaanR2Kln3vd3CIidR571UstOC32XDyqAQNlvjD19zeIDVfmLa0Q+Or0zaxY99QwBHwIDAQAB
+priKey:
+MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIb+IhlnNvXo/EqqyWQMxhri1UVvchU8GkuPgGAdCYN97zjewbiCQkg9cKbv63pDEht8N/KcGmpkku+7RzoTtOqUK3KcEiVEU4FmtBU0QWRpqdHYqWfe93cIiJ1HnvVSy04LfZcPKoBA2W+MPX3N4gNV+YtrRD46vTNrFj31DAEfAgMBAAECgYBiNPQdwwcq86rHr2QAE4L0AF3ju+YlKKqAmg9s3PMU5ENq/jO0xZ7u6zPPXu/S7IR51m7lY0ecazqyiW6SA9AzYH7ImWWkZ4stZ03beTB2US3cSeJIkugoexoN5fQRAGZiZezTLs91CeJivESOZyDKnnQdgJ49mveBV5OvievD8QJBAMztpqiWWavdR4tqQ+plat+rwYoXqejsK3Hyfg0pVJqEdazve2sr74rla7yI9P47ZAh1sklCv0CO//ctICv366UCQQCoop3T0FeZtbKJG+fHzZvpAe63tXpdhLMaQvTBuXLG8vi78Wyfhg5r7HOWR0Z1V7nzF1gzMywL53Pmkq9tB65zAkAiHu/A4kfL9ewTqn3kaT6CP3baJ1aDEc+qCVYzms4bbDKruLQ0A/y+g7SMj8E7E2h0gCRPTm3JsgWsgjb5Gy6BAkAA8mjQd6sGQe7utilnBdCKTmh4v5wgSk53J0kYjWIHm/WpmIFzo90Q3hMIFP5gSk3Q/6CPKQpmRrZv5QL3KcPhAkEAuMoQbij/7hyLlIxRHZs2SMXxfHPiZgDc6rVi1KNxeq8HXTlERi7Npc2Uz5TeWN4JwBBx9uA50zowk9iS05nclQ==
+用公钥加密mi : c3B0jtMdvkqrgaPxHZCK2cXMUQC2QzLud2ouLMNx0nBAj9k2/ytOuVJViTGe/DozB/ky5jvl4spD9Ey6aTMrwLHfQVhn0gRJ+wHcmx/51dXQDIgsldt6bf7YpdPdnghBjQz2+P5RhqSkeFDbTZKkl2BNaLE78a/OyWWeCGwN+4s=
+true
+用私钥加密mi2 : QU5vDnQ1ukj8GsauokFlgcB/g61U882tj82wHGrrqHEnvaga+4cXjML9RhjpZtKqwDGZTCujsmpynDk4qek6IGOQ/oxdWLwV4ZNjfa/oqA8OFDothVUT8wpqCu9kOYHrTdGybmXD0dB2Iy1/AMQTAgPNNXXiRXdvsz9xWYTV6z8=
+true
+ */
+ /*public static void main(String[] args) throws Exception {
+ KeyStore keys = createKeys();
+ String pubKey = keys.getPublicKey();
+ System.out.println("pubKey:");
+ System.out.println(pubKey);
+ String priKey = keys.getPrivateKey();
+ System.out.println("priKey:");
+ System.out.println(priKey);
+
+ String ming = "1234567890123456";
+ // 用公钥加密
+ String mi = encryptByPublicKey(ming, pubKey);
+ System.out.println("用公钥加密mi : " + mi);
+ // 用私钥解密
+ System.out.println(ming.equals(decryptByPrivateKey(mi, priKey)));
+
+ // 用私钥加密
+ String mi2 = encryptByPrivateKey(ming, priKey);
+
+ System.out.println("用私钥加密mi2 : " + mi2);
+ // 用公钥解密
+ String ming2 = decryptByPublicKey(mi2, pubKey);
+ System.out.println(ming.equals(ming2));
+ }*/
+
+}
diff --git a/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RSAUtil.java b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RSAUtil.java
new file mode 100644
index 00000000..b77ae897
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/java/com/gitee/sop/index/util/RSAUtil.java
@@ -0,0 +1,312 @@
+package com.gitee.sop.index.util;
+
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * RSA加解密工具
+ * @author tanghc
+ */
+public class RSAUtil {
+ public static String RSA_ALGORITHM = "RSA";
+
+ /**
+ * 创建公钥私钥
+ *
+ * @return 返回公私钥对
+ * @throws Exception
+ */
+ public static KeyStore createKeys() throws Exception {
+ KeyPairGenerator keyPairGeno = KeyPairGenerator.getInstance(RSA_ALGORITHM);
+ keyPairGeno.initialize(1024);
+ KeyPair keyPair = keyPairGeno.generateKeyPair();
+
+ RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+ RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
+
+ KeyStore keyStore = new KeyStore();
+ keyStore.setPublicKey(Base64.encodeBase64String(publicKey.getEncoded()));
+ keyStore.setPrivateKey(Base64.encodeBase64String(privateKey.getEncoded()));
+ return keyStore;
+ }
+
+ /**
+ * 获取公钥对象
+ *
+ * @param pubKeyData 公钥
+ * @return 返回公钥对象
+ * @throws Exception
+ */
+ public static RSAPublicKey getPublicKey(byte[] pubKeyData) throws Exception {
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyData);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
+ return (RSAPublicKey) keyFactory.generatePublic(keySpec);
+ }
+
+ /**
+ * 获取公钥对象
+ *
+ * @param pubKey
+ * 公钥
+ * @return 返回私钥对象
+ * @throws Exception
+ */
+ public static RSAPublicKey getPublicKey(String pubKey) throws Exception {
+ return getPublicKey(Base64.decodeBase64(pubKey));
+
+ }
+
+ /**
+ * 获取私钥对象
+ *
+ * @param priKey
+ * 私钥
+ * @return 私钥对象
+ * @throws Exception
+ */
+ public static RSAPrivateKey getPrivateKey(String priKey) throws Exception {
+ return getPrivateKey(Base64.decodeBase64(priKey));
+ }
+
+ /**
+ * 通过私钥byte[]将公钥还原,适用于RSA算法
+ *
+ * @param keyBytes
+ * @return 返回私钥
+ * @throws Exception
+ */
+ public static RSAPrivateKey getPrivateKey(byte[] keyBytes) throws Exception {
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+ KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
+ return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
+
+ }
+
+ /**
+ * 公钥加密
+ *
+ * @param data 待加密内容
+ * @param publicKey 公钥
+ * @return 返回密文
+ * @throws Exception
+ */
+ public static String encryptByPublicKey(String data, RSAPublicKey publicKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ // 模长
+ int key_len = publicKey.getModulus().bitLength() / 8;
+ // 加密数据长度 <= 模长-11
+ String[] datas = splitString(data, key_len - 11);
+ String mi = "";
+ // 如果明文长度大于模长-11则要分组加密
+ for (String s : datas) {
+ mi += bcd2Str(cipher.doFinal(s.getBytes()));
+ }
+ return mi;
+ }
+ public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
+ return encryptByPrivateKey(data, getPrivateKey(privateKey));
+ }
+
+ /**
+ * 私钥加密
+ *
+ * @param data 待加密数据
+ * @param privateKey 私钥
+ * @return 返回密文
+ * @throws Exception
+ */
+ public static String encryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, privateKey);
+ // 模长
+ int key_len = privateKey.getModulus().bitLength() / 8;
+ // 加密数据长度 <= 模长-11
+ String[] datas = splitString(data, key_len - 11);
+ String mi = "";
+ // 如果明文长度大于模长-11则要分组加密
+ for (String s : datas) {
+ mi += bcd2Str(cipher.doFinal(s.getBytes()));
+ }
+ return mi;
+ }
+
+ public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
+ return decryptByPrivateKey(data, getPrivateKey(privateKey));
+ }
+
+ /**
+ * 私钥解密
+ *
+ * @param data 待解密内容
+ * @param privateKey 私钥
+ * @return 返回明文
+ * @throws Exception
+ */
+ public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+ cipher.init(Cipher.DECRYPT_MODE, privateKey);
+ // 模长
+ int key_len = privateKey.getModulus().bitLength() / 8;
+ byte[] bytes = data.getBytes();
+ byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
+ // 如果密文长度大于模长则要分组解密
+ String ming = "";
+ byte[][] arrays = splitArray(bcd, key_len);
+ for (byte[] arr : arrays) {
+ ming += new String(cipher.doFinal(arr));
+ }
+ return ming;
+ }
+
+ /**
+ * 公钥解密
+ *
+ * @param data 待解密内容
+ * @param rsaPublicKey 公钥
+ * @return 返回明文
+ * @throws Exception
+ */
+ public static String decryptByPublicKey(String data, RSAPublicKey rsaPublicKey) throws Exception {
+ Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
+ cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey);
+ // 模长
+ int key_len = rsaPublicKey.getModulus().bitLength() / 8;
+ byte[] bytes = data.getBytes();
+ byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
+ // 如果密文长度大于模长则要分组解密
+ String ming = "";
+ byte[][] arrays = splitArray(bcd, key_len);
+ for (byte[] arr : arrays) {
+ ming += new String(cipher.doFinal(arr));
+ }
+ return ming;
+ }
+
+
+ /**
+ * ASCII码转BCD码
+ *
+ */
+ public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
+ byte[] bcd = new byte[asc_len / 2];
+ int j = 0;
+ for (int i = 0; i < (asc_len + 1) / 2; i++) {
+ bcd[i] = asc_to_bcd(ascii[j++]);
+ bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++]) & 0xff) + (bcd[i] << 4));
+ }
+ return bcd;
+ }
+
+ public static byte asc_to_bcd(byte asc) {
+ byte bcd;
+
+ if ((asc >= '0') && (asc <= '9')) {
+ bcd = (byte) (asc - '0');
+ } else if ((asc >= 'A') && (asc <= 'F')) {
+ bcd = (byte) (asc - 'A' + 10);
+ } else if ((asc >= 'a') && (asc <= 'f')) {
+ bcd = (byte) (asc - 'a' + 10);
+ } else {
+ bcd = (byte) (asc - 48);
+ }
+ return bcd;
+ }
+
+ /**
+ * BCD转字符串
+ */
+ public static String bcd2Str(byte[] bytes) {
+ char[] temp = new char[bytes.length * 2];
+ char val;
+
+ for (int i = 0; i < bytes.length; i++) {
+ val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
+ temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
+
+ val = (char) (bytes[i] & 0x0f);
+ temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
+ }
+ return new String(temp);
+ }
+
+ /**
+ * 拆分字符串
+ */
+ public static String[] splitString(String string, int len) {
+ int x = string.length() / len;
+ int y = string.length() % len;
+ int z = 0;
+ if (y != 0) {
+ z = 1;
+ }
+ String[] strings = new String[x + z];
+ String str = "";
+ for (int i = 0; i < x + z; i++) {
+ if (i == x + z - 1 && y != 0) {
+ str = string.substring(i * len, i * len + y);
+ } else {
+ str = string.substring(i * len, i * len + len);
+ }
+ strings[i] = str;
+ }
+ return strings;
+ }
+
+ /**
+ * 拆分数组
+ */
+ public static byte[][] splitArray(byte[] data, int len) {
+ int x = data.length / len;
+ int y = data.length % len;
+ int z = 0;
+ if (y != 0) {
+ z = 1;
+ }
+ byte[][] arrays = new byte[x + z][];
+ byte[] arr;
+ for (int i = 0; i < x + z; i++) {
+ arr = new byte[len];
+ if (i == x + z - 1 && y != 0) {
+ System.arraycopy(data, i * len, arr, 0, y);
+ } else {
+ System.arraycopy(data, i * len, arr, 0, len);
+ }
+ arrays[i] = arr;
+ }
+ return arrays;
+ }
+
+ /*public static void main(String[] args) throws Exception {
+ KeyStore keys = createKeys();
+ String pubKey = keys.getPublicKey();
+ System.out.println("pubKey:");
+ System.out.println(pubKey);
+ String priKey = keys.getPrivateKey();
+ System.out.println("priKey:");
+ System.out.println(priKey);
+
+ String ming = "6460201d23954f8e90cf79b818844ca0";
+ // 用公钥加密
+ String mi = encryptByPublicKey(ming, getPublicKey(pubKey));
+ System.out.println("mi : " + mi);
+ // 用私钥解密
+ System.out.println("ming : " + decryptByPrivateKey(mi, getPrivateKey(priKey)));
+
+ // 用私钥加密
+ String mi2 = encryptByPrivateKey(ming, getPrivateKey(priKey));
+
+ System.out.println("mi2 : " + mi2);
+ // 用公钥解密
+ System.out.println("ming2 : " + decryptByPublicKey(mi2, getPublicKey(pubKey)));
+ }*/
+
+}
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
new file mode 100644
index 00000000..171e376d
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/resources/application-dev.properties
@@ -0,0 +1,5 @@
+nacos.host=127.0.0.1:8848
+
+dubbo.protocol.name=dubbo
+dubbo.protocol.port=-1
+dubbo.registry.address=nacos://${nacos.host}
diff --git a/sop-index/sop-index-service/src/main/resources/application.properties b/sop-index/sop-index-service/src/main/resources/application.properties
new file mode 100644
index 00000000..b92b78f3
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.profiles.active=dev
+spring.application.name=sop-index
+server.port=8081
diff --git a/sop-index/sop-index-service/src/main/resources/i18n/open/error_en.properties b/sop-index/sop-index-service/src/main/resources/i18n/open/error_en.properties
new file mode 100644
index 00000000..2a928dc5
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/resources/i18n/open/error_en.properties
@@ -0,0 +1,65 @@
+# \u7F51\u5173\u9519\u8BEF\u914D\u7F6E
+
+open.error_10000=Success
+
+# \u683C\u5F0F\uFF1A\u524D\u7F00 + \u7F51\u5173\u9519\u8BEF\u7801 + "_"+ \u5B50\u9519\u8BEF\u7801
+# 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
+open.error_20000_isv.service-busy=service busy
+
+open.error_20001=Insufficient authorization authority
+open.error_20001_aop.invalid-auth-token=Invalid access token
+open.error_20001_aop.auth-token-time-out=The access token has expired
+open.error_20001_aop.invalid-app-auth-token=Invalid application authorization token
+open.error_20001_aop.invalid-app-auth-token-no-api=Merchant does not authorize current interface
+open.error_20001_aop.app-auth-token-time-out=The application authorization token has expired
+open.error_20001_aop.no-product-reg-by-partner=The merchant has not signed any product
+
+open.error_40001=Missing required parameters
+open.error_40001_isv.missing-method=Method name parameter is missing
+open.error_40001_isv.missing-signature=Lack of signature parameter
+open.error_40001_isv.missing-signature-type=Missing signature type parameter
+open.error_40001_isv.missing-signature-key=Lack of signature configuration
+open.error_40001_isv.missing-app-id=Missing appId parameter
+open.error_40001_isv.missing-timestamp=Missing timestamp parameter
+open.error_40001_isv.missing-version=Missing version parameter
+open.error_40001_isv.decryption-error-missing-encrypt-type=Decryption error, no encryption algorithm specified
+
+open.error_40002=Invalid parameter
+open.error_40002_isv.invalid-parameter=Parameter is invalid
+open.error_40002_isv.error-parameter=Parameter incorrect
+open.error_40002_isv.upload-fail=File upload failed
+open.error_40002_isv.invalid-file-extension=Invalid file extension
+open.error_40002_isv.invalid-file-size=Invalid {0} file size, the max size is {1}
+open.error_40002_isv.invalid-method=Nonexistent method name
+open.error_40002_isv.invalid-format=Invalid data format
+open.error_40002_isv.invalid-signature-type=Invalid signature type
+open.error_40002_isv.invalid-signature=Invalid signature
+open.error_40002_isv.invalid-encrypt-type=Invalid encryption type
+open.error_40002_isv.invalid-encrypt=Decryption exception
+open.error_40002_isv.invalid-app-id=Invalid appId parameter
+open.error_40002_isv.invalid-timestamp=Invalid timestamp parameter
+open.error_40002_isv.invalid-charset=Character set error
+open.error_40002_isv.invalid-digest=Digest error
+open.error_40002_isv.decryption-error-not-valid-encrypt-type=Decryption error, unsupported encryption algorithm
+open.error_40002_isv.decryption-error-not-valid-encrypt-key=Decryption error, unconfigured encryption key or encryption key format error
+open.error_40002_isv.decryption-error-unknown=Decryption error, unknown exception
+open.error_40002_isv.missing-signature-config=Signature verification error, no public key or certificate of the corresponding signature algorithm is configured
+open.error_40002_isv.not-support-app-auth=This interface does not support third-party proxy calls
+open.error_40002_isv.suspected-attack=Suspicious attack requests
+open.error_40002_isv.invalid-content-type=Invalid content type
+
+open.error_40004=Business processing failure
+open.error_40004_=Business processing failure
+
+open.error_40006=Insufficient permissions
+open.error_40006_isv.insufficient-isv-permissions=Insufficient ISV permissions
+open.error_40006_isv.insufficient-user-permissions=Insufficient user permissions
+open.error_40006_isv.route-no-permissions=No api permissions
+open.error_40006_isv.access-forbidden=Access forbidden
+open.error_40006_isv.ip-forbidden=IP access forbidden
diff --git a/sop-index/sop-index-service/src/main/resources/i18n/open/error_zh_CN.properties b/sop-index/sop-index-service/src/main/resources/i18n/open/error_zh_CN.properties
new file mode 100644
index 00000000..9578df54
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/resources/i18n/open/error_zh_CN.properties
@@ -0,0 +1,122 @@
+# \u7F51\u5173\u9519\u8BEF\u914D\u7F6E
+
+#open.error_20000=\u670D\u52A1\u4E0D\u53EF\u7528
+#open.error_20000_isp.unknow-error=\u670D\u52A1\u6682\u4E0D\u53EF\u7528
+#open.error_20000_aop.unknow-error=\u670D\u52A1\u6682\u4E0D\u53EF\u7528
+#open.error_20000_isp.service-not-available=\u670D\u52A1\u6682\u4E0D\u53EF\u7528
+#
+#open.error_20001=\u6388\u6743\u6743\u9650\u4E0D\u8DB3
+#open.error_20001_aop.invalid-auth-token=\u65E0\u6548\u7684\u8BBF\u95EE\u4EE4\u724C
+#open.error_20001_aop.auth-token-time-out=\u8BBF\u95EE\u4EE4\u724C\u5DF2\u8FC7\u671F
+#open.error_20001_aop.invalid-app-auth-token=\u65E0\u6548\u7684\u5E94\u7528\u6388\u6743\u4EE4\u724C
+#open.error_20001_aop.invalid-app-auth-token-no-api=\u5546\u6237\u672A\u6388\u6743\u5F53\u524D\u63A5\u53E3
+#open.error_20001_aop.app-auth-token-time-out=\u5E94\u7528\u6388\u6743\u4EE4\u724C\u5DF2\u8FC7\u671F
+#open.error_20001_aop.no-product-reg-by-partner=\u5546\u6237\u672A\u7B7E\u7EA6\u4EFB\u4F55\u4EA7\u54C1
+#
+#open.error_40001=\u7F3A\u5C11\u5FC5\u9009\u53C2\u6570
+#open.error_40001_isv.missing-method=\u7F3A\u5C11\u65B9\u6CD5\u540D\u53C2\u6570
+#open.error_40001_isv.missing-signature=\u7F3A\u5C11\u7B7E\u540D\u53C2\u6570
+#open.error_40001_isv.missing-signature-type=\u7F3A\u5C11\u7B7E\u540D\u7C7B\u578B\u53C2\u6570
+#open.error_40001_isv.missing-signature-key=\u7F3A\u5C11\u7B7E\u540D\u914D\u7F6E
+#open.error_40001_isv.missing-app-id=\u7F3A\u5C11appId\u53C2\u6570
+#open.error_40001_isv.missing-timestamp=\u7F3A\u5C11\u65F6\u95F4\u6233\u53C2\u6570
+#open.error_40001_isv.missing-version=\u7F3A\u5C11\u7248\u672C\u53C2\u6570
+#open.error_40001_isv.decryption-error-missing-encrypt-type=\u89E3\u5BC6\u51FA\u9519, \u672A\u6307\u5B9A\u52A0\u5BC6\u7B97\u6CD5
+#
+#open.error_40002=\u975E\u6CD5\u7684\u53C2\u6570
+#open.error_40002_isv.invalid-parameter=\u53C2\u6570\u65E0\u6548
+#open.error_40002_isv.upload-fail=\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25
+#open.error_40002_isv.invalid-file-extension=\u6587\u4EF6\u6269\u5C55\u540D\u65E0\u6548
+#open.error_40002_isv.invalid-file-size={0}\u6587\u4EF6\u5927\u5C0F\u65E0\u6548\uFF0C\u5355\u6587\u4EF6\u4E0D\u5F97\u8D85\u8FC7{1}
+#open.error_40002_isv.invalid-method=\u4E0D\u5B58\u5728\u7684\u65B9\u6CD5\u540D
+#open.error_40002_isv.invalid-format=\u65E0\u6548\u7684\u6570\u636E\u683C\u5F0F
+#open.error_40002_isv.invalid-signature-type=\u65E0\u6548\u7684\u7B7E\u540D\u7C7B\u578B
+#open.error_40002_isv.invalid-signature=\u65E0\u6548\u7B7E\u540D
+#open.error_40002_isv.invalid-encrypt-type=\u65E0\u6548\u7684\u52A0\u5BC6\u7C7B\u578B
+#open.error_40002_isv.invalid-encrypt=\u89E3\u5BC6\u5F02\u5E38
+#open.error_40002_isv.invalid-app-id=\u65E0\u6548\u7684appId\u53C2\u6570
+#open.error_40002_isv.invalid-timestamp=\u975E\u6CD5\u7684\u65F6\u95F4\u6233\u53C2\u6570
+#open.error_40002_isv.invalid-charset=\u5B57\u7B26\u96C6\u9519\u8BEF
+#open.error_40002_isv.invalid-digest=\u6458\u8981\u9519\u8BEF
+#open.error_40002_isv.decryption-error-not-valid-encrypt-type=\u89E3\u5BC6\u51FA\u9519\uFF0C\u4E0D\u652F\u6301\u7684\u52A0\u5BC6\u7B97\u6CD5
+#open.error_40002_isv.decryption-error-not-valid-encrypt-key=\u89E3\u5BC6\u51FA\u9519, \u672A\u914D\u7F6E\u52A0\u5BC6\u5BC6\u94A5\u6216\u52A0\u5BC6\u5BC6\u94A5\u683C\u5F0F\u9519\u8BEF
+#open.error_40002_isv.decryption-error-unknown=\u89E3\u5BC6\u51FA\u9519\uFF0C\u672A\u77E5\u5F02\u5E38
+#open.error_40002_isv.missing-signature-config=\u9A8C\u7B7E\u51FA\u9519, \u672A\u914D\u7F6E\u5BF9\u5E94\u7B7E\u540D\u7B97\u6CD5\u7684\u516C\u94A5\u6216\u8005\u8BC1\u4E66
+#open.error_40002_isv.not-support-app-auth=\u672C\u63A5\u53E3\u4E0D\u652F\u6301\u7B2C\u4E09\u65B9\u4EE3\u7406\u8C03\u7528
+#open.error_40002_isv.suspected-attack=\u53EF\u7591\u7684\u653B\u51FB\u8BF7\u6C42
+#open.error_40002_isv.invalid-content-type=\u65E0\u6548\u7684content-type
+#
+#open.error_40004=\u4E1A\u52A1\u5904\u7406\u5931\u8D25
+#open.error_40004_=\u4E1A\u52A1\u5904\u7406\u5931\u8D25
+#
+#open.error_40006=\u6743\u9650\u4E0D\u8DB3
+#open.error_40006_isv.insufficient-isv-permissions=\u8BF7\u68C0\u67E5\u914D\u7F6E\u7684\u8D26\u6237\u662F\u5426\u6709\u5F53\u524D\u63A5\u53E3\u6743\u9650
+#open.error_40006_isv.insufficient-user-permissions=\u4EE3\u7406\u7684\u5546\u6237\u6CA1\u6709\u5F53\u524D\u63A5\u53E3\u6743\u9650
+#open.error_40006_isv.route-no-permissions=\u6CA1\u6709\u5F53\u524D\u63A5\u53E3\u6743\u9650
+#open.error_40006_isv.access-forbidden=\u65E0\u6743\u8BBF\u95EE
+
+
+open.error_10000=Success
+
+# \u683C\u5F0F\uFF1A\u524D\u7F00 + \u7F51\u5173\u9519\u8BEF\u7801 + "_"+ \u5B50\u9519\u8BEF\u7801
+# 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
+open.error_20000_isv.service-busy=\u670D\u52A1\u5668\u5FD9
+
+open.error_20001=\u6388\u6743\u6743\u9650\u4E0D\u8DB3
+open.error_20001_aop.invalid-auth-token=\u65E0\u6548\u7684\u8BBF\u95EE\u4EE4\u724C
+open.error_20001_aop.auth-token-time-out=\u8BBF\u95EE\u4EE4\u724C\u5DF2\u8FC7\u671F
+open.error_20001_aop.invalid-app-auth-token=\u65E0\u6548\u7684\u5E94\u7528\u6388\u6743\u4EE4\u724C
+open.error_20001_aop.invalid-app-auth-token-no-api=\u5546\u6237\u672A\u6388\u6743\u5F53\u524D\u63A5\u53E3
+open.error_20001_aop.app-auth-token-time-out=\u5E94\u7528\u6388\u6743\u4EE4\u724C\u5DF2\u8FC7\u671F
+open.error_20001_aop.no-product-reg-by-partner=\u5546\u6237\u672A\u7B7E\u7EA6\u4EFB\u4F55\u4EA7\u54C1
+
+open.error_40001=\u7F3A\u5C11\u5FC5\u9009\u53C2\u6570
+open.error_40001_isv.missing-method=\u7F3A\u5C11\u65B9\u6CD5\u540D\u53C2\u6570
+open.error_40001_isv.missing-signature=\u7F3A\u5C11\u7B7E\u540D\u53C2\u6570
+open.error_40001_isv.missing-signature-type=\u7F3A\u5C11\u7B7E\u540D\u7C7B\u578B\u53C2\u6570
+open.error_40001_isv.missing-signature-key=\u7F3A\u5C11\u7B7E\u540D\u914D\u7F6E
+open.error_40001_isv.missing-app-id=\u7F3A\u5C11appId\u53C2\u6570
+open.error_40001_isv.missing-timestamp=\u7F3A\u5C11\u65F6\u95F4\u6233\u53C2\u6570
+open.error_40001_isv.missing-version=\u7F3A\u5C11\u7248\u672C\u53C2\u6570
+open.error_40001_isv.decryption-error-missing-encrypt-type=\u89E3\u5BC6\u51FA\u9519, \u672A\u6307\u5B9A\u52A0\u5BC6\u7B97\u6CD5
+
+open.error_40002=\u975E\u6CD5\u7684\u53C2\u6570
+open.error_40002_isv.invalid-parameter=\u53C2\u6570\u65E0\u6548
+open.error_40002_isv.error-parameter=\u53c2\u6570\u4e0d\u6b63\u786e
+
+open.error_40002_isv.upload-fail=\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25
+open.error_40002_isv.invalid-file-extension=\u6587\u4EF6\u6269\u5C55\u540D\u65E0\u6548
+open.error_40002_isv.invalid-file-size={0}\u6587\u4EF6\u5927\u5C0F\u65E0\u6548\uFF0C\u5355\u6587\u4EF6\u4E0D\u5F97\u8D85\u8FC7{1}
+open.error_40002_isv.invalid-method=\u4E0D\u5B58\u5728\u7684\u65B9\u6CD5\u540D
+open.error_40002_isv.invalid-format=\u65E0\u6548\u7684\u6570\u636E\u683C\u5F0F
+open.error_40002_isv.invalid-signature-type=\u65E0\u6548\u7684\u7B7E\u540D\u7C7B\u578B
+open.error_40002_isv.invalid-signature=\u65E0\u6548\u7B7E\u540D
+open.error_40002_isv.invalid-encrypt-type=\u65E0\u6548\u7684\u52A0\u5BC6\u7C7B\u578B
+open.error_40002_isv.invalid-encrypt=\u89E3\u5BC6\u5F02\u5E38
+open.error_40002_isv.invalid-app-id=\u65E0\u6548\u7684appId\u53C2\u6570
+open.error_40002_isv.invalid-timestamp=\u975E\u6CD5\u7684\u65F6\u95F4\u6233\u53C2\u6570
+open.error_40002_isv.invalid-charset=\u5B57\u7B26\u96C6\u9519\u8BEF
+open.error_40002_isv.invalid-digest=\u6458\u8981\u9519\u8BEF
+open.error_40002_isv.decryption-error-not-valid-encrypt-type=\u89E3\u5BC6\u51FA\u9519\uFF0C\u4E0D\u652F\u6301\u7684\u52A0\u5BC6\u7B97\u6CD5
+open.error_40002_isv.decryption-error-not-valid-encrypt-key=\u89E3\u5BC6\u51FA\u9519, \u672A\u914D\u7F6E\u52A0\u5BC6\u5BC6\u94A5\u6216\u52A0\u5BC6\u5BC6\u94A5\u683C\u5F0F\u9519\u8BEF
+open.error_40002_isv.decryption-error-unknown=\u89E3\u5BC6\u51FA\u9519\uFF0C\u672A\u77E5\u5F02\u5E38
+open.error_40002_isv.missing-signature-config=\u9A8C\u7B7E\u51FA\u9519, \u672A\u914D\u7F6E\u5BF9\u5E94\u7B7E\u540D\u7B97\u6CD5\u7684\u516C\u94A5\u6216\u8005\u8BC1\u4E66
+open.error_40002_isv.not-support-app-auth=\u672C\u63A5\u53E3\u4E0D\u652F\u6301\u7B2C\u4E09\u65B9\u4EE3\u7406\u8C03\u7528
+open.error_40002_isv.suspected-attack=\u53EF\u7591\u7684\u653B\u51FB\u8BF7\u6C42
+open.error_40002_isv.invalid-content-type=\u65E0\u6548\u7684content-type
+
+open.error_40004=\u4E1A\u52A1\u5904\u7406\u5931\u8D25
+open.error_40004_=\u4E1A\u52A1\u5904\u7406\u5931\u8D25
+
+open.error_40006=\u6743\u9650\u4E0D\u8DB3
+open.error_40006_isv.insufficient-isv-permissions=\u8BF7\u68C0\u67E5\u914D\u7F6E\u7684\u8D26\u6237\u662F\u5426\u6709\u5F53\u524D\u63A5\u53E3\u6743\u9650
+open.error_40006_isv.insufficient-user-permissions=\u4EE3\u7406\u7684\u5546\u6237\u6CA1\u6709\u5F53\u524D\u63A5\u53E3\u6743\u9650
+open.error_40006_isv.route-no-permissions=\u6CA1\u6709\u5F53\u524D\u63A5\u53E3\u6743\u9650
+open.error_40006_isv.access-forbidden=\u65E0\u6743\u8BBF\u95EE
+open.error_40006_isv.ip-forbidden=IP\u65E0\u6743\u8BBF\u95EE
diff --git a/sop-index/sop-index-service/src/main/resources/i18n/readme.md b/sop-index/sop-index-service/src/main/resources/i18n/readme.md
new file mode 100644
index 00000000..08062f2d
--- /dev/null
+++ b/sop-index/sop-index-service/src/main/resources/i18n/readme.md
@@ -0,0 +1 @@
+存放国际化文件
diff --git a/sop-index/src/main/java/com/gitee/sop/index/controller/param/ApiResponse.java b/sop-index/src/main/java/com/gitee/sop/index/controller/param/ApiResponse.java
deleted file mode 100644
index 9b031811..00000000
--- a/sop-index/src/main/java/com/gitee/sop/index/controller/param/ApiResponse.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.gitee.sop.index.controller.param;
-
-import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import lombok.Data;
-
-import java.io.Serializable;
-
-/**
- * 默认的结果封装类.
- *
- *
- * xml返回结果:
- *
- * 50
- * 0
- *
- * msg:网关异常信息
- * sub_code:业务异常码
- * sub_msg:业务异常信息
- *
- * @author tanghc
- */
-@Data
-// 驼峰转下划线
-@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
-public class ApiResponse implements Serializable {
- private static final long serialVersionUID = 6208496044702199437L;
-
- /**
- * 网关异常码,范围0~100 成功返回"0"
- */
- private String code = "0";
-
- /**
- * 网关异常信息
- */
- private String msg;
-
- /**
- * 业务异常码
- */
- private String subCode;
-
- /**
- * 业务异常信息
- */
- private String subMsg;
-
-
-
-}
diff --git a/sop-index/src/main/java/com/gitee/sop/index/service/RouteService.java b/sop-index/src/main/java/com/gitee/sop/index/service/RouteService.java
deleted file mode 100644
index df4ca25b..00000000
--- a/sop-index/src/main/java/com/gitee/sop/index/service/RouteService.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.gitee.sop.index.service;
-
-import com.gitee.sop.index.controller.param.ApiRequest;
-import com.gitee.sop.index.controller.param.ApiResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-/**
- * 接口路由
- *
- * @author 六如
- */
-@Service
-public class RouteService {
-
- @Autowired
- private ValidateService validateService;
-
- public ApiResponse route(ApiRequest apiRequest) {
- // 签名校验
- validateService.validate(apiRequest);
-
- return null;
- }
-
-
-
-}
diff --git a/sop-index/src/main/java/com/gitee/sop/index/service/validate/ApiSigner.java b/sop-index/src/main/java/com/gitee/sop/index/service/validate/ApiSigner.java
deleted file mode 100644
index 5c771411..00000000
--- a/sop-index/src/main/java/com/gitee/sop/index/service/validate/ApiSigner.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.gitee.sop.index.service.validate;
-
-
-import com.gitee.sop.gatewaycommon.message.ErrorEnum;
-import com.gitee.sop.gatewaycommon.param.ApiParam;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * 签名验证实现
- *
- * @author tanghc
- */
-public class ApiSigner extends AbstractSigner {
-
- private Map