diff --git a/src/main/java/quant/rich/emoney/annotation/ResponseDecodeExtension.java b/src/main/java/quant/rich/emoney/annotation/ResponseDecodeExtension.java
index 96547a0..247b9a0 100644
--- a/src/main/java/quant/rich/emoney/annotation/ResponseDecodeExtension.java
+++ b/src/main/java/quant/rich/emoney/annotation/ResponseDecodeExtension.java
@@ -14,11 +14,25 @@ import java.lang.annotation.Target;
*
* 例:
* {@code StrategyAndPoolService#updateByQueryResponse(JsonNode)}
+ * @see quant.rich.emoney.service.RequestResponseInspectService
*/
@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface ResponseDecodeExtension {
+ /**
+ * 指定的 protocolId
+ * @return
+ */
String protocolId();
+ /**
+ * inspect 的排序
+ * @return
+ */
int order() default -1;
+ /**
+ * 是否在模拟客户端请求和返回时启用, 默认 true
+ * @return
+ */
+ boolean client() default true;
}
diff --git a/src/main/java/quant/rich/emoney/client/EmoneyClient.java b/src/main/java/quant/rich/emoney/client/EmoneyClient.java
index ea65575..d39ae6a 100644
--- a/src/main/java/quant/rich/emoney/client/EmoneyClient.java
+++ b/src/main/java/quant/rich/emoney/client/EmoneyClient.java
@@ -22,6 +22,7 @@ import quant.rich.emoney.exception.EmoneyDecodeException;
import quant.rich.emoney.exception.EmoneyIllegalRequestParamException;
import quant.rich.emoney.exception.EmoneyRequestException;
import quant.rich.emoney.exception.EmoneyResponseException;
+import quant.rich.emoney.service.RequestResponseInspectService;
import quant.rich.emoney.service.sqlite.RequestInfoService;
import quant.rich.emoney.util.EncryptUtils;
import quant.rich.emoney.util.SpringContextHolder;
@@ -63,9 +64,11 @@ public class EmoneyClient implements Cloneable {
private static final String RELOGIN_X_PROTOCOL_ID = "user%2Fauth%2FReLogin";
private static volatile RequestInfoService requestInfoService;
+ private static volatile RequestResponseInspectService requestResponseInspectService;
/**
* 根据 protocolId 返回 URL
+ *
益盟操盘手对于不同的 protocolId 有不同的 URL 负责。在进行某类请求之前,请先通过调试 APP 进行确认,否则可能无法获取到相应内容
* @param protocolId
* @return
*/
@@ -87,7 +90,9 @@ public class EmoneyClient implements Cloneable {
}
/**
- * 从 Spring 上下文中获取载入的请求配置
+ * 从 Spring 上下文中获取由 RequestInfoService 管理的默认请求配置
+ * @see RequestInfo
+ * @see RequestInfoService
* @return
*/
private static RequestInfo getDefaultRequestInfo() {
@@ -95,14 +100,32 @@ public class EmoneyClient implements Cloneable {
synchronized (EmoneyClient.class) {
requestInfoService = SpringContextHolder.getBean(RequestInfoService.class);
}
- }
- if (requestInfoService == null) {
- log.warn("获取 RequestInfoService 实例失败");
- return null;
+ if (requestInfoService == null) {
+ log.warn("获取 RequestInfoService 实例失败");
+ return null;
+ }
}
return requestInfoService.getDefaultRequestInfo();
}
+ /**
+ * 从 Spring 上下文中获取 RequestResponseInspectService
+ * @see RequestResponseInspectService
+ * @return
+ */
+ private static RequestResponseInspectService getRequestResponseInspectService() {
+ if (requestResponseInspectService == null) {
+ synchronized (EmoneyClient.class) {
+ requestResponseInspectService = SpringContextHolder.getBean(RequestResponseInspectService.class);
+ }
+ if (requestResponseInspectService == null) {
+ log.warn("获取 RequestResponseInspectService 实例失败");
+ return null;
+ }
+ }
+ return requestResponseInspectService;
+ }
+
private EmoneyClient() {}
/**
@@ -293,7 +316,7 @@ public class EmoneyClient implements Cloneable {
* @param nanoRequest
* @return
*/
- public static BaseResponse.Base_Response post(
+ protected static BaseResponse.Base_Response post(
T nanoRequest,
Serializable xProtocolId,
Serializable xRequestId) {
@@ -373,6 +396,12 @@ public class EmoneyClient implements Cloneable {
U nanoResponse = (U) MessageNano.mergeFrom(
(MessageNano) clazz.getDeclaredConstructor().newInstance(), baseResponse.detail.getValue());
log.debug("执行 emoney 请求成功");
+ try {
+ getRequestResponseInspectService().inspectResponse(xProtocolId.toString(), nanoResponse, true);
+ }
+ catch (Exception e) {
+ log.warn("执行 Inspect response 时发生错误, protocolId={}", xProtocolId, e);
+ }
return nanoResponse;
} catch (Exception e) {
throw new EmoneyDecodeException("试图将返回数据解析成 " + clazz.getSimpleName() + " 时失败", e);
diff --git a/src/main/java/quant/rich/emoney/config/PostgreMybatisConfig.java b/src/main/java/quant/rich/emoney/config/PostgreMybatisConfig.java
index 9511549..b87570e 100644
--- a/src/main/java/quant/rich/emoney/config/PostgreMybatisConfig.java
+++ b/src/main/java/quant/rich/emoney/config/PostgreMybatisConfig.java
@@ -1,13 +1,19 @@
package quant.rich.emoney.config;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.baomidou.mybatisplus.annotation.DbType;
@@ -21,13 +27,28 @@ import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
public class PostgreMybatisConfig {
public static final String POSTGRE_TRANSACTION_MANAGER = "postgreTransactionManager";
-
+
+ @Value("${mybatis-plus.mapper-locations}")
+ private String[] mapperLocations;
+
@Bean("postgreSqlSessionFactory")
public SqlSessionFactory postgreSqlSessionFactory(
@Qualifier("postgreDataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
+
+ List resources = new ArrayList<>();
+ for (String mapperLocation : mapperLocations) {
+ for (Resource resource : new PathMatchingResourcePatternResolver()
+ .getResources(mapperLocation)) {
+ resources.add(resource);
+ }
+ }
+ factory.setMapperLocations(
+ resources.toArray(new Resource[0])
+ );
+
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
diff --git a/src/main/java/quant/rich/emoney/config/SqliteMybatisConfig.java b/src/main/java/quant/rich/emoney/config/SqliteMybatisConfig.java
index b800482..5db8bc2 100644
--- a/src/main/java/quant/rich/emoney/config/SqliteMybatisConfig.java
+++ b/src/main/java/quant/rich/emoney/config/SqliteMybatisConfig.java
@@ -4,15 +4,21 @@ import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.baomidou.mybatisplus.annotation.DbType;
@@ -33,6 +39,10 @@ public class SqliteMybatisConfig {
private static final String RESOURCE_PATH = "database.db";
public static final String SQLITE_TRANSACTION_MANAGER = "sqliteTransactionManager";
+
+
+ @Value("${mybatis-plus.mapper-locations}")
+ private String[] mapperLocations;
/**
* 配置数据库连接
@@ -106,6 +116,17 @@ public class SqliteMybatisConfig {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
+
+
+ List resources = new ArrayList<>();
+ for (String mapperLocation : mapperLocations) {
+ for (Resource resource : new PathMatchingResourcePatternResolver().getResources(mapperLocation)) {
+ resources.add(resource);
+ }
+ }
+ factory.setMapperLocations(
+ resources.toArray(new Resource[0])
+ );
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.SQLITE));
diff --git a/src/main/java/quant/rich/emoney/controller/api/CommonAbilityControllerV1.java b/src/main/java/quant/rich/emoney/controller/api/CommonAbilityControllerV1.java
index 0d86014..6c55d5a 100644
--- a/src/main/java/quant/rich/emoney/controller/api/CommonAbilityControllerV1.java
+++ b/src/main/java/quant/rich/emoney/controller/api/CommonAbilityControllerV1.java
@@ -1,18 +1,27 @@
package quant.rich.emoney.controller.api;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
import org.reflections.Reflections;
import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.interfaces.IQueryableEnum;
+import quant.rich.emoney.service.postgre.StockStrategyService;
@RestController
@RequestMapping("/api/v1/common")
@@ -22,6 +31,20 @@ public class CommonAbilityControllerV1 {
@Autowired
Reflections reflections;
+ @Autowired
+ ObjectMapper objectMapper;
+
+ @Autowired
+ StockStrategyService stockStrategyService;
+
+ @GetMapping("/test")
+ void test() throws IOException, InterruptedException, ExecutionException {
+ String str = Files.readString(Path.of("C:\\Users\\Administrator\\Desktop\\stock_strategy.json"));
+ JsonNode node = objectMapper.readTree(str);
+ Future future = stockStrategyService.updateByQueryResponseAsync(node);
+ future.get();
+ }
+
@GetMapping("/getIQueryableEnum")
public Map getIQueryableEnum(String enumName) {
Set> enums = reflections.getSubTypesOf(IQueryableEnum.class);
diff --git a/src/main/java/quant/rich/emoney/controller/api/ProtoDecodeControllerV1.java b/src/main/java/quant/rich/emoney/controller/api/ProtoDecodeControllerV1.java
index bfec8f9..53abb36 100644
--- a/src/main/java/quant/rich/emoney/controller/api/ProtoDecodeControllerV1.java
+++ b/src/main/java/quant/rich/emoney/controller/api/ProtoDecodeControllerV1.java
@@ -1,16 +1,7 @@
package quant.rich.emoney.controller.api;
import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import java.util.Objects;
-import java.util.Set;
-
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.PostMapping;
@@ -22,23 +13,15 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.nano.MessageNano;
-import jakarta.annotation.PostConstruct;
-
import org.apache.commons.lang3.StringUtils;
-import org.reflections.Reflections;
-
-import lombok.Data;
-import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import nano.BaseResponse.Base_Response;
-import quant.rich.emoney.annotation.ResponseDecodeExtension;
import quant.rich.emoney.entity.sqlite.ProtocolMatch;
import quant.rich.emoney.exception.RException;
import quant.rich.emoney.pojo.dto.EmoneyConvertResult;
import quant.rich.emoney.pojo.dto.EmoneyProtobufBody;
+import quant.rich.emoney.service.RequestResponseInspectService;
import quant.rich.emoney.service.sqlite.ProtocolMatchService;
-import quant.rich.emoney.util.SpringBeanDetector;
-import quant.rich.emoney.util.SpringContextHolder;
/**
* 益盟 ProtocolBuf 报文解析 API 控制器
@@ -52,66 +35,10 @@ public class ProtoDecodeControllerV1 {
ProtocolMatchService protocolMatchService;
@Autowired
- Reflections reflections;
+ RequestResponseInspectService requestResponseInspectService;
- Map> responseDecodeExtensions = new HashMap>();
-
- @Data
- @RequiredArgsConstructor
- private static class MethodInfo {
- final Method method;
- final Class> declaringClass;
- final Integer order;
- Object instance;
- }
-
- @PostConstruct
- void postConstruct() {
- // Reflections 扫描所有注解并根据 protocolId 和 order 排序
- Set methods = reflections.getMethodsAnnotatedWith(ResponseDecodeExtension.class);
- for (Method m : methods) {
- MethodInfo info;
- ResponseDecodeExtension ex = m.getAnnotation(ResponseDecodeExtension.class);
- String protocolId = ex.protocolId();
- Integer order = ex.order();
-
- // 判断 method 是否为单参数接受 JsonNode 的方法
- Class>[] parameterTypes = m.getParameterTypes();
- Class> declaringClass = m.getDeclaringClass();
- if (parameterTypes.length != 1 || parameterTypes[0] != JsonNode.class) {
- log.warn("方法 {}#{} 不为类型为 JsonNode 的单参数方法,暂不支持作为解码额外选项",
- declaringClass.getSimpleName(), m.getName(), declaringClass.getSimpleName());
- continue;
- }
-
- // 判断 method 是否是静态
- if (Modifier.isStatic(m.getModifiers())) {
- info = new MethodInfo(m, null, order);
- }
- else {
- if (!SpringBeanDetector.isSpringManagedClass(declaringClass)) {
- log.warn("方法 {} 所属类 {} 不归属于 Spring 管理,目前暂不支持作为解码额外选项",
- m.getName(), declaringClass.getSimpleName());
- continue;
- }
- info = new MethodInfo(m, declaringClass, order);
- }
- List list = responseDecodeExtensions.get(protocolId);
- if (list == null) {
- list = new ArrayList<>();
- list.add(info);
- responseDecodeExtensions.put(protocolId, list);
- }
- else {
- list.add(info);
- }
- }
- for (List list : responseDecodeExtensions.values()) {
- list.sort(Comparator.comparingInt(info -> info.getOrder()));
- }
- log.debug("ResponseDecodeExtension: 共载入 {} 个 ProtocolID 的 {} 个方法",
- responseDecodeExtensions.keySet().size(), responseDecodeExtensions.values().size());
- }
+ @Autowired
+ ObjectMapper objectMapper;
/**
* 解析 emoney protobuf 的请求
@@ -174,7 +101,7 @@ public class ProtoDecodeControllerV1 {
U nano = (U)MessageNano.mergeFrom((MessageNano)
clazz.getDeclaredConstructor().newInstance(), buf);
return EmoneyConvertResult
- .ok(new ObjectMapper().valueToTree(nano))
+ .ok(objectMapper.valueToTree(nano))
.setProtocolId(protocolId)
.setSupposedClassName(className);
}
@@ -269,27 +196,13 @@ public class ProtoDecodeControllerV1 {
(MessageNano)clazz.getDeclaredConstructor().newInstance(),
baseResponse.detail.getValue());
- JsonNode jo = new ObjectMapper().valueToTree(nano);
+ JsonNode jo = objectMapper.valueToTree(nano);
- // 查找 ResponseDecodeExtension
- List methodInfos = responseDecodeExtensions.get(protocolId.toString());
- if (methodInfos != null) {
- for (MethodInfo methodInfo : methodInfos) {
- if (methodInfo.getInstance() != null) {
- // instance 不为 null 则说明是已经取到的 spring bean, 直接调用
- methodInfo.getMethod().invoke(methodInfo.getInstance(), jo);
- }
- else if (methodInfo.getDeclaringClass() != null) {
- // 获取 spring 管理的实例类
- Object instance = SpringContextHolder.getBean(methodInfo.getDeclaringClass());
- methodInfo.getMethod().invoke(instance, jo);
- methodInfo.setInstance(instance);
- }
- else {
- // 静态方法直接 invoke
- methodInfo.getMethod().invoke(null, jo);
- }
- }
+ try {
+ requestResponseInspectService.inspectResponse(protocolId.toString(), nano, false);
+ }
+ catch (Exception e) {
+ log.warn("执行 Inspect response 时发生错误, protocolId={}", protocolId, e);
}
return EmoneyConvertResult
diff --git a/src/main/java/quant/rich/emoney/entity/postgre/StockStrategy.java b/src/main/java/quant/rich/emoney/entity/postgre/StockStrategy.java
index ea9d0cf..f01acbb 100644
--- a/src/main/java/quant/rich/emoney/entity/postgre/StockStrategy.java
+++ b/src/main/java/quant/rich/emoney/entity/postgre/StockStrategy.java
@@ -2,6 +2,8 @@ package quant.rich.emoney.entity.postgre;
import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableName;
+
import lombok.Data;
import lombok.experimental.Accessors;
@@ -10,47 +12,21 @@ import lombok.experimental.Accessors;
*/
@Data
@Accessors(chain=true)
+@TableName("stock_strategy")
public class StockStrategy {
- private String tsCode;
+ private Integer goodsId ;
private LocalDateTime date;
- private String strategyName;
-
- private Integer strategyId;
+ private Integer poolId;
private String poolName;
+ private Integer strategyId;
+
+ private String strategyName;
+
private String type;
-
- private Integer poolId;
-
- public StockStrategy setTsCodeFromGoodsId(Integer goodsId) {
- // 自动将益盟 goodsId 转换成 tsCode
- // 1301325 -> 301325.SZ
- // 600325 -> 600325.SH
- // 1920009 -> 920009.BJ
- String goodsIdStr = goodsId.toString();
- RuntimeException e = new RuntimeException("无法将 goodsId " + goodsIdStr + " 转换为 tsCode");
- if (goodsIdStr.length() == 6) {
- // SH
- return setTsCode(goodsIdStr + ".SH");
- }
- else if (goodsIdStr.length() == 7) {
- if (goodsIdStr.charAt(0) != '1') {
- throw e;
- }
- if (goodsIdStr.charAt(1) == '9') {
- // BJ
- return setTsCode(goodsIdStr.substring(1) + ".BJ");
- }
- // SZ
- return setTsCode(goodsIdStr.substring(1) + ".SZ");
- }
- throw e;
- }
-
-
}
diff --git a/src/main/java/quant/rich/emoney/entity/sqlite/Plan.java b/src/main/java/quant/rich/emoney/entity/sqlite/Plan.java
index 4abc622..32e6979 100644
--- a/src/main/java/quant/rich/emoney/entity/sqlite/Plan.java
+++ b/src/main/java/quant/rich/emoney/entity/sqlite/Plan.java
@@ -20,6 +20,15 @@ import lombok.experimental.Accessors;
import quant.rich.emoney.mybatis.typehandler.CommaListTypeHandler;
import quant.rich.emoney.mybatis.typehandler.JsonStringTypeHandler;
+/**
+ * 目前能想到的计划任务有三种
+ *
+ * - 指标的抓取
+ *
- 个股策略(/strategy, id=9400)的抓取
+ *
- 选股策略的抓取
+ *
+ * 未来可能存在更多的计划任务, 所以需要考虑如何设计才能更好地兼容后续添加的任务类型
+ */
@Data
@Accessors(chain = true)
@TableName(value = "plan", autoResultMap = true)
diff --git a/src/main/java/quant/rich/emoney/entity/sqlite/RequestInfo.java b/src/main/java/quant/rich/emoney/entity/sqlite/RequestInfo.java
index c479c84..7da1d92 100644
--- a/src/main/java/quant/rich/emoney/entity/sqlite/RequestInfo.java
+++ b/src/main/java/quant/rich/emoney/entity/sqlite/RequestInfo.java
@@ -451,6 +451,11 @@ public class RequestInfo extends Model {
return node;
}
+ /**
+ * 当前请求配置是否是匿名配置
+ * 当用户名和密码任一为 blank 时视为匿名
+ * @return
+ */
public boolean isAnonymous() {
return StringUtils.isAnyBlank(getUsername(), getPassword());
}
diff --git a/src/main/java/quant/rich/emoney/mapper/postgre/StockStrategyMapper.java b/src/main/java/quant/rich/emoney/mapper/postgre/StockStrategyMapper.java
index b1a7ce4..9f67228 100644
--- a/src/main/java/quant/rich/emoney/mapper/postgre/StockStrategyMapper.java
+++ b/src/main/java/quant/rich/emoney/mapper/postgre/StockStrategyMapper.java
@@ -1,12 +1,13 @@
package quant.rich.emoney.mapper.postgre;
+import java.util.Collection;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import quant.rich.emoney.entity.postgre.EmoneyIndex;
import quant.rich.emoney.entity.postgre.StockStrategy;
@Component
@@ -14,4 +15,8 @@ import quant.rich.emoney.entity.postgre.StockStrategy;
@DS("postgre")
public interface StockStrategyMapper extends BaseMapper {
+ int insertOrUpdateBatch(
+ @Param("list") Collection list,
+ @Param("batchSize") int batchSize
+ );
}
diff --git a/src/main/java/quant/rich/emoney/service/RequestResponseInspectService.java b/src/main/java/quant/rich/emoney/service/RequestResponseInspectService.java
new file mode 100644
index 0000000..1968eb9
--- /dev/null
+++ b/src/main/java/quant/rich/emoney/service/RequestResponseInspectService.java
@@ -0,0 +1,158 @@
+package quant.rich.emoney.service;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.reflections.Reflections;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.protobuf.nano.MessageNano;
+
+import jakarta.annotation.PostConstruct;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import quant.rich.emoney.annotation.ResponseDecodeExtension;
+import quant.rich.emoney.util.SpringBeanDetector;
+import quant.rich.emoney.util.SpringContextHolder;
+
+/**
+ * 负责对请求和返回进行拦截和进一步处理
+ * @see ResponseDecodeExtension
+ * @see quant.rich.emoney.client.EmoneyClient
+ * @see quant.rich.emoney.controller.api.ProtoDecodeController
+ */
+@Service
+@Slf4j
+public class RequestResponseInspectService {
+
+ @Autowired
+ Reflections reflections;
+
+ @Autowired
+ ObjectMapper objectMapper;
+
+ Map> responseDecodeExtensions = new HashMap>();
+
+ @Data
+ @RequiredArgsConstructor
+ private static class MethodInfo {
+ /**
+ * 对应的 Inspect 方法
+ */
+ final Method method;
+ /**
+ * 声明了 Inspect 方法的类
+ */
+ final Class> declaringClass;
+ /**
+ * Inspect 顺序
+ */
+ final Integer order;
+ /**
+ * 声明了 Inspect 方法的类的实例。当方法是成员方法且实例受 Spring 管理时,通过实例调用
+ */
+ Object instance;
+ /**
+ * 是否在模拟客户端中启用。该参数从注解处填充
+ */
+ boolean isClient = true;
+
+ }
+
+ @PostConstruct
+ void postConstruct() {
+ // Reflections 扫描所有注解并根据 protocolId 和 order 排序
+ Set methods = reflections.getMethodsAnnotatedWith(ResponseDecodeExtension.class);
+ for (Method m : methods) {
+ MethodInfo info;
+ ResponseDecodeExtension ex = m.getAnnotation(ResponseDecodeExtension.class);
+ String protocolId = ex.protocolId();
+ Integer order = ex.order();
+
+ // 判断 method 是否为单参数接受 JsonNode 的方法
+ Class>[] parameterTypes = m.getParameterTypes();
+ Class> declaringClass = m.getDeclaringClass();
+ if (parameterTypes.length != 1 || parameterTypes[0] != JsonNode.class) {
+ log.warn("方法 {}#{} 不为类型为 JsonNode 的单参数方法,暂不支持作为解码额外选项",
+ declaringClass.getSimpleName(), m.getName(), declaringClass.getSimpleName());
+ continue;
+ }
+
+ // 判断 method 是否是静态
+ if (Modifier.isStatic(m.getModifiers())) {
+ info = new MethodInfo(m, null, order);
+ }
+ else {
+ if (!SpringBeanDetector.isSpringManagedClass(declaringClass)) {
+ log.warn("方法 {} 所属类 {} 不归属于 Spring 管理,目前暂不支持作为解码额外选项",
+ m.getName(), declaringClass.getSimpleName());
+ continue;
+ }
+ info = new MethodInfo(m, declaringClass, order);
+ }
+ info.setClient(ex.client());
+ List list = responseDecodeExtensions.get(protocolId);
+ if (list == null) {
+ list = new ArrayList<>();
+ list.add(info);
+ responseDecodeExtensions.put(protocolId, list);
+ }
+ else {
+ list.add(info);
+ }
+ }
+ for (List list : responseDecodeExtensions.values()) {
+ list.sort(Comparator.comparingInt(info -> info.getOrder()));
+ }
+ log.debug("RequestResponseInspectService: 共载入 {} 个 ProtocolID 的 {} 个方法",
+ responseDecodeExtensions.keySet().size(), responseDecodeExtensions.values().size());
+ }
+
+ /**
+ * 对 Response 进行 inspect
+ * @param protocolId
+ * @param nano
+ * @param fromClient 该 inspect 来源是否是 client.
+ * @return
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ */
+ public void inspectResponse(String protocolId, U nano, boolean fromClient) throws IllegalAccessException, InvocationTargetException {
+ // 查找 ResponseDecodeExtension
+ List methodInfos = responseDecodeExtensions.get(protocolId.toString());
+ JsonNode jo = objectMapper.valueToTree(nano);
+ if (methodInfos != null) {
+ for (MethodInfo methodInfo : methodInfos) {
+ if (fromClient && !methodInfo.isClient()) {
+ // 来自客户端请求但该方法未开启客户端 inspect, 忽略
+ continue;
+ }
+ if (methodInfo.getInstance() != null) {
+ // instance 不为 null 则说明是已经取到的 spring bean, 直接调用
+ methodInfo.getMethod().invoke(methodInfo.getInstance(), jo);
+ }
+ else if (methodInfo.getDeclaringClass() != null) {
+ // 获取 spring 管理的实例类
+ Object instance = SpringContextHolder.getBean(methodInfo.getDeclaringClass());
+ methodInfo.setInstance(instance);
+ methodInfo.getMethod().invoke(instance, jo);
+ }
+ else {
+ // 静态方法直接 invoke
+ methodInfo.getMethod().invoke(null, jo);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/quant/rich/emoney/service/postgre/StockStrategyService.java b/src/main/java/quant/rich/emoney/service/postgre/StockStrategyService.java
index 2ac79e1..8294a57 100644
--- a/src/main/java/quant/rich/emoney/service/postgre/StockStrategyService.java
+++ b/src/main/java/quant/rich/emoney/service/postgre/StockStrategyService.java
@@ -1,15 +1,106 @@
package quant.rich.emoney.service.postgre;
-import org.springframework.stereotype.Service;
-import com.baomidou.dynamic.datasource.annotation.DS;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+
+import lombok.extern.slf4j.Slf4j;
+import quant.rich.emoney.annotation.ResponseDecodeExtension;
+import quant.rich.emoney.config.PostgreMybatisConfig;
import quant.rich.emoney.entity.postgre.StockStrategy;
import quant.rich.emoney.mapper.postgre.StockStrategyMapper;
+import quant.rich.emoney.util.DateUtils;
@DS("postgre")
@Service
+@Slf4j
public class StockStrategyService extends PostgreServiceImpl {
+ /**
+ * 从请求响应的 JsonNode 转换出个股日策略标记信息列表
+ * @param jsonNode
+ * @return
+ */
+ public List parseJsonToList(JsonNode jsonNode) {
+
+ if (jsonNode == null) {
+ log.warn("试图获取 StockStrategy list, 但提供的响应 json 为空");
+ return List.of();
+ }
+
+ JsonNode goodsIdNode = jsonNode.at("/data/input/goodsId");
+ if (goodsIdNode.isMissingNode() || !goodsIdNode.isInt()) {
+ log.warn("试图获取 StockStrategy list, 但 goodsId node 缺失或不为 integer");
+ return List.of();
+ }
+
+ Integer goodsId = goodsIdNode.asInt();
+ log.debug("StockStrategy json with goodsId: {}", goodsId);
+
+ JsonNode output = jsonNode.at("/data/output");
+ if (output.getNodeType() != JsonNodeType.ARRAY) {
+ log.warn("试图获取 StockStrategy list, 但提供的响应 json.data.output 为 null 或不为 ARRAY");
+ return List.of();
+ }
+
+ List stockStrategies = new ArrayList<>();
+ String[] types = new String[] {"band", "tech", "val"}; // 波段/技术/基本面(价值)
+ for (JsonNode node : output) {
+ JsonNode dateNode = node.get("date");
+ if (dateNode == null) {
+ log.warn("试图获取 StockStrategy node, 但缺失日期 date 节点");
+ continue;
+ }
+ LocalDateTime date = DateUtils.parse(String.valueOf(dateNode.asInt()), "yyyyMMdd").atStartOfDay();
+ for (String type : types) {
+ JsonNode strategies = node.get(type);
+ if (strategies != null && strategies.getNodeType() == JsonNodeType.ARRAY) {
+ for (JsonNode simpleStrategy : strategies) {
+ StockStrategy stockStrategy = new StockStrategy();
+ stockStrategy.setGoodsId(goodsId);
+ stockStrategy.setDate(date);
+ stockStrategy.setStrategyName(simpleStrategy.get("strategyName").asText());
+ stockStrategy.setStrategyId(simpleStrategy.get("strategyId").asInt());
+ stockStrategy.setPoolName(simpleStrategy.get("poolName").asText());
+ stockStrategy.setPoolId(simpleStrategy.get("poolId").asInt());
+ stockStrategy.setType(type);
+ stockStrategies.add(stockStrategy);
+ }
+ }
+ }
+ }
+ log.debug("共载入 {} 条 StockStrategy 数据", stockStrategies.size());
+ return stockStrategies;
+ }
+ /**
+ * 从 jsonNode 节点直接更新到数据库内
+ * @param jsonNode
+ * @return
+ */
+ @ResponseDecodeExtension(protocolId="9400")
+ @Async
+ public Future updateByQueryResponseAsync(JsonNode jsonNode) {
+ List stockStrategies = parseJsonToList(jsonNode);
+ return CompletableFuture.completedFuture(saveOrUpdateBatch(stockStrategies));
+ }
+
+ @Override
+ @Transactional(transactionManager = PostgreMybatisConfig.POSTGRE_TRANSACTION_MANAGER, rollbackFor = Exception.class)
+ public boolean saveOrUpdateBatch(Collection entityList, int batchSize) {
+ return SqlHelper.retBool(baseMapper.insertOrUpdateBatch(entityList, batchSize));
+ }
}
diff --git a/src/main/java/quant/rich/emoney/service/sqlite/StrategyAndPoolService.java b/src/main/java/quant/rich/emoney/service/sqlite/StrategyAndPoolService.java
index cab34cc..5812028 100644
--- a/src/main/java/quant/rich/emoney/service/sqlite/StrategyAndPoolService.java
+++ b/src/main/java/quant/rich/emoney/service/sqlite/StrategyAndPoolService.java
@@ -4,6 +4,8 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.baomidou.dynamic.datasource.annotation.DS;
@@ -24,7 +26,8 @@ import quant.rich.emoney.mapper.sqlite.StrategyAndPoolMapper;
@Slf4j
public class StrategyAndPoolService extends SqliteServiceImpl {
- static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ @Autowired
+ ObjectMapper objectMapper;
/**
* 从数据库中导入所有已记录的策略和池,形成可供益盟 Fiddler 插件使用的 prepared_strategies.json
@@ -35,7 +38,7 @@ public class StrategyAndPoolService extends SqliteServiceImpl set = new HashSet<>();
- String[] types = new String[] {"band", "tech", "val"}; // 波段/技术/基本面
+ String[] types = new String[] {"band", "tech", "val"}; // 波段/技术/基本面(价值)
for (JsonNode node : output) {
for (String type : types) {
JsonNode strategies = node.get(type);
diff --git a/src/main/java/quant/rich/emoney/util/DateUtils.java b/src/main/java/quant/rich/emoney/util/DateUtils.java
new file mode 100644
index 0000000..9380e52
--- /dev/null
+++ b/src/main/java/quant/rich/emoney/util/DateUtils.java
@@ -0,0 +1,58 @@
+package quant.rich.emoney.util;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public final class DateUtils {
+
+ // 缓存 formatter,行为接近 fastjson2
+ private static final Map FORMATTER_CACHE =
+ new ConcurrentHashMap<>();
+
+ private DateUtils() {
+ }
+
+ /**
+ * 格式化 LocalDateTime
+ *
+ * @param dateTime LocalDateTime
+ * @param pattern 日期格式,如 yyyy-MM-dd HH:mm:ss
+ * @return 格式化后的字符串
+ */
+ public static String format(LocalDateTime dateTime, String pattern) {
+ if (dateTime == null) {
+ return null;
+ }
+ if (pattern == null || pattern.isEmpty()) {
+ throw new IllegalArgumentException("pattern must not be null or empty");
+ }
+
+ DateTimeFormatter formatter =
+ FORMATTER_CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
+
+ return dateTime.format(formatter);
+ }
+
+ /**
+ * 将给定字符串转换成 LocalDate
+ * @param value 如 "20260101"
+ * @param pattern 日期格式,如 yyyyMMdd
+ * @return
+ */
+ public static LocalDate parse(String value, String pattern) {
+ if (value == null) {
+ return null;
+ }
+ if (pattern == null || pattern.isEmpty()) {
+ throw new IllegalArgumentException("pattern must not be null or empty");
+ }
+ DateTimeFormatter formatter =
+ FORMATTER_CACHE.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
+
+ LocalDate date = LocalDate.parse(value, formatter);
+ return date;
+ }
+}
diff --git a/src/main/java/quant/rich/emoney/util/StockCodeUtils.java b/src/main/java/quant/rich/emoney/util/StockCodeUtils.java
new file mode 100644
index 0000000..89967aa
--- /dev/null
+++ b/src/main/java/quant/rich/emoney/util/StockCodeUtils.java
@@ -0,0 +1,90 @@
+package quant.rich.emoney.util;
+
+public class StockCodeUtils {
+
+ /**
+ * 从 goodsId 转换为 tsCode
+ * @param goodsId
+ * @return
+ */
+ public static String goodsIdToTsCode(Integer goodsId) {
+ if (goodsId == null || goodsId < 0) {
+ throw new IllegalArgumentException("goodsId 不能为空或为负数");
+ }
+
+ final String s = goodsId.toString();
+ final int len = s.length();
+
+ switch (len) {
+ case 6:
+ // 6 位默认 SH
+ return s + ".SH";
+
+ case 7:
+ // 7 位默认 SZ 或 BJ
+ if (!s.startsWith("1")) {
+ throw new IllegalArgumentException("无法将 goodsId " + s + " 转换为 tsCode");
+ }
+
+ char second = s.charAt(1);
+ String core = s.substring(1);
+
+ if (second == '9') {
+ return core + ".BJ";
+ }
+ return core + ".SZ";
+
+ default:
+ throw new IllegalArgumentException("无法将 goodsId " + s + " 转换为 tsCode");
+ }
+ }
+
+ /**
+ * 从 tsCode 转换成 goodsId
+ * @param tsCode
+ * @return
+ */
+ public static Integer tsCodeToGoodsId(String tsCode) {
+ if (tsCode == null || tsCode.isBlank()) {
+ throw new IllegalArgumentException("tsCode 不能为空");
+ }
+
+ String s = tsCode.trim().toUpperCase();
+
+ // 期望格式:XXX.SZ / XXX.SH / XXX.BJ
+ int dot = s.indexOf('.');
+ if (dot <= 0 || dot == s.length() - 1) {
+ throw new IllegalArgumentException("tsCode 格式无效: " + tsCode);
+ }
+
+ String code = s.substring(0, dot);
+ String market = s.substring(dot + 1);
+
+ if (!code.matches("\\d+")) {
+ throw new IllegalArgumentException("tsCode 数字部分无效: " + tsCode);
+ }
+
+ switch (market) {
+ case "SH":
+ if (code.length() == 6) {
+ return Integer.valueOf(code);
+ }
+ break;
+
+ case "SZ":
+ if (code.length() == 6) {
+ return Integer.valueOf("1" + code);
+ }
+ break;
+
+ case "BJ":
+ if (code.length() == 6) {
+ return Integer.valueOf("1" + code);
+ }
+ break;
+ }
+
+ throw new IllegalArgumentException("无法将 tsCode " + tsCode + " 转换为 goodsId");
+ }
+
+}
diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml
index 13553e9..d8e92bc 100644
--- a/src/main/resources/application-local.yml
+++ b/src/main/resources/application-local.yml
@@ -1,6 +1,6 @@
spring:
datasource:
- url: jdbc:postgresql://localhost:5432/verich
+ url: jdbc:postgresql://localhost:5432/emoney
username: postgres
password: 123456
driver-class-name: org.postgresql.Driver
diff --git a/src/main/resources/application-remote.yml b/src/main/resources/application-remote.yml
index aa16fff..4427ae8 100644
--- a/src/main/resources/application-remote.yml
+++ b/src/main/resources/application-remote.yml
@@ -2,7 +2,7 @@ spring:
cache.type: simple
datasource:
postgre:
- jdbc-url: jdbc:postgresql://localhost:5432/verich
+ jdbc-url: jdbc:postgresql://localhost:5432/emoney
username: postgres
password: 123456
driver-class-name: org.postgresql.Driver
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index c2d7885..8d88f91 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -40,9 +40,7 @@ mybatis-plus-join.banner: false
mybatis-plus:
global-config:
banner: false
- mapper-locations:
- - classpath*:mapper/postgre/*.xml
- - classpath*:mapper/sqlite/*.xml
+ mapper-locations: classpath*:mapper/postgre/*.xml,classpath*:mapper/sqlite/*.xml
type-aliases-package:
- quant.rich.emoney.entity.postgre
- quant.rich.emoney.entity.sqlite
diff --git a/src/main/resources/database.db b/src/main/resources/database.db
index 39e181c..303b6a6 100644
Binary files a/src/main/resources/database.db and b/src/main/resources/database.db differ
diff --git a/src/main/resources/mapper/postgre/StockStrategy.xml b/src/main/resources/mapper/postgre/StockStrategy.xml
new file mode 100644
index 0000000..86a1979
--- /dev/null
+++ b/src/main/resources/mapper/postgre/StockStrategy.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+ INSERT INTO stock_strategy
+ (goods_id, date, pool_id, pool_name, strategy_id, strategy_name, type)
+ VALUES
+
+
+ (#{item.goodsId},
+ #{item.date},
+ #{item.poolId},
+ #{item.poolName},
+ #{item.strategyId},
+ #{item.strategyName},
+ #{item.type})
+
+
+ ON CONFLICT (goods_id, date, pool_id)
+ DO UPDATE SET
+ pool_name = EXCLUDED.pool_name,
+ strategy_id = EXCLUDED.strategy_id,
+ strategy_name = EXCLUDED.strategy_name,
+ type = EXCLUDED.type
+
+
+
+
+
diff --git a/src/test/java/quant/rich/EmoneyAutoApplicationTests.java b/src/test/java/quant/rich/EmoneyAutoApplicationTests.java
index 65d64b4..55fabde 100644
--- a/src/test/java/quant/rich/EmoneyAutoApplicationTests.java
+++ b/src/test/java/quant/rich/EmoneyAutoApplicationTests.java
@@ -2,7 +2,6 @@ package quant.rich;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -14,7 +13,6 @@ import lombok.extern.slf4j.Slf4j;
import nano.CandleStickNewWithIndexExResponse.CandleStickNewWithIndexEx_Response;
import nano.CandleStickRequest.CandleStick_Request;
import nano.CandleStickWithIndexRequest.CandleStickWithIndex_Request;
-import nano.CandleStickWithIndexRequest.CandleStickWithIndex_Request.IndexInfo;
import quant.rich.emoney.EmoneyAutoApplication;
import quant.rich.emoney.client.EmoneyClient;
diff --git a/src/test/java/quant/rich/emoney/EmoneyStrategyMarkTests.java b/src/test/java/quant/rich/emoney/EmoneyStrategyMarkTests.java
index c6746b6..08510c5 100644
--- a/src/test/java/quant/rich/emoney/EmoneyStrategyMarkTests.java
+++ b/src/test/java/quant/rich/emoney/EmoneyStrategyMarkTests.java
@@ -14,7 +14,9 @@ import nano.StrategyMarkRequest.StrategyMark_Request;
import nano.StrategyMarkResponse.StrategyMark_Response;
import quant.rich.emoney.client.EmoneyClient;
-
+/**
+ * 测试获取策略标记数据。可以用这个做一个 MVP,
+ */
@SpringBootTest
@ContextConfiguration(classes = EmoneyAutoApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
diff --git a/src/test/java/quant/rich/emoney/StockStrategyJsonParseAndUpdateLocalTest.java b/src/test/java/quant/rich/emoney/StockStrategyJsonParseAndUpdateLocalTest.java
new file mode 100644
index 0000000..94f0e3f
--- /dev/null
+++ b/src/test/java/quant/rich/emoney/StockStrategyJsonParseAndUpdateLocalTest.java
@@ -0,0 +1,44 @@
+package quant.rich.emoney;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import lombok.extern.slf4j.Slf4j;
+import quant.rich.emoney.service.postgre.StockStrategyService;
+
+/**
+ * 测试从本地读取包含 stock strategy 的 json, 转换为列表并更新到数据库中
+ */
+@SpringBootTest
+@ContextConfiguration(classes = EmoneyAutoApplication.class)
+@RunWith(SpringJUnit4ClassRunner.class)
+@Slf4j
+public class StockStrategyJsonParseAndUpdateLocalTest {
+
+ @Autowired
+ ObjectMapper objectMapper;
+
+ @Autowired
+ StockStrategyService stockStrategyService;
+
+ @Test
+ void test() throws IOException, InterruptedException, ExecutionException {
+ String str = Files.readString(Path.of("C:\\Users\\Administrator\\Desktop\\stock_strategy.json"));
+ JsonNode node = objectMapper.readTree(str);
+ Future future = stockStrategyService.updateByQueryResponseAsync(node);
+ future.get();
+ }
+}
diff --git a/src/test/java/quant/rich/emoney/TushareDataServiceClientTest.java b/src/test/java/quant/rich/emoney/TushareDataServiceClientTest.java
index 0a3b2b5..c75d145 100644
--- a/src/test/java/quant/rich/emoney/TushareDataServiceClientTest.java
+++ b/src/test/java/quant/rich/emoney/TushareDataServiceClientTest.java
@@ -13,6 +13,10 @@ import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.tushare.StockInfo;
import quant.rich.emoney.tushare.TushareDataServiceClient;
+/**
+ * 测试通过 Feign 从 tushare-data-service 获取数据
+ * @see TushareDataServiceClient
+ */
@SpringBootTest
@ContextConfiguration(classes = EmoneyAutoApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
diff --git a/src/test/resources/application-local.yml b/src/test/resources/application-local.yml
deleted file mode 100644
index 13553e9..0000000
--- a/src/test/resources/application-local.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-spring:
- datasource:
- url: jdbc:postgresql://localhost:5432/verich
- username: postgres
- password: 123456
- driver-class-name: org.postgresql.Driver
- type: com.zaxxer.hikari.HikariDataSource
- hikari:
- minimum-idle: 5
- connection-test-query: SELECT 1
- maximum-pool-size: 2000
- auto-commit: true
- idle-timeout: 30000
- pool-name: SpringBootDemoHikariCP
- max-lifetime: 60000
- connection-timeout: 30000
- sql:
- init:
- mode: always
- continue-on-error: true
\ No newline at end of file
diff --git a/src/test/resources/application-remote.yml b/src/test/resources/application-remote.yml
deleted file mode 100644
index aa16fff..0000000
--- a/src/test/resources/application-remote.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-spring:
- cache.type: simple
- datasource:
- postgre:
- jdbc-url: jdbc:postgresql://localhost:5432/verich
- username: postgres
- password: 123456
- driver-class-name: org.postgresql.Driver
- type: com.zaxxer.hikari.HikariDataSource
- mapper-locations: classpath*:mapper/postgre/*.xml
- type-aliases-package: quant.rich.emoney.entity.postgre
- hikari:
- minimum-idle: 5
- connection-test-query: SELECT 1
- maximum-pool-size: 2000
- auto-commit: true
- idle-timeout: 30000
- pool-name: SpringBootDemoHikariCP
- max-lifetime: 60000
- connection-timeout: 30000
- sqlite:
- jdbc-url: jdbc:sqlite:E:/eclipse-workspace/emo-grab/src/main/resources/database.db
- driver-class-name: org.sqlite.JDBC
- mapper-locations: classpath*:mapper/sqlite/*.xml
- type-aliases-package: quant.rich.emoney.entity.sqlite
- sql:
- init:
- mode: always
- continue-on-error: true
diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml
deleted file mode 100644
index c2d7885..0000000
--- a/src/test/resources/application.yml
+++ /dev/null
@@ -1,75 +0,0 @@
-server:
- port: 7790
- compression: #开启gzip压缩,返回内容大于2k的才会进行压缩
- enabled: true
- mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain
- min-response-size: 2048
-
-logging.level:
- '[quant.rich]': debug
- '[org.springframework.security]': info
- '[org.springframework.boot.devtools.restart]': debug
-
-spring:
- cache:
- type: redis
- redis:
- key-prefix: 'emoney-auto:'
- use-key-prefix: true
- devtools:
- restart:
- enabled: true
- additional-exclude:
- - '**/*.html'
- - '**/*.js'
- - '**/*.css'
- additional-paths: lib/
- jackson:
- date-format: yyyy-MM-dd HH:mm:ss
- time-zone: Asia/Shanghai
- profiles.active: remote
- session.timeout: 86400
- thymeleaf:
- prefix: classpath:/webpage/
- suffix: .html
- mode: HTML
- encoding: UTF-8
- cache: false
-
-mybatis-plus-join.banner: false
-mybatis-plus:
- global-config:
- banner: false
- mapper-locations:
- - classpath*:mapper/postgre/*.xml
- - classpath*:mapper/sqlite/*.xml
- type-aliases-package:
- - quant.rich.emoney.entity.postgre
- - quant.rich.emoney.entity.sqlite
- type-handlers-package: quant.rich.emoney.mybatis.typehandler
- configuration:
- map-underscore-to-camel-case: true
- default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
-
-kaptcha:
- border: "no"
- image:
- width: 130
- height: 38
- textproducer:
- char:
- length: 5
- font:
- color: 35,37,38,80
- size: 30
- names: Times New Roman,Sans,Microsoft Yahei UI,Consolas
- session:
- key: code
- noise:
- color: 35,37,38,80
-
-# 程序默认配置,部分内容可以通过数据库覆写
-# 当数据库不存在配置时默认加载文件内配置
-emoney-auto-config:
- username: admin
- password: Em0nY_4u70~!
\ No newline at end of file