diff --git a/carp-dependencies/pom.xml b/carp-dependencies/pom.xml
new file mode 100644
index 00000000..0559d4fa
--- /dev/null
+++ b/carp-dependencies/pom.xml
@@ -0,0 +1,706 @@
+
+
+
+
+ 4.0.0
+ cn.sliew
+ carp-dependencies
+ 0.0.13-SNAPSHOT
+ pom
+
+ carp-dependencies
+ Carp Dependencies
+ https://github.com/flowerfine/carp
+
+
+
+ Apache License, Version 2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+ git@github.com:flowerfine/carp.git
+ scm:git:git@github.com:flowerfine/carp.git
+ https://github.com/flowerfine/carp
+ HEAD
+
+
+
+
+ kalencaya
+ 1942460489@qq.com
+
+
+
+
+ Github Issue
+ https://github.com/flowerfine/carp/issues
+
+
+
+
+ sonatype-nexus
+ Sonatype Nexus Snapshots
+ https://s01.oss.sonatype.org/content/repositories/snapshots/
+
+
+ sonatype-nexus
+ Sonatype Nexus Release
+ https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
+
+ 2023.0.1
+ 3.3.0
+ 0.1.1
+ 1.4.2.Final
+ 0.2.0
+ 1.18.32
+ 5.8.30
+ 3.12.0
+ 1.9.4
+ 1.9
+ 1.19
+ 2.11.0
+ 33.2.1-jre
+ 1.0.13
+
+ 3.0.3
+ 3.5.7
+ 2.2
+ 8.3.0
+ 42.3.3
+ 2.3.230
+
+ 1.38.0
+ 4.5.0
+ 3.3.4
+ 1.1.0-M1
+ 8.3.8
+ 3.27.2
+ 4.3.2
+ 1.5.2
+ 0.4.14
+ 0.9.0
+ 1.1.1
+ 3.9.0
+ 3.12.1
+ 0.9.0
+ 6.9.2
+ 7.6.1
+ 0.5.1
+ 3.3.2
+ 0.0.9
+ 9.7
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring.cloud.version}
+ pom
+ import
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.boot.version}
+ pom
+ import
+
+
+ com.github.xiaoymin
+ knife4j-dependencies
+ ${knife4j.version}
+ pom
+ import
+
+
+ org.zalando
+ logbook-bom
+ ${logbook.version}
+ pom
+ import
+
+
+
+ ${project.groupId}
+ carp-framework-common
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-dag
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-exception
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-metrics
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-mongo
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-mybatis
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-pekko
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-redis
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-spring
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-framework-web
+ ${project.version}
+
+
+
+ ${project.groupId}
+ carp-module-alert
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-application-vela
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-datasource
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-http-framework
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-kubernetes
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-plugin
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-scheduler-base
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-scheduler-quartz
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-queue-api
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-security-core
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-security-spring
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-system
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-workflow-api
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-module-workflow-internal
+ ${project.version}
+
+
+
+ ${project.groupId}
+ carp-plugin-schedule-api
+ ${project.version}
+
+
+ ${project.groupId}
+ carp-plugin-test-api
+ ${project.version}
+
+
+
+ ${project.groupId}
+ carp-server
+ ${project.version}
+
+
+
+ org.projectlombok
+ lombok
+ ${org.projectlombok.version}
+
+
+
+ org.mapstruct.extensions.spring
+ mapstruct-spring-annotations
+ ${org.mapstruct.extensions.spring.version}
+
+
+ org.mapstruct
+ mapstruct
+ ${org.mapstruct.version}
+
+
+
+ cn.hutool
+ hutool-all
+ ${hutool.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons.lang3.version}
+
+
+ commons-beanutils
+ commons-beanutils
+ ${commons.beanutils.version}
+
+
+ org.apache.commons
+ commons-text
+ ${commons.text.version}
+
+
+ org.apache.commons
+ commons-compress
+ ${commons.compress.version}
+
+
+ commons-io
+ commons-io
+ ${commons.io.version}
+
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+
+ cn.sliew
+ milky-common
+ ${milky.version}
+
+
+ cn.sliew
+ milky-registry
+ ${milky.version}
+
+
+ cn.sliew
+ milky-test
+ ${milky.version}
+
+
+
+
+ org.mybatis
+ mybatis-spring
+ ${mybatis.spring.version}
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ ${mybatis.plus.version}
+
+
+ org.mybatis
+ mybatis-spring
+
+
+
+
+ com.baomidou
+ mybatis-plus-core
+ ${mybatis.plus.version}
+
+
+ com.baomidou
+ mybatis-plus-generator
+ ${mybatis.plus.version}
+
+
+ org.apache.velocity
+ velocity-engine-core
+ ${velocity.engine.version}
+
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+ ${mysql.version}
+
+
+ org.postgresql
+ postgresql
+ runtime
+ ${postgresql.version}
+
+
+ com.h2database
+ h2
+ ${h2.version}
+
+
+
+
+ cn.dev33
+ sa-token-spring-boot-starter
+ ${sa-token.version}
+
+
+
+ org.apache.hadoop
+ hadoop-common
+ ${hadoop.version}
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ slf4j-reload4j
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ commons-logging
+ commons-logging
+
+
+ ch.qos.reload4j
+ reload4j
+
+
+ javax.servlet
+ javax.servlet-api
+
+
+ javax.servlet.jsp
+ jsp-api
+
+
+
+
+ org.apache.hadoop
+ hadoop-hdfs-client
+ ${hadoop.version}
+
+
+ org.apache.hadoop
+ hadoop-hdfs
+ ${hadoop.version}
+
+
+ org.apache.hadoop
+ hadoop-aliyun
+ ${hadoop.version}
+
+
+ org.apache.hadoop
+ hadoop-aws
+ ${hadoop.version}
+
+
+
+ org.apache.pekko
+ pekko-actor-typed_${scala.binary.version}
+ ${pekko.version}
+
+
+ org.apache.pekko
+ pekko-cluster-typed_${scala.binary.version}
+ ${pekko.version}
+
+
+ org.apache.pekko
+ pekko-cluster-sharding-typed_${scala.binary.version}
+ ${pekko.version}
+
+
+ org.apache.pekko
+ pekko-stream_${scala.binary.version}
+ ${pekko.version}
+
+
+ org.apache.pekko
+ pekko-serialization-jackson_${scala.binary.version}
+ ${pekko.version}
+
+
+ org.apache.pekko
+ pekko-persistence-typed_${scala.binary.version}
+ ${pekko.version}
+
+
+ org.apache.pekko
+ pekko-persistence-jdbc_${scala.binary.version}
+ ${pekko.version}
+
+
+ org.apache.pekko
+ pekko-http_${scala.binary.version}
+ ${pekko.version}
+
+
+ org.apache.pekko
+ pekko-http-jackson_${scala.binary.version}
+ ${pekko.version}
+
+
+
+ io.minio
+ minio
+ ${minio.version}
+
+
+
+ org.redisson
+ redisson-spring-boot-starter
+ ${redisson.version}
+
+
+
+ com.alibaba.cola
+ cola-component-statemachine
+ ${cola.version}
+
+
+
+ org.furyio
+ fury-core
+ ${fury.version}
+
+
+
+ org.jgrapht
+ jgrapht-core
+ ${jgrapht.version}
+
+
+
+ com.github.zafarkhaja
+ java-semver
+ ${semver.version}
+
+
+
+ com.flipkart.zjsonpatch
+ zjsonpatch
+ ${zjsonpatch.version}
+
+
+
+ com.google.auto.service
+ auto-service
+ ${auto-service.version}
+
+
+
+ org.pf4j
+ pf4j
+ ${pf4j.version}
+
+
+ org.pf4j
+ pf4j-spring
+ ${pf4j.version}
+
+
+
+ io.fabric8
+ kubernetes-client
+ ${kubernetes-client.version}
+
+
+
+ org.javers
+ javers-spring-boot-starter-sql
+ ${javers.version}
+
+
+ org.javers
+ javers-spring
+ ${javers.version}
+
+
+
+ com.alibaba
+ easyexcel
+ ${easyexcel.version}
+
+
+
+ com.tencent.devops
+ devops-boot-starter-schedule-server
+ ${bkdevops.version}
+
+
+
+ org.ow2.asm
+ asm
+ ${asm.version}
+
+
+
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.7.0
+ true
+
+ sonatype-nexus
+ https://s01.oss.sonatype.org/
+ true
+
+
+
+
+
+
+
+ oss-release
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+ verify
+
+ jar-no-fork
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+ ${project.build.sourceEncoding}
+ ${project.build.sourceEncoding}
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+
+
+ sign-artifacts
+
+ sign
+
+
+
+
+
+
+ --pinentry-mode
+ loopback
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-remote-resources-plugin
+
+
+ process-resource-bundles
+
+ process
+
+
+
+ org.apache:apache-jar-resource-bundle:1.4
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/carp-dist/pom.xml b/carp-dist/pom.xml
index ca9ab337..8856418b 100644
--- a/carp-dist/pom.xml
+++ b/carp-dist/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOTcarp-dist
diff --git a/carp-examples/carp-ageiport-example/carp-ageiport-processor/pom.xml b/carp-examples/carp-ageiport-example/carp-ageiport-processor/pom.xml
index ae9ce88e..413de834 100644
--- a/carp-examples/carp-ageiport-example/carp-ageiport-processor/pom.xml
+++ b/carp-examples/carp-ageiport-example/carp-ageiport-processor/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-ageiport-example
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-ageiport-processor
@@ -43,6 +43,11 @@
ageiport-processor-core
+
+ net.datafaker
+ datafaker
+
+
org.junit.jupiterjunit-jupiter
diff --git a/carp-examples/carp-ageiport-example/carp-ageiport-processor/src/main/java/cn/sliew/carp/example/ageiport/controller/EasyExcelController.java b/carp-examples/carp-ageiport-example/carp-ageiport-processor/src/main/java/cn/sliew/carp/example/ageiport/controller/EasyExcelController.java
new file mode 100644
index 00000000..3ced556a
--- /dev/null
+++ b/carp-examples/carp-ageiport-example/carp-ageiport-processor/src/main/java/cn/sliew/carp/example/ageiport/controller/EasyExcelController.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.example.ageiport.controller;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.UUID;
+import cn.sliew.carp.example.ageiport.util.DataFakerUtil;
+import cn.sliew.carp.processor.core.model.UserData;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.metadata.WriteSheet;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.File;
+
+@RestController
+@RequestMapping("/api/carp/example/ageiport/easyexcel")
+@Tag(name = "测试模块-EasyExcel功能")
+public class EasyExcelController {
+
+ @GetMapping
+ @Operation(summary = "测试流式导出", description = "测试流式导出")
+ public void testStreamExport() throws Exception {
+ File file = FileUtil.file(FileUtil.getUserHomePath() + "/Downloads/export/" + UUID.fastUUID().toString(true) + ".xlsx");
+ if (FileUtil.exist(file) == false) {
+ file.createNewFile();
+ }
+
+// EasyExcel.write(file).head(UserData.class).sheet(1).doWrite(DataFakerUtil.generateList(5));
+ // 这种指定 sheet 的方式必须执行 finish() 方法。上面的 doWrite() 方法内部会自己执行 finish() 方法
+ try (ExcelWriter excelWriter = EasyExcel.write(file).head(UserData.class).inMemory(false).autoCloseStream(true).build()) {
+ // excel 单个 sheet 最多可写入 1048576 条数据。超出后需重新写
+ for (int i = 1 ; i <= 10; i++) {
+ WriteSheet writeSheet = EasyExcel.writerSheet(i, "测试" + i).head(UserData.class).build();
+ doWriteSheet(excelWriter, writeSheet);
+ System.out.println(String.format("写入第%d批次数据", i));
+ }
+ }
+ }
+
+ private void doWriteSheet(ExcelWriter excelWriter, WriteSheet writeSheet) {
+ for (int i = 0; i < 50; i++) {
+ excelWriter.write(DataFakerUtil.generateList(10000), writeSheet);
+ }
+ }
+
+}
diff --git a/carp-examples/carp-ageiport-example/carp-ageiport-processor/src/main/java/cn/sliew/carp/example/ageiport/util/DataFakerUtil.java b/carp-examples/carp-ageiport-example/carp-ageiport-processor/src/main/java/cn/sliew/carp/example/ageiport/util/DataFakerUtil.java
new file mode 100644
index 00000000..b6810de0
--- /dev/null
+++ b/carp-examples/carp-ageiport-example/carp-ageiport-processor/src/main/java/cn/sliew/carp/example/ageiport/util/DataFakerUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.example.ageiport.util;
+
+import cn.sliew.carp.processor.core.model.UserData;
+import net.datafaker.Faker;
+import net.datafaker.transformations.Field;
+import net.datafaker.transformations.JavaObjectTransformer;
+import net.datafaker.transformations.Schema;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public enum DataFakerUtil {
+ ;
+
+ private static final Faker FAKER = new Faker();
+ private static final JavaObjectTransformer J_TRANSFORMER = new JavaObjectTransformer();
+
+ public static Schema
+
+ net.datafaker
+ datafaker
+ ${datafaker.version}
+
+
org.junit.jupiterjunit-jupiter
diff --git a/carp-examples/carp-camellia-example/pom.xml b/carp-examples/carp-camellia-example/pom.xml
index 7a5bf6f6..5a554a53 100644
--- a/carp-examples/carp-camellia-example/pom.xml
+++ b/carp-examples/carp-camellia-example/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-examples
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-camellia-example
diff --git a/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/config/CamelliaConfig.java b/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/config/CamelliaConfig.java
index ec6c3fdf..956b6151 100644
--- a/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/config/CamelliaConfig.java
+++ b/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/config/CamelliaConfig.java
@@ -22,7 +22,11 @@
import org.springframework.context.annotation.Configuration;
@Configuration
-@ComponentScan(basePackages = {"com.netease.nim.camellia.redis.springboot",
- "com.netease.nim.camellia.delayqueue.server"})
+@ComponentScan(basePackages = {
+ "com.netease.nim.camellia.redis.springboot",
+ "com.netease.nim.camellia.delayqueue.server.springboot",
+ "com.netease.nim.camellia.delayqueue.sdk.springboot"
+})
public class CamelliaConfig {
+
}
diff --git a/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/controller/DelayMsgController.java b/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/controller/DelayMsgController.java
index 028e0558..b683c386 100644
--- a/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/controller/DelayMsgController.java
+++ b/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/controller/DelayMsgController.java
@@ -18,9 +18,9 @@
package cn.sliew.carp.example.camellia.controller;
-import cn.sliew.carp.example.camellia.listener.ConsumerService1;
+import cn.sliew.carp.example.camellia.service.DelayMsgService;
import com.netease.nim.camellia.delayqueue.common.domain.CamelliaDelayMsg;
-import com.netease.nim.camellia.delayqueue.sdk.CamelliaDelayQueueSdk;
+import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -29,8 +29,6 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
-import java.util.concurrent.TimeUnit;
-
@Slf4j
@RestController
@RequestMapping("/api/carp/example/camellia")
@@ -38,15 +36,23 @@
public class DelayMsgController {
@Autowired
- private CamelliaDelayQueueSdk delayQueueSdk;
+ private DelayMsgService delayMsgService;
- @PostMapping("/put")
- public CamelliaDelayMsg sendDelayMsg(@RequestParam("msg") String msg,
+ @PostMapping("/simple")
+ @Operation(summary = "发送-简单消息", description = "发送-简单消息")
+ public CamelliaDelayMsg sendSimpleDelayMsg(@RequestParam("msg") String msg,
@RequestParam("delaySeconds") long delaySeconds,
@RequestParam(value = "ttlSeconds", required = false, defaultValue = "30") long ttlSeconds,
@RequestParam(value = "maxRetry", required = false, defaultValue = "3") int maxRetry) {
- String topic = ConsumerService1.TOPIC;
- log.info("sendDelayMsg, topic = {}, msg = {}, delaySeconds = {}, ttlSeconds = {}, maxRetry = {}", topic, msg, delaySeconds, ttlSeconds, maxRetry);
- return delayQueueSdk.sendMsg(topic, msg, delaySeconds, TimeUnit.SECONDS, ttlSeconds, TimeUnit.SECONDS, maxRetry);
+ return delayMsgService.sendSimpleDelayMsg(msg, delaySeconds, ttlSeconds, maxRetry);
+ }
+
+ @PostMapping("/lambda")
+ @Operation(summary = "发送-Lambda消息", description = "发送-Lambda消息")
+ public CamelliaDelayMsg sendLambdaDelayMsg(@RequestParam("msg") String msg,
+ @RequestParam("delaySeconds") long delaySeconds,
+ @RequestParam(value = "ttlSeconds", required = false, defaultValue = "30") long ttlSeconds,
+ @RequestParam(value = "maxRetry", required = false, defaultValue = "3") int maxRetry) {
+ return delayMsgService.sendLambdaDelayMsg(msg, delaySeconds, ttlSeconds, maxRetry);
}
}
diff --git a/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/service/DelayMsgService.java b/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/service/DelayMsgService.java
new file mode 100644
index 00000000..b28aa114
--- /dev/null
+++ b/carp-examples/carp-camellia-example/src/main/java/cn/sliew/carp/example/camellia/service/DelayMsgService.java
@@ -0,0 +1,44 @@
+package cn.sliew.carp.example.camellia.service;
+
+import cn.sliew.carp.example.camellia.listener.ConsumerService1;
+import cn.sliew.carp.framework.common.reflection.JobDetails;
+import cn.sliew.carp.framework.common.reflection.JobDetailsAsmGenerator;
+import cn.sliew.carp.framework.common.reflection.JobDetailsGenerator;
+import cn.sliew.carp.framework.common.reflection.lambdas.JobLambda;
+import cn.sliew.milky.common.util.JacksonUtil;
+import com.netease.nim.camellia.delayqueue.common.domain.CamelliaDelayMsg;
+import com.netease.nim.camellia.delayqueue.sdk.CamelliaDelayQueueSdk;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Service
+public class DelayMsgService {
+
+ @Autowired
+ private CamelliaDelayQueueSdk delayQueueSdk;
+
+ public CamelliaDelayMsg sendSimpleDelayMsg(String msg, long delaySeconds, long ttlSeconds, int maxRetry) {
+ String topic = ConsumerService1.TOPIC;
+ log.info("sendSimpleDelayMsg, topic = {}, msg = {}, delaySeconds = {}, ttlSeconds = {}, maxRetry = {}", topic, msg, delaySeconds, ttlSeconds, maxRetry);
+ return delayQueueSdk.sendMsg(topic, msg, delaySeconds, TimeUnit.SECONDS, ttlSeconds, TimeUnit.SECONDS, maxRetry);
+ }
+
+ public CamelliaDelayMsg sendLambdaDelayMsg(String msg, long delaySeconds, long ttlSeconds, int maxRetry) {
+ return doSendLambdaDelayMsg(() -> System.out.println(msg), delaySeconds, ttlSeconds, maxRetry);
+ }
+
+ public CamelliaDelayMsg doSendLambdaDelayMsg(JobLambda jobLambda, long delaySeconds, long ttlSeconds, int maxRetry) {
+ JobDetailsGenerator generator = new JobDetailsAsmGenerator();
+ JobDetails jobDetails = generator.toJobDetails(jobLambda);
+ String msg = JacksonUtil.toJsonString(jobDetails);
+ String topic = ConsumerService1.TOPIC;
+ log.info("sendDelayMsg, topic = {}, msg = {}, delaySeconds = {}, ttlSeconds = {}, maxRetry = {}", topic, msg, delaySeconds, ttlSeconds, maxRetry);
+ return delayQueueSdk.sendMsg(topic, msg, delaySeconds, TimeUnit.SECONDS, ttlSeconds, TimeUnit.SECONDS, maxRetry);
+ }
+
+
+}
diff --git a/carp-examples/carp-hazelcast-example/pom.xml b/carp-examples/carp-hazelcast-example/pom.xml
index 4668c533..067430db 100644
--- a/carp-examples/carp-hazelcast-example/pom.xml
+++ b/carp-examples/carp-hazelcast-example/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-examples
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-hazelcast-example
diff --git a/carp-examples/carp-hazelcast-example/src/main/java/cn/sliew/carp/example/hazelcast/controller/CommandController.java b/carp-examples/carp-hazelcast-example/src/main/java/cn/sliew/carp/example/hazelcast/controller/CommandController.java
index 72325860..84641823 100644
--- a/carp-examples/carp-hazelcast-example/src/main/java/cn/sliew/carp/example/hazelcast/controller/CommandController.java
+++ b/carp-examples/carp-hazelcast-example/src/main/java/cn/sliew/carp/example/hazelcast/controller/CommandController.java
@@ -19,6 +19,7 @@
package cn.sliew.carp.example.hazelcast.controller;
import cn.sliew.carp.example.hazelcast.service.HazelcastMapService;
+import com.hazelcast.map.IMap;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -34,6 +35,7 @@ public class CommandController {
@PostMapping("/put")
public boolean put(@RequestParam("key") String key, @RequestParam("value") String value) {
mapService.getMap("map-command").put(key, value);
+ IMap map = mapService.getMap("");
return true;
}
diff --git a/carp-examples/carp-javers-example/pom.xml b/carp-examples/carp-javers-example/pom.xml
index 2528a1b5..69b98675 100644
--- a/carp-examples/carp-javers-example/pom.xml
+++ b/carp-examples/carp-javers-example/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-examples
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-javers-example
diff --git a/carp-examples/carp-jobrunr-example/pom.xml b/carp-examples/carp-jobrunr-example/pom.xml
index a212fecc..41e15f7a 100644
--- a/carp-examples/carp-jobrunr-example/pom.xml
+++ b/carp-examples/carp-jobrunr-example/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-examples
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-jobrunr-example
diff --git a/carp-examples/carp-jobrunr-example/src/main/java/cn/sliew/carp/example/jobrunr/controller/JobRunrController.java b/carp-examples/carp-jobrunr-example/src/main/java/cn/sliew/carp/example/jobrunr/controller/JobRunrController.java
index be017924..746538a5 100644
--- a/carp-examples/carp-jobrunr-example/src/main/java/cn/sliew/carp/example/jobrunr/controller/JobRunrController.java
+++ b/carp-examples/carp-jobrunr-example/src/main/java/cn/sliew/carp/example/jobrunr/controller/JobRunrController.java
@@ -49,12 +49,24 @@ public String enqueueExampleJob(@RequestParam(value = "name", defaultValue = "Wo
}
@PutMapping("/enqueue-example-job-with-record")
+ @Operation(summary = "新增-复杂对象", description = "新增-复杂对象")
public String enqueueExampleJobWithRecord(@RequestParam(value = "name", defaultValue = "World") String name) {
SampleJobInput sampleJobInput = new SampleJobInput(UUID.randomUUID(), name);
final JobId enqueuedJobId = jobScheduler.enqueue(() -> sampleService.sampleJobWithRecordInput(sampleJobInput));
return "Job Enqueued: " + enqueuedJobId.toString();
}
+ @PutMapping("/enqueue-example-job-pure-lambda")
+ @Operation(summary = "新增-纯lambda", description = "新增-纯lambda")
+ public String enqueueExampleJobPureLambda(@RequestParam(value = "name", defaultValue = "World") String name) {
+ final JobId enqueuedJobId = jobScheduler.enqueue(() -> {
+ // 只能写一个,如果打印 2 次就报错
+ System.out.println("第一次:Hello " + name);
+// System.out.println("第二次:Hello " + name);
+ });
+ return "Job Enqueued: " + enqueuedJobId.toString();
+ }
+
@DeleteMapping("/delete-job")
@Operation(summary = "删除", description = "删除")
public String deleteExampleJob(@RequestParam(value = "id") String jobId) {
diff --git a/carp-examples/carp-mongo-example/pom.xml b/carp-examples/carp-mongo-example/pom.xml
index b08214c1..4542de78 100644
--- a/carp-examples/carp-mongo-example/pom.xml
+++ b/carp-examples/carp-mongo-example/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-examples
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-mongo-example
diff --git a/carp-examples/carp-pekko-example/pom.xml b/carp-examples/carp-pekko-example/pom.xml
index 8725885c..1f1a19ec 100644
--- a/carp-examples/carp-pekko-example/pom.xml
+++ b/carp-examples/carp-pekko-example/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-examples
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-pekko-example
diff --git a/carp-examples/carp-pekko-example/src/main/java/cn/sliew/carp/example/pekko/cluster/distrubuted/Counter.java b/carp-examples/carp-pekko-example/src/main/java/cn/sliew/carp/example/pekko/cluster/distrubuted/Counter.java
new file mode 100644
index 00000000..5e16efcc
--- /dev/null
+++ b/carp-examples/carp-pekko-example/src/main/java/cn/sliew/carp/example/pekko/cluster/distrubuted/Counter.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.example.pekko.cluster.distrubuted;
+
+import org.apache.pekko.actor.typed.ActorRef;
+import org.apache.pekko.actor.typed.Behavior;
+import org.apache.pekko.actor.typed.javadsl.AbstractBehavior;
+import org.apache.pekko.actor.typed.javadsl.ActorContext;
+import org.apache.pekko.actor.typed.javadsl.Behaviors;
+import org.apache.pekko.actor.typed.javadsl.Receive;
+import org.apache.pekko.cluster.ddata.GCounter;
+import org.apache.pekko.cluster.ddata.Key;
+import org.apache.pekko.cluster.ddata.SelfUniqueAddress;
+import org.apache.pekko.cluster.ddata.typed.javadsl.DistributedData;
+import org.apache.pekko.cluster.ddata.typed.javadsl.Replicator;
+import org.apache.pekko.cluster.ddata.typed.javadsl.ReplicatorMessageAdapter;
+
+public class Counter extends AbstractBehavior {
+ interface Command {
+ }
+
+ enum Increment implements Command {
+ INSTANCE
+ }
+
+ public static class GetValue implements Command {
+ public final ActorRef replyTo;
+
+ public GetValue(ActorRef replyTo) {
+ this.replyTo = replyTo;
+ }
+ }
+
+ public static class GetCachedValue implements Command {
+ public final ActorRef replyTo;
+
+ public GetCachedValue(ActorRef replyTo) {
+ this.replyTo = replyTo;
+ }
+ }
+
+ enum Unsubscribe implements Command {
+ INSTANCE
+ }
+
+ private interface InternalCommand extends Command {
+ }
+
+ private static class InternalUpdateResponse implements InternalCommand {
+ final Replicator.UpdateResponse rsp;
+
+ InternalUpdateResponse(Replicator.UpdateResponse rsp) {
+ this.rsp = rsp;
+ }
+ }
+
+ private static class InternalGetResponse implements InternalCommand {
+ final Replicator.GetResponse rsp;
+ final ActorRef replyTo;
+
+ InternalGetResponse(Replicator.GetResponse rsp, ActorRef replyTo) {
+ this.rsp = rsp;
+ this.replyTo = replyTo;
+ }
+ }
+
+ private static final class InternalSubscribeResponse implements InternalCommand {
+ final Replicator.SubscribeResponse rsp;
+
+ InternalSubscribeResponse(Replicator.SubscribeResponse rsp) {
+ this.rsp = rsp;
+ }
+ }
+
+ public static Behavior create(Key key) {
+ return Behaviors.setup(
+ ctx ->
+ DistributedData.withReplicatorMessageAdapter(
+ (ReplicatorMessageAdapter replicatorAdapter) ->
+ new Counter(ctx, replicatorAdapter, key)));
+ }
+
+ // adapter that turns the response messages from the replicator into our own protocol
+ private final ReplicatorMessageAdapter replicatorAdapter;
+ private final SelfUniqueAddress node;
+ private final Key key;
+
+ private int cachedValue = 0;
+
+ private Counter(
+ ActorContext context,
+ ReplicatorMessageAdapter replicatorAdapter,
+ Key key) {
+ super(context);
+
+ this.replicatorAdapter = replicatorAdapter;
+ this.key = key;
+ this.node = DistributedData.get(context.getSystem()).selfUniqueAddress();
+ this.replicatorAdapter.subscribe(this.key, InternalSubscribeResponse::new);
+ }
+
+ @Override
+ public Receive createReceive() {
+ return newReceiveBuilder()
+ .onMessage(Increment.class, this::onIncrement)
+ .onMessage(InternalUpdateResponse.class, msg -> Behaviors.same())
+ .onMessage(GetValue.class, this::onGetValue)
+ .onMessage(GetCachedValue.class, this::onGetCachedValue)
+ .onMessage(Unsubscribe.class, this::onUnsubscribe)
+ .onMessage(InternalGetResponse.class, this::onInternalGetResponse)
+ .onMessage(InternalSubscribeResponse.class, this::onInternalSubscribeResponse)
+ .build();
+ }
+
+ private Behavior onIncrement(Increment cmd) {
+ replicatorAdapter.askUpdate(
+ askReplyTo ->
+ new Replicator.Update<>(
+ key,
+ GCounter.empty(),
+ Replicator.writeLocal(),
+ askReplyTo,
+ curr -> curr.increment(node, 1)),
+ InternalUpdateResponse::new);
+ return this;
+ }
+
+ private Behavior onGetValue(GetValue cmd) {
+ replicatorAdapter.askGet(
+ askReplyTo -> new Replicator.Get<>(key, Replicator.readLocal(), askReplyTo),
+ rsp -> new InternalGetResponse(rsp, cmd.replyTo));
+
+ return this;
+ }
+
+ private Behavior onGetCachedValue(GetCachedValue cmd) {
+ cmd.replyTo.tell(cachedValue);
+ return this;
+ }
+
+ private Behavior onUnsubscribe(Unsubscribe cmd) {
+ replicatorAdapter.unsubscribe(key);
+ return this;
+ }
+
+ private Behavior onInternalGetResponse(InternalGetResponse msg) {
+ if (msg.rsp instanceof Replicator.GetSuccess) {
+ int value = ((Replicator.GetSuccess>) msg.rsp).get(key).getValue().intValue();
+ msg.replyTo.tell(value);
+ return this;
+ } else {
+ // not dealing with failures
+ return Behaviors.unhandled();
+ }
+ }
+
+ private Behavior onInternalSubscribeResponse(InternalSubscribeResponse msg) {
+ if (msg.rsp instanceof Replicator.Changed) {
+ GCounter counter = ((Replicator.Changed>) msg.rsp).get(key);
+ cachedValue = counter.getValue().intValue();
+ return this;
+ } else {
+ // no deletes
+ return Behaviors.unhandled();
+ }
+ }
+}
\ No newline at end of file
diff --git a/carp-examples/carp-redisson-example/pom.xml b/carp-examples/carp-redisson-example/pom.xml
index b7755bef..72077e14 100644
--- a/carp-examples/carp-redisson-example/pom.xml
+++ b/carp-examples/carp-redisson-example/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-examples
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-redisson-example
diff --git a/carp-examples/carp-redisson-example/src/main/java/cn/sliew/carp/example/redisson/controller/LockController.java b/carp-examples/carp-redisson-example/src/main/java/cn/sliew/carp/example/redisson/controller/LockController.java
new file mode 100644
index 00000000..919015f0
--- /dev/null
+++ b/carp-examples/carp-redisson-example/src/main/java/cn/sliew/carp/example/redisson/controller/LockController.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.example.redisson.controller;
+
+import cn.hutool.core.lang.UUID;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.sliew.carp.example.redisson.service.LockService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.apache.commons.lang3.time.DurationFormatUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.Duration;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@RestController
+@RequestMapping("/api/carp/example/redisson/lock")
+@Tag(name = "测试模块-Lock")
+public class LockController {
+
+ @Autowired
+ private LockService lockService;
+
+ /**
+ * 测试自动续期,自动续期有 1 个要点:
+ * 1.不设置锁ttl,所以会无限续期下去。如果显式指定,则不会生效。
+ */
+ @PostMapping("/lock-unlock")
+ @Operation(summary = "加锁-释放锁")
+ public String lockAndUnlock() throws Exception {
+ String key = UUID.fastUUID().toString(true);
+ boolean locked = lockService.lockWithAutoRefreshTTL(key, Duration.ofSeconds(3L).toMillis());
+ if (locked) {
+ System.out.println("lock: " + key);
+ ThreadUtil.sleep(Duration.ofMinutes(3L).toMillis());
+ Long releaseTime = lockService.lockReleaseTime(key);
+ System.out.println("lock relase time: " + DurationFormatUtils.formatDurationHMS(releaseTime));
+ lockService.unlock(key);
+ return key;
+ }
+ return "加锁失败";
+ }
+
+ /**
+ * 测试异步释放锁
+ * 1.默认是只有持有锁的线程才可以释放锁,异步情况下,必须强制释放锁才可以
+ */
+ @PostMapping("/lock-unlock-async")
+ @Operation(summary = "加锁-异步释放锁")
+ public String lockAndUnlockAsync() throws Exception {
+ String key = UUID.fastUUID().toString(true);
+ boolean locked = lockService.lockWithAutoRefreshTTL(key, Duration.ofSeconds(3L).toMillis());
+ if (locked) {
+ ThreadPoolExecutor executor = ThreadUtil.newExecutor(4);
+ CompletableFuture future = CompletableFuture.runAsync(() -> {
+ System.out.println("lock: " + key);
+ ThreadUtil.sleep(Duration.ofMinutes(1L).toMillis());
+ Long releaseTime = lockService.lockReleaseTime(key);
+ System.out.println("lock relase time: " + DurationFormatUtils.formatDurationHMS(releaseTime));
+ }, executor);
+ future.whenCompleteAsync((unused, throwable) -> {
+ lockService.forceUnlock(key);
+ }, executor);
+ return key;
+ }
+ return "加锁失败";
+ }
+
+ @PostMapping("/lock")
+ @Operation(summary = "加锁")
+ public String lock() throws Exception {
+ String key = UUID.fastUUID().toString(true);
+ boolean locked = lockService.lock(key, Duration.ofSeconds(3L).toMillis(), Duration.ofSeconds(10L).toMillis());
+ if (locked) {
+ return key;
+ }
+ return "加锁失败";
+ }
+
+ @PostMapping("/unlock")
+ @Operation(summary = "释放锁")
+ public void unlock(@RequestParam("key") String key) throws Exception {
+ lockService.unlock(key);
+ }
+
+ @PostMapping("/forceUnlock")
+ @Operation(summary = "强制释放锁")
+ public void forceUnlock(@RequestParam("key") String key) throws Exception {
+ lockService.forceUnlock(key);
+ }
+
+ @GetMapping("/lock-ttl")
+ @Operation(summary = "锁释放时间")
+ public String scheduleLambda(@RequestParam("key") String key) throws Exception {
+ Long time = lockService.lockReleaseTime(key);
+ return DurationFormatUtils.formatDurationHMS(time);
+ }
+
+}
diff --git a/carp-examples/carp-redisson-example/src/main/java/cn/sliew/carp/example/redisson/service/LockService.java b/carp-examples/carp-redisson-example/src/main/java/cn/sliew/carp/example/redisson/service/LockService.java
new file mode 100644
index 00000000..f8e3824e
--- /dev/null
+++ b/carp-examples/carp-redisson-example/src/main/java/cn/sliew/carp/example/redisson/service/LockService.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.example.redisson.service;
+
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Service
+public class LockService {
+
+ @Value("${spring.application.name}")
+ private String application;
+
+ @Autowired
+ private RedissonClient client;
+
+ /**
+ * watchDog 只有设置 releaseTime 的 lock 不会生效,不会自动续期
+ */
+ public boolean lock(String key, long lockTimeout, long releaseTime) {
+ RLock lock = getLock(key);
+ try {
+ // 尝试拿锁 lockTimeout 后停止重试,返回false
+ // 没有Watch Dog ,releaseTime 后自动释放
+ return lock.tryLock(lockTimeout, releaseTime, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return false;
+ }
+ }
+
+ /**
+ * watchDog 自动续期时长默认为 30s,可通过 lockWatchdogTimeout 设置每次续期时长。
+ * watchDog 按照 lockWatchdogTimeout / 3 的频率检测 key,进行续期
+ */
+ public boolean lockWithAutoRefreshTTL(String key, long lockTimeout) {
+ RLock lock = getLock(key);
+ try {
+ // 尝试拿锁 lockTimeout 后停止重试,返回false
+ // 具有Watch Dog 自动延期机制 默认续30s
+ return lock.tryLock(lockTimeout, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return false;
+ }
+ }
+
+ public Long lockReleaseTime(String key) {
+ RLock lock = getLock(key);
+ if (lock.isLocked()) {
+ return lock.remainTimeToLive();
+ }
+ return 0L;
+ }
+
+ public void unlock(String key) {
+ RLock lock = getLock(key);
+ try {
+ if (lock.isLocked()) {
+ lock.unlock();
+ }
+ } catch (Exception e) {
+ log.error("unlock failed, lock: {}", lock.getName(), e);
+ }
+ }
+
+ public void forceUnlock(String key) {
+ RLock lock = getLock(key);
+ try {
+ if (lock.isLocked()) {
+ lock.forceUnlock();
+ }
+ } catch (Exception e) {
+ log.error("forceUnlock failed, lock: {}", lock.getName(), e);
+ }
+ }
+
+ private RLock getLock(String key) {
+ return client.getLock(appendLockKey(key));
+ }
+
+ private String appendLockKey(String key) {
+ return String.format("%s:lock:%s", application, key);
+ }
+}
diff --git a/carp-examples/pom.xml b/carp-examples/pom.xml
index f07b7880..70b67b34 100644
--- a/carp-examples/pom.xml
+++ b/carp-examples/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-examples
diff --git a/carp-framework/carp-framework-biz/pom.xml b/carp-framework/carp-framework-biz/pom.xml
new file mode 100644
index 00000000..d1feda48
--- /dev/null
+++ b/carp-framework/carp-framework-biz/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+
+ 4.0.0
+
+ cn.sliew
+ carp-framework
+ 0.0.13-SNAPSHOT
+ ../pom.xml
+
+ carp-framework-biz
+
+
+
+ ${project.parent.groupId}
+ carp-framework-mybatis
+
+
+
+ com.alibaba
+ easyexcel
+ provided
+
+
+
+ jakarta.validation
+ jakarta.validation-api
+ provided
+
+
+
+
+
\ No newline at end of file
diff --git a/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/annotation/ExcelImage.java b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/annotation/ExcelImage.java
new file mode 100644
index 00000000..2bdffb02
--- /dev/null
+++ b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/annotation/ExcelImage.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.biz.ext.easyexcel.annotation;
+
+import com.alibaba.excel.metadata.data.ClientAnchorData;
+
+import java.lang.annotation.*;
+
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExcelImage {
+
+ boolean isMultiple() default false;
+
+ ClientAnchorData.AnchorType anchorType() default ClientAnchorData.AnchorType.MOVE_AND_RESIZE;
+}
diff --git a/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/converters/DictConverter.java b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/converters/DictConverter.java
new file mode 100644
index 00000000..84c904a6
--- /dev/null
+++ b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/converters/DictConverter.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.biz.ext.easyexcel.converters;
+
+import cn.sliew.carp.framework.common.dict.*;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.exception.ExcelDataConvertException;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+
+import java.util.Objects;
+import java.util.Optional;
+
+public class DictConverter implements Converter {
+
+ private DictRegistry dictRegistry = EnumDictRegistry.INSTANCE;
+
+ @Override
+ public Class> supportJavaTypeKey() {
+ return DictInstance.class;
+ }
+
+ @Override
+ public CellDataTypeEnum supportExcelTypeKey() {
+ return CellDataTypeEnum.STRING;
+ }
+
+ @Override
+ public DictInstance convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
+ String value = cellData.getStringValue();
+ try {
+ Dict dictEnum = contentProperty.getField().getAnnotation(Dict.class);
+ if (Objects.nonNull(dictEnum) && Objects.nonNull(value)) {
+ String code = dictEnum.code();
+ Optional optional = dictRegistry.getDictDefinition(code);
+ if (optional.isEmpty()) {
+ throw new ExcelDataConvertException(cellData.getRowIndex(), cellData.getColumnIndex(), cellData, contentProperty, "unknown dict code");
+ }
+ Optional dictInstance = dictRegistry.getDictInstance(optional.get(), value);
+ if (dictInstance.isEmpty()) {
+ throw new ExcelDataConvertException(cellData.getRowIndex(), cellData.getColumnIndex(), cellData, contentProperty, "unknown dict instance code");
+ }
+ return dictInstance.get();
+ }
+ throw new ExcelDataConvertException(cellData.getRowIndex(), cellData.getColumnIndex(), cellData, contentProperty, "field must contains Dict annotation");
+ } catch (Exception e) {
+ throw new ExcelDataConvertException(cellData.getRowIndex(), cellData.getColumnIndex(), cellData, contentProperty, e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public WriteCellData> convertToExcelData(DictInstance value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
+ return new WriteCellData(value.getValue());
+ }
+}
diff --git a/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/handler/ImageCellWriteHandler.java b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/handler/ImageCellWriteHandler.java
new file mode 100644
index 00000000..6d937118
--- /dev/null
+++ b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/easyexcel/handler/ImageCellWriteHandler.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.biz.ext.easyexcel.handler;
+
+import cn.hutool.http.HttpUtil;
+import cn.sliew.carp.framework.biz.ext.easyexcel.annotation.ExcelImage;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.metadata.data.CellData;
+import com.alibaba.excel.metadata.data.ImageData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.write.handler.CellWriteHandler;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.util.Units;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 使用时需注册一下,才能生效
+ */
+public class ImageCellWriteHandler implements CellWriteHandler {
+
+ private List repeats = new ArrayList<>();
+
+ @Override
+ public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
+
+ }
+
+ @Override
+ public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
+
+ }
+
+ @Override
+ public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData> cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
+ // 在数据转换成功后 不是 Head 就把类型设置成空
+ if (isHead) {
+ return;
+ }
+ //将要插入图片的单元格的type设置为空,下面再填充图片
+ Object data = cellData.getData();
+ if (cellData.getImageDataList() != null || data instanceof ArrayList) {
+ cellData.setType(CellDataTypeEnum.EMPTY);
+ return;
+ }
+ // 写入图片
+ handlerExcelImage(cellData, cell, head);
+ }
+
+ private void handlerExcelImage(WriteCellData> cellData, Cell cell, Head head) {
+ ExcelImage excelImage = head.getField().getAnnotation(ExcelImage.class);
+ String stringValue = cellData.getStringValue();
+ if (Objects.nonNull(excelImage) && Objects.nonNull(stringValue)) {
+ //处理单张图片
+ if (!excelImage.isMultiple()) {
+ cellData.setType(CellDataTypeEnum.RICH_TEXT_STRING);
+ ImageData imageData = downloadImageData(stringValue, excelImage);
+ if (Objects.nonNull(imageData)) {
+ cellData.setImageDataList(Collections.singletonList(imageData));
+ }
+ } else {
+ cellData.setType(CellDataTypeEnum.EMPTY);
+ // 默认使用 , 分割
+ List list = Arrays.asList(stringValue.replace(",", ",").split(","));
+ Sheet sheet = cell.getSheet();
+ int maxColumnWidth = Math.max(sheet.getColumnWidth(cell.getColumnIndex()), 240 * 8 * list.size());
+ sheet.setColumnWidth(cell.getColumnIndex(), maxColumnWidth);
+ List imageDataList = list.stream()
+ .map(u -> downloadImageData(u, excelImage))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ for (int i = 0; i < imageDataList.size(); i++) {
+ insertImage(sheet, cell, imageDataList.get(i).getImage(), i);
+ }
+ }
+ }
+ }
+
+ private ImageData downloadImageData(String strUrl, ExcelImage excelImage) {
+ byte[] bytes = HttpUtil.downloadBytes(strUrl);
+ ImageData imageData = new ImageData();
+ imageData.setImage(bytes);
+ imageData.setAnchorType(excelImage.anchorType());
+ return imageData;
+ }
+
+ @Override
+ public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
+ // 在单元格写入完毕后,自己填充图片
+ if (isHead || CollectionUtils.isEmpty(cellDataList)) {
+ return;
+ }
+ WriteCellData> writeCellData = cellDataList.get(0);
+ if (writeCellData.getData() != null && writeCellData.getData() instanceof ArrayList) {
+ String key = cell.getRowIndex() + "_" + cell.getColumnIndex();
+ if (repeats.contains(key)) {
+ return;
+ }
+ repeats.add(key);
+ List> cellDatas = (List>) writeCellData.getData();
+ Sheet sheet = cell.getSheet();
+ sheet.getRow(cell.getRowIndex()).setHeight((short) 900);
+ int maxColumnWidth = Math.max(sheet.getColumnWidth(cell.getColumnIndex()), 240 * 8 * cellDatas.size());
+ sheet.setColumnWidth(cell.getColumnIndex(), maxColumnWidth);
+ for (int i = 0; i < cellDatas.size(); i++) {
+ insertImage(sheet, cell, cellDatas.get(i).getData(), i);
+ }
+ }
+ }
+
+ private void insertImage(Sheet sheet, Cell cell, byte[] pictureData, int i) {
+ int picWidth = Units.pixelToEMU(60);
+ int index = sheet.getWorkbook().addPicture(pictureData, HSSFWorkbook.PICTURE_TYPE_PNG);
+ Drawing drawing = sheet.getDrawingPatriarch();
+ if (drawing == null) {
+ drawing = sheet.createDrawingPatriarch();
+ }
+ CreationHelper helper = sheet.getWorkbook().getCreationHelper();
+ ClientAnchor anchor = helper.createClientAnchor();
+ // 设置图片坐标
+ anchor.setDx1(picWidth * i);
+ anchor.setDx2(picWidth + picWidth * i);
+ anchor.setDy1(0);
+ anchor.setDy2(0);
+ //设置图片位置
+ anchor.setCol1(cell.getColumnIndex());
+ anchor.setCol2(cell.getColumnIndex());
+ anchor.setRow1(cell.getRowIndex());
+ anchor.setRow2(cell.getRowIndex() + 1);
+
+ // 设置图片可以随着单元格移动
+ anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
+ drawing.createPicture(anchor, index);
+ }
+}
+
diff --git a/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mapstruct/EntityConvert.java b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mapstruct/EntityConvert.java
new file mode 100644
index 00000000..6f2587a1
--- /dev/null
+++ b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mapstruct/EntityConvert.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.biz.ext.mapstruct;
+
+import cn.sliew.carp.framework.mybatis.entity.BaseAuditDO;
+import org.mapstruct.AfterMapping;
+import org.mapstruct.MappingTarget;
+
+public interface EntityConvert {
+
+ @AfterMapping
+ default void fillAudit(@MappingTarget BaseAuditDO auditDO) {
+
+ }
+}
diff --git a/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mybatis/AbstractEncryptTypeHandler.java b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mybatis/AbstractEncryptTypeHandler.java
new file mode 100644
index 00000000..375a7a32
--- /dev/null
+++ b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mybatis/AbstractEncryptTypeHandler.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.biz.ext.mybatis;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.StringTypeHandler;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public abstract class AbstractEncryptTypeHandler extends StringTypeHandler {
+
+ @Override
+ public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
+ super.setNonNullParameter(ps, i, encrypt(parameter), jdbcType);
+ }
+
+ @Override
+ public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
+ String nullableResult = super.getNullableResult(rs, columnName);
+ if (StringUtils.isNotBlank(nullableResult)) {
+ return decrypt(nullableResult);
+ }
+ return nullableResult;
+ }
+
+ @Override
+ public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+ String nullableResult = super.getNullableResult(rs, columnIndex);
+ if (StringUtils.isNotBlank(nullableResult)) {
+ return decrypt(nullableResult);
+ }
+ return nullableResult;
+ }
+
+ @Override
+ public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+ String nullableResult = super.getNullableResult(cs, columnIndex);
+ if (StringUtils.isNotBlank(nullableResult)) {
+ return decrypt(nullableResult);
+ }
+ return nullableResult;
+ }
+
+ protected abstract String encrypt(String input);
+
+ protected abstract String decrypt(String input);
+}
diff --git a/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mybatis/AesEncryptTypeHandler.java b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mybatis/AesEncryptTypeHandler.java
new file mode 100644
index 00000000..5a6afbe3
--- /dev/null
+++ b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/mybatis/AesEncryptTypeHandler.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.biz.ext.mybatis;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.crypto.SecureUtil;
+
+public class AesEncryptTypeHandler extends AbstractEncryptTypeHandler {
+
+ @Override
+ protected String encrypt(String input) {
+ byte[] encrypt = SecureUtil.aes().encrypt(input);
+ return Base64.encode(encrypt);
+ }
+
+ @Override
+ protected String decrypt(String input) {
+ byte[] decrypt = SecureUtil.aes().decrypt(Base64.decode(input));
+ return new String(decrypt, CharsetUtil.CHARSET_UTF_8);
+ }
+}
diff --git a/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/validation/DictConstraint.java b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/validation/DictConstraint.java
new file mode 100644
index 00000000..4c685633
--- /dev/null
+++ b/carp-framework/carp-framework-biz/src/main/java/cn/sliew/carp/framework/biz/ext/validation/DictConstraint.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.biz.ext.validation;
+
+import cn.sliew.carp.framework.common.dict.DictDefinition;
+import cn.sliew.carp.framework.common.dict.EnumDictRegistry;
+import jakarta.validation.Constraint;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+import java.util.Objects;
+import java.util.Optional;
+
+@Documented
+@Constraint(validatedBy = DictConstraint.DictValidator.class)
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DictConstraint {
+
+ String message() default "";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ String dict();
+
+ class DictValidator implements ConstraintValidator {
+
+ private DictConstraint constraint;
+
+ @Override
+ public void initialize(DictConstraint constraint) {
+ this.constraint = constraint;
+ }
+
+ @Override
+ public boolean isValid(String value, ConstraintValidatorContext context) {
+ if (Objects.isNull(constraint.dict()) || Objects.isNull(value)) {
+ context.buildConstraintViolationWithTemplate("[Dict Instance] is invalid").addConstraintViolation();
+ return false;
+ }
+
+ Optional optional = EnumDictRegistry.INSTANCE.getDictDefinition(constraint.dict());
+ if (optional.isEmpty()) {
+ context.buildConstraintViolationWithTemplate("[Dict] is invalid").addConstraintViolation();
+ return false;
+ }
+ if (EnumDictRegistry.INSTANCE.exists(optional.get(), value) == false) {
+ context.buildConstraintViolationWithTemplate("[Dict Instance] is invalid").addConstraintViolation();
+ return false;
+ }
+ return true;
+ }
+ }
+
+
+}
diff --git a/carp-framework/carp-framework-common/pom.xml b/carp-framework/carp-framework-common/pom.xml
index 8da24013..20a71f67 100644
--- a/carp-framework/carp-framework-common/pom.xml
+++ b/carp-framework/carp-framework-common/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-framework
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-framework-common
@@ -72,6 +72,11 @@
zjsonpatch
+
+ org.ow2.asm
+ asm
+
+
cn.sliewmilky-common
diff --git a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/Dict.java b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/Dict.java
new file mode 100644
index 00000000..549f986e
--- /dev/null
+++ b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/Dict.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.common.dict;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface Dict {
+
+ String code();
+}
diff --git a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/DictType.java b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/DictType.java
index 7981d8b4..2c939864 100644
--- a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/DictType.java
+++ b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/DictType.java
@@ -25,6 +25,7 @@
import cn.sliew.carp.framework.common.dict.datasource.RedisMode;
import cn.sliew.carp.framework.common.dict.k8s.ClusterStatus;
import cn.sliew.carp.framework.common.dict.k8s.ClusterType;
+import cn.sliew.carp.framework.common.dict.license.LicenseType;
import cn.sliew.carp.framework.common.dict.oam.AppType;
import cn.sliew.carp.framework.common.dict.schedule.ScheduleEngineType;
import cn.sliew.carp.framework.common.dict.schedule.ScheduleJobType;
@@ -44,6 +45,8 @@ public enum DictType implements DictDefinition {
YES_OR_NO("yes_or_no", "是否", YesOrNo.class),
IS_DELETED("is_delete", "是否删除", IsDeleted.class),
+ LICENSE_TYPE("license_type", "证书类型", LicenseType.class),
+
K8S_CLUSTER_TYPE("k8s_cluster_type", "集群类型", ClusterType.class),
K8S_CLUSTER_STATUS("k8s_cluster_status", "集群状态", ClusterStatus.class),
diff --git a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/license/LicenseType.java b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/license/LicenseType.java
new file mode 100644
index 00000000..2c2bc42d
--- /dev/null
+++ b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/dict/license/LicenseType.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.common.dict.license;
+
+import cn.sliew.carp.framework.common.dict.DictInstance;
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.util.Arrays;
+
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum LicenseType implements DictInstance {
+
+ TRIAL("trial", "试用"),
+ PRO("pro", "专业版"),
+ ENTERPRISE("enterprise", "企业版"),
+ ;
+
+ @JsonCreator
+ public static LicenseType of(String value) {
+ return Arrays.stream(values())
+ .filter(instance -> instance.getValue().equals(value))
+ .findAny().orElseThrow(() -> new EnumConstantNotPresentException(LicenseType.class, value));
+ }
+
+ @EnumValue
+ private String value;
+ private String label;
+
+ LicenseType(String value, String label) {
+ this.value = value;
+ this.label = label;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public String getLabel() {
+ return label;
+ }
+}
diff --git a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/model/IdListParam.java b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/model/IdListParam.java
new file mode 100644
index 00000000..c8a2d131
--- /dev/null
+++ b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/model/IdListParam.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.common.model;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+
+@Data
+public class IdListParam {
+
+ @Schema(description = "ids")
+ @Nonnull
+ private List ids;
+}
diff --git a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/model/IdParam.java b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/model/IdParam.java
new file mode 100644
index 00000000..b22434b7
--- /dev/null
+++ b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/model/IdParam.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.common.model;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.annotation.Nonnull;
+
+@Data
+public class IdParam {
+
+ @Schema(description = "id")
+ @Nonnull
+ private Long id;
+}
diff --git a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/AbstractJobDetailsFinder.java b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/AbstractJobDetailsFinder.java
new file mode 100644
index 00000000..e273245a
--- /dev/null
+++ b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/AbstractJobDetailsFinder.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.common.reflection;
+
+import cn.sliew.carp.framework.common.reflection.instructions.*;
+import cn.sliew.carp.framework.common.reflection.lambdas.JobRunrJob;
+import cn.sliew.carp.framework.common.util.reflection.JarUtils;
+import org.objectweb.asm.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+abstract class AbstractJobDetailsFinder extends ClassVisitor {
+
+ protected final JobDetailsBuilder jobDetailsBuilder;
+
+ protected AbstractJobDetailsFinder(JobDetailsBuilder jobDetailsBuilder) {
+ super(Opcodes.ASM7);
+ this.jobDetailsBuilder = jobDetailsBuilder;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
+ if (isLambdaContainingJobDetails(name)) {
+ return new MethodVisitor(Opcodes.ASM7) {
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
+ VisitFieldInstruction instruction = AllJVMInstructions.get(opcode, jobDetailsBuilder);
+ instruction.load(owner, name, descriptor);
+ }
+
+ @Override
+ public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
+ InvokeDynamicInstruction instruction = AllJVMInstructions.get(Opcodes.INVOKEDYNAMIC, jobDetailsBuilder);
+ instruction.load(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
+ VisitMethodInstruction visitMethodInstruction = AllJVMInstructions.get(opcode, jobDetailsBuilder);
+ visitMethodInstruction.load(owner, name, descriptor, isInterface);
+ }
+
+ @Override
+ public void visitInsn(int opcode) {
+ ZeroOperandInstruction zeroOperandInstruction = AllJVMInstructions.get(opcode, jobDetailsBuilder);
+ zeroOperandInstruction.load();
+ }
+
+ @Override
+ public void visitVarInsn(int opcode, int variable) {
+ VisitLocalVariableInstruction instruction = AllJVMInstructions.get(opcode, jobDetailsBuilder);
+ instruction.load(variable);
+ }
+
+ @Override
+ public void visitIntInsn(int opcode, int operand) {
+ SingleIntOperandInstruction singleIntOperandInstruction = AllJVMInstructions.get(opcode, jobDetailsBuilder);
+ singleIntOperandInstruction.load(operand);
+ }
+
+ @Override
+ public void visitLdcInsn(Object value) {
+ LdcInstruction ldcInstruction = AllJVMInstructions.get(Opcodes.LDC, jobDetailsBuilder);
+ ldcInstruction.load(value);
+ }
+
+ @Override
+ public void visitTypeInsn(int opcode, String type) {
+ VisitTypeInstruction instruction = AllJVMInstructions.get(opcode, jobDetailsBuilder);
+ instruction.load(type);
+ }
+ };
+ } else {
+ return super.visitMethod(access, name, descriptor, signature, exceptions);
+ }
+ }
+
+ protected abstract boolean isLambdaContainingJobDetails(String name);
+
+ protected abstract InputStream getClassContainingLambdaAsInputStream();
+
+ public JobDetails getJobDetails() {
+ return jobDetailsBuilder.getJobDetails();
+ }
+
+ protected void parse(InputStream inputStream) throws IOException {
+ try {
+ ClassReader parser = new ClassReader(inputStream);
+ parser.accept(this, ClassReader.SKIP_FRAMES);
+ } catch (IllegalArgumentException e) {
+ if(e.getMessage().startsWith("Unsupported class file")) {
+ String requiredAsmVersion = JarUtils.getManifestAttributeValue(JobRunrJob.class, "Minimum-ASM-Version");
+ String actualAsmVersion = JarUtils.getVersion(Opcodes.class);
+ throw new IllegalArgumentException("JobRunr needs (and automatically adds) ASM " + requiredAsmVersion + " as a transitive dependency but you have ASM " + actualAsmVersion + " on the classpath.", e);
+ }
+ throw e;
+ }
+ }
+
+}
diff --git a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/CachingJobDetailsGenerator.java b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/CachingJobDetailsGenerator.java
new file mode 100644
index 00000000..f504d637
--- /dev/null
+++ b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/CachingJobDetailsGenerator.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.common.reflection;
+
+import cn.sliew.carp.framework.common.reflection.lambdas.IocJobLambda;
+import cn.sliew.carp.framework.common.reflection.lambdas.JobLambda;
+import cn.sliew.carp.framework.common.reflection.lambdas.JobRunrJob;
+import cn.sliew.carp.framework.common.util.reflection.ReflectionUtils;
+import cn.sliew.milky.common.exception.Rethrower;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import static java.lang.Boolean.TRUE;
+import static java.util.Arrays.asList;
+import static java.util.Arrays.stream;
+import static java.util.Collections.emptyList;
+
+public class CachingJobDetailsGenerator implements JobDetailsGenerator {
+
+ private final JobDetailsGenerator delegate;
+ private final Map, CacheableJobDetails> cache;
+
+ public CachingJobDetailsGenerator() {
+ this(new JobDetailsAsmGenerator());
+ }
+
+ public CachingJobDetailsGenerator(JobDetailsGenerator delegate) {
+ this.delegate = delegate;
+ this.cache = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public JobDetails toJobDetails(JobLambda lambda) {
+ return cache
+ .computeIfAbsent(lambda.getClass(), clazz -> new CacheableJobDetails(delegate))
+ .getJobDetails(lambda);
+ }
+
+ @Override
+ public JobDetails toJobDetails(IocJobLambda> lambda) {
+ return cache
+ .computeIfAbsent(lambda.getClass(), clazz -> new CacheableJobDetails(delegate))
+ .getJobDetails(lambda);
+ }
+
+ private static class CacheableJobDetails {
+
+ private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
+ private final JobDetailsGenerator jobDetailsGeneratorDelegate;
+ private volatile JobDetails jobDetails;
+ private List jobParameterRetrievers;
+
+ private CacheableJobDetails(JobDetailsGenerator jobDetailsGeneratorDelegate) {
+ this.jobDetailsGeneratorDelegate = jobDetailsGeneratorDelegate;
+ }
+
+ public JobDetails getJobDetails(JobLambda lambda) {
+ return initOrGetJobDetails(
+ () -> jobDetailsGeneratorDelegate.toJobDetails(lambda),
+ () -> initJobParameterRetrievers(jobDetails, lambda, Optional.empty()),
+ () -> getCachedJobDetails(lambda, Optional.empty()));
+ }
+
+ public JobDetails getJobDetails(IocJobLambda> lambda) {
+ return initOrGetJobDetails(
+ () -> jobDetailsGeneratorDelegate.toJobDetails(lambda),
+ () -> initJobParameterRetrievers(jobDetails, lambda, Optional.empty()),
+ () -> getCachedJobDetails(lambda, Optional.empty()));
+ }
+
+ private JobDetails initOrGetJobDetails(Supplier jobDetailsSupplier, Supplier> jobParameterRetrieverSupplier, Supplier getJobDetailsUsingCache) {
+ if (this.jobDetails == null) {
+ JobDetails jobDetails = initJobDetails(jobDetailsSupplier, jobParameterRetrieverSupplier);
+ if (jobDetails != null) return jobDetails;
+ }
+
+ if (TRUE.equals(this.jobDetails.getCacheable())) {
+ return getJobDetailsUsingCache.get();
+ } else {
+ return jobDetailsSupplier.get();
+ }
+ }
+
+ /**
+ * On first initialization, this creates the JobDetails, determines whether it is cacheable and returns it.
+ *
+ * @param jobDetailsSupplier a Supplier to use when the {@link JobDetails} are null.
+ * @param jobParameterRetrieverSupplier a Supplier to use when the List of {@link JobParameterRetriever JobParameterRetrievers} are null.
+ * @return JobDetails if it was just initialized, null otherwise.
+ */
+ private synchronized JobDetails initJobDetails(Supplier jobDetailsSupplier, Supplier> jobParameterRetrieverSupplier) {
+ if (this.jobDetails == null) {
+ this.jobDetails = jobDetailsSupplier.get();
+ jobParameterRetrievers = jobParameterRetrieverSupplier.get();
+ return this.jobDetails;
+ }
+ return null;
+ }
+
+ private static List initJobParameterRetrievers(JobDetails jobDetails, JobRunrJob jobRunrJob, Optional itemFromStream) {
+ try {
+ List parameterRetrievers = new ArrayList<>();
+ List declaredFields = new ArrayList<>(asList(jobRunrJob.getClass().getDeclaredFields()));
+ List jobParameters = jobDetails.getJobParameters();
+
+ if (isParentClassPassedAsFieldToPassJobDetailsClass(declaredFields, jobDetails)
+ || isClassPassedAsFieldToPassJobDetailsClass(declaredFields, jobDetails)) {
+ declaredFields.remove(0);
+ }
+
+ for (JobParameter jp : jobParameters) {
+ parameterRetrievers.add(createJobParameterRetriever(jp, jobRunrJob, itemFromStream, declaredFields));
+ }
+
+ jobDetails.setCacheable(
+ declaredFields.isEmpty()
+ && jobParameters.size() == parameterRetrievers.size()
+ && (!itemFromStream.isPresent() || parameterRetrievers.stream().anyMatch(r -> r instanceof ItemFromStreamJobParameterRetriever))
+ );
+ return parameterRetrievers;
+ } catch (Exception e) {
+ jobDetails.setCacheable(false);
+ return emptyList();
+ }
+ }
+
+
+ private static boolean isParentClassPassedAsFieldToPassJobDetailsClass(List declaredFields, JobDetails jobDetails) {
+ if (declaredFields.isEmpty()) return false;
+
+ Class> jobDetailsClass = ReflectionUtils.toClass(jobDetails.getClassName());
+
+ return stream(declaredFields.get(0).getType().getDeclaredFields())
+ .map(Field::getType)
+ .anyMatch(x -> x.isAssignableFrom(jobDetailsClass));
+ }
+
+ private static boolean isClassPassedAsFieldToPassJobDetailsClass(List declaredFields, JobDetails jobDetails) {
+ if (declaredFields.isEmpty()) return false;
+
+ return declaredFields.get(0).getType().getName().equals(jobDetails.getClassName());
+ }
+
+ private static JobParameterRetriever createJobParameterRetriever(JobParameter jp, JobRunrJob jobRunrJob, Optional itemFromStream, List declaredFields) throws IllegalAccessException {
+ JobParameterRetriever jobParameterRetriever = new FixedJobParameterRetriever(jp);
+ if (itemFromStream.isPresent() && jp.getObject().equals(itemFromStream.get())) {
+ jobParameterRetriever = new ItemFromStreamJobParameterRetriever(jp);
+ } else {
+ final ListIterator fieldIterator = declaredFields.listIterator();
+ while (fieldIterator.hasNext()) {
+ Field f = fieldIterator.next();
+ Object valueFromField = ReflectionUtils.getValueFromField(f, jobRunrJob);
+ if (jp.getObject().equals(valueFromField)) {
+ MethodHandle e = lookup.unreflectGetter(f);
+ jobParameterRetriever = new MethodHandleJobParameterRetriever(jp, e.asType(e.type().generic()));
+ fieldIterator.remove();
+ break;
+ }
+ }
+ }
+ return jobParameterRetriever;
+ }
+
+ private JobDetails getCachedJobDetails(JobRunrJob job, Optional itemFromStream) {
+ final JobDetails cachedJobDetails = new JobDetails(
+ this.jobDetails.getClassName(),
+ this.jobDetails.getStaticFieldName(),
+ this.jobDetails.getMethodName(),
+ jobParameterRetrievers.stream()
+ .map(jobParameterRetriever -> jobParameterRetriever.getJobParameter(job, itemFromStream))
+ .collect(Collectors.toList())
+ );
+ cachedJobDetails.setCacheable(true);
+ return cachedJobDetails;
+ }
+ }
+
+ private interface JobParameterRetriever {
+ JobParameter getJobParameter(JobRunrJob job, Optional itemFromStream);
+ }
+
+ private static class FixedJobParameterRetriever implements JobParameterRetriever {
+
+ private final JobParameter jobParameter;
+
+ public FixedJobParameterRetriever(JobParameter jobParameter) {
+ this.jobParameter = jobParameter;
+ }
+
+ @Override
+ public JobParameter getJobParameter(JobRunrJob job, Optional itemFromStream) {
+ return jobParameter;
+ }
+ }
+
+ private static class MethodHandleJobParameterRetriever implements JobParameterRetriever {
+
+ private final String jobParameterClassName;
+ private final MethodHandle methodHandle;
+
+ public MethodHandleJobParameterRetriever(JobParameter jobParameter, MethodHandle methodHandle) {
+ this.jobParameterClassName = jobParameter.getClassName();
+ this.methodHandle = methodHandle;
+ }
+
+ @Override
+ public JobParameter getJobParameter(JobRunrJob job, Optional itemFromStream) {
+ try {
+ Object o = methodHandle.invokeExact((Object) job);
+ return new JobParameter(jobParameterClassName, o);
+ } catch (Throwable throwable) {
+ Rethrower.throwAs(throwable);
+ return null;
+ }
+ }
+ }
+
+ private static class ItemFromStreamJobParameterRetriever implements JobParameterRetriever {
+
+ private final String jobParameterClassName;
+
+ public ItemFromStreamJobParameterRetriever(JobParameter jobParameter) {
+ this.jobParameterClassName = jobParameter.getClassName();
+ }
+
+ @Override
+ public JobParameter getJobParameter(JobRunrJob job, Optional itemFromStream) {
+ return new JobParameter(jobParameterClassName, itemFromStream.orElseThrow(() -> new IllegalStateException("Can not find itemFromStream")));
+ }
+ }
+}
diff --git a/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/JavaJobDetailsBuilder.java b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/JavaJobDetailsBuilder.java
new file mode 100644
index 00000000..56b9234a
--- /dev/null
+++ b/carp-framework/carp-framework-common/src/main/java/cn/sliew/carp/framework/common/reflection/JavaJobDetailsBuilder.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.common.reflection;
+
+import cn.sliew.carp.framework.common.reflection.lambdas.IocJobLambda;
+
+import java.lang.invoke.MethodHandleInfo;
+import java.lang.invoke.SerializedLambda;
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.Arrays.asList;
+
+public class JavaJobDetailsBuilder extends JobDetailsBuilder {
+
+ public JavaJobDetailsBuilder(SerializedLambda serializedLambda, Object... params) {
+ super(initLocalVariables(serializedLambda, params), JobDetailsGeneratorUtils.toFQClassName(serializedLambda.getImplClass()), serializedLambda.getImplMethodName());
+ }
+
+ protected static List
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
\ No newline at end of file
diff --git a/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/concurrent/MetricsTaskDecorator.java b/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/concurrent/MetricsTaskDecorator.java
new file mode 100644
index 00000000..446cf631
--- /dev/null
+++ b/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/concurrent/MetricsTaskDecorator.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.spring.concurrent;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.Timer;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.StopWatch;
+import org.springframework.core.task.TaskDecorator;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class MetricsTaskDecorator implements TaskDecorator {
+
+ private List tags;
+ private MeterRegistry meterRegistry;
+
+ public MetricsTaskDecorator(List tags, MeterRegistry meterRegistry) {
+ this.tags = tags;
+ this.meterRegistry = meterRegistry;
+ }
+
+ @Override
+ public Runnable decorate(Runnable runnable) {
+ return new JobMetricsRunnable(runnable);
+ }
+
+ private class JobMetricsRunnable implements Runnable {
+
+ private final Runnable task;
+
+ private JobMetricsRunnable(Runnable task) {
+ this.task = task;
+ }
+
+ @Override
+ public void run() {
+ try {
+ StopWatch stopWatch = StopWatch.createStarted();
+ task.run();
+ stopWatch.stop();
+ recordTaskCostTime(stopWatch.getTime(TimeUnit.MILLISECONDS));
+ } catch (Throwable e) {
+ log.error("failed to run! task: {}", task.toString(), e);
+ }
+ }
+
+ private void recordTaskCostTime(long costInMills) {
+ if (meterRegistry != null) {
+ try {
+ Timer.builder("job_thread_pool_tasks")
+ .tags(tags)
+ .publishPercentileHistogram(true)
+ .register(meterRegistry)
+ .record(costInMills, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ log.warn("Fail to record thread pool task timer metrics", e);
+ }
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return task.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return task.equals(obj);
+ }
+
+ @Override
+ public String toString() {
+ return "[task-executor-wrapper] task: " + task.toString();
+ }
+ }
+}
diff --git a/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/concurrent/MetricsThreadPoolExecutor.java b/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/concurrent/MetricsThreadPoolExecutor.java
new file mode 100644
index 00000000..8366fe35
--- /dev/null
+++ b/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/concurrent/MetricsThreadPoolExecutor.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.spring.concurrent;
+
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
+import io.micrometer.core.instrument.Timer;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class MetricsThreadPoolExecutor extends ThreadPoolTaskExecutor {
+
+ /**
+ * 任务开始时间
+ */
+ private final ThreadLocal startTimeThreadLocal = new ThreadLocal<>();
+
+ private MeterRegistry meterRegistry;
+
+ private List tags;
+
+ @Override
+ public void initialize() {
+ super.initialize();
+ enableMetrics(getThreadNamePrefix());
+ }
+
+ private void enableMetrics(String poolName) {
+ this.tags = Collections.singletonList(Tag.of("pool_name", poolName));
+ startWatch();
+ }
+
+ private void startWatch() {
+ meterRegistry.gauge("job_thread_pool_active_thread_size",
+ getTags(),
+ this,
+ threadPoolExecutor -> (double) threadPoolExecutor.getActiveCount());
+ meterRegistry.gauge("job_thread_pool_pool_size",
+ getTags(),
+ this,
+ threadPoolExecutor -> (double) threadPoolExecutor.getPoolSize());
+ meterRegistry.gauge("job_thread_pool_core_pool_size",
+ getTags(),
+ this,
+ threadPoolExecutor -> (double) threadPoolExecutor.getCorePoolSize());
+ meterRegistry.gauge("job_thread_pool_max_pool_size",
+ getTags(),
+ this,
+ threadPoolExecutor -> (double) threadPoolExecutor.getMaxPoolSize());
+ meterRegistry.gauge("job_thread_pool_task_total",
+ getTags(),
+ this,
+ threadPoolExecutor -> (double) threadPoolExecutor.getThreadPoolExecutor().getTaskCount());
+ meterRegistry.gauge("job_thread_pool_completed_task_total",
+ getTags(),
+ this,
+ threadPoolExecutor -> (double) threadPoolExecutor.getThreadPoolExecutor().getCompletedTaskCount());
+ meterRegistry.gauge("job_thread_pool_queue_size",
+ getTags(),
+ this,
+ threadPoolExecutor -> (double) threadPoolExecutor.getQueueSize());
+ meterRegistry.gauge("job_thread_pool_queue_capacity",
+ getTags(),
+ this,
+ threadPoolExecutor -> (double) threadPoolExecutor.getQueueCapacity());
+ }
+
+ private List getTags() {
+ return tags;
+ }
+
+
+ /**
+ * 任务执行之前,记录任务开始时间
+ */
+ @Override
+ protected void beforeExecute(Thread t, Runnable r) {
+ startTimeThreadLocal.set(System.currentTimeMillis());
+ }
+
+ /**
+ * 任务执行之后,计算任务结束时间
+ */
+ @Override
+ protected void afterExecute(Runnable r, Throwable t) {
+ try {
+ long costTime = System.currentTimeMillis() - startTimeThreadLocal.get();
+ recordTaskCostTime(costTime);
+ } finally {
+ startTimeThreadLocal.remove();
+ }
+ }
+
+
+ private void recordTaskCostTime(long costInMills) {
+ try {
+ Timer.builder("job_thread_pool_tasks")
+ .tags(getTags())
+ .publishPercentileHistogram(true)
+ .register(meterRegistry)
+ .record(costInMills, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ log.warn("Fail to record thread pool task timer metrics", e);
+ }
+ }
+
+
+}
diff --git a/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/config/AsyncConfig.java b/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/config/AsyncConfig.java
new file mode 100644
index 00000000..857de9b2
--- /dev/null
+++ b/carp-framework/carp-framework-spring/src/main/java/cn/sliew/carp/framework/spring/config/AsyncConfig.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.spring.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+
+@Configuration
+public class AsyncConfig implements AsyncConfigurer {
+
+
+}
diff --git a/carp-framework/carp-framework-task/pom.xml b/carp-framework/carp-framework-task/pom.xml
index f9c39bd6..0d630a0b 100644
--- a/carp-framework/carp-framework-task/pom.xml
+++ b/carp-framework/carp-framework-task/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-framework
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-framework-task
@@ -37,5 +37,10 @@
${project.parent.groupId}carp-framework-exception
+
+
+ ${project.parent.groupId}
+ carp-framework-redis
+
\ No newline at end of file
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskClient.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskClient.java
new file mode 100644
index 00000000..67599f26
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskClient.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server;
+
+import cn.sliew.carp.framework.task.server.detail.TaskDetail;
+
+import java.time.Duration;
+
+public interface TaskClient {
+
+ /**
+ * fire-forget 任务,优先级任务,定时任务
+ */
+ String publish(String topic, TaskDetail task, Duration delay);
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskClientImpl.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskClientImpl.java
new file mode 100644
index 00000000..51ab0405
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskClientImpl.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server;
+
+import cn.sliew.carp.framework.task.server.broker.TaskBroker;
+import cn.sliew.carp.framework.task.server.detail.TaskDetail;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+
+@Component
+@AllArgsConstructor
+public class TaskClientImpl implements TaskClient {
+
+ private TaskBroker taskBroker;
+
+ @Override
+ public String publish(String topic, TaskDetail task, Duration delay) {
+ return taskBroker.sendTask(topic, task, delay).getId();
+ }
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskScheduler.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskScheduler.java
new file mode 100644
index 00000000..90208823
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/TaskScheduler.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server;
+
+public interface TaskScheduler {
+
+
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/TaskBroker.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/TaskBroker.java
new file mode 100644
index 00000000..718ec9e4
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/TaskBroker.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.broker;
+
+import cn.sliew.carp.framework.task.server.detail.TaskDetail;
+import cn.sliew.carp.framework.task.server.storage.StorageProvider;
+
+import java.time.Duration;
+
+public interface TaskBroker {
+
+ TaskMessage sendTask(String topic, TaskDetail taskDetail, Duration delay);
+
+ TaskMessage getTask(String topic, String id);
+
+ TaskMessage deleteTask(String topic, String id);
+
+ StorageProvider getStorageProvider();
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/TaskMessage.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/TaskMessage.java
new file mode 100644
index 00000000..829a0ad2
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/TaskMessage.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.broker;
+
+public interface TaskMessage {
+
+ String getId();
+
+ Integer getStatus();
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/DefaultTaskMessage.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/DefaultTaskMessage.java
new file mode 100644
index 00000000..d8bb65c9
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/DefaultTaskMessage.java
@@ -0,0 +1,23 @@
+package cn.sliew.carp.framework.task.server.broker.impl;
+
+import cn.sliew.carp.framework.task.server.broker.TaskMessage;
+import cn.sliew.carp.framework.task.server.detail.TaskDetail;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class DefaultTaskMessage implements TaskMessage {
+
+ private String id;
+ private Integer status;
+
+ private String topic;
+ private TaskDetail taskDetail;
+ private Long produceTime;
+ private Long triggerTime;
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/RedissonTaskBroker.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/RedissonTaskBroker.java
new file mode 100644
index 00000000..1f691293
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/RedissonTaskBroker.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.broker.impl;
+
+import cn.sliew.carp.framework.task.server.broker.TaskBroker;
+import cn.sliew.carp.framework.task.server.broker.TaskMessage;
+import cn.sliew.carp.framework.task.server.detail.TaskDetail;
+import cn.sliew.carp.framework.task.server.storage.StorageProvider;
+import cn.sliew.carp.framework.task.server.storage.TaskResultStorage;
+import cn.sliew.carp.framework.task.server.worker.impl.RedissonTaskWorker;
+import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import org.redisson.api.RScheduledExecutorService;
+import org.redisson.api.RScheduledFuture;
+import org.redisson.api.RedissonClient;
+import org.redisson.api.WorkerOptions;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+
+@Component
+@RequiredArgsConstructor
+public class RedissonTaskBroker implements TaskBroker {
+
+ private RedissonClient client;
+ private TaskStartedListenerImpl taskStartedListener;;
+ private TaskFinishedListenerImpl taskFinishedListener;
+ private TaskSuccessListenerImpl taskSuccessListener;
+ private TaskFailureListenerImpl taskFailureListener;
+
+ private ConcurrentMap executorServiceMap = new ConcurrentHashMap<>();
+
+ @Override
+ public TaskMessage sendTask(String topic, TaskDetail taskDetail, Duration delay) {
+ RScheduledExecutorService executorService = executorServiceMap.computeIfAbsent(topic, key -> buildExecutorService(key));
+
+ RScheduledFuture> future = executorService.schedule(new RedissonTaskWorker(topic, taskDetail), delay.toMillis(), TimeUnit.MILLISECONDS);
+ TaskResultStorage taskResultStorage = getStorageProvider().getTaskResultStorage();
+ // 写入任务结果
+ return getTask(topic, future.getTaskId());
+ }
+
+ @Override
+ public TaskMessage getTask(String topic, String id) {
+ RScheduledExecutorService executorService = executorServiceMap.computeIfAbsent(topic, key -> buildExecutorService(key));
+ // 读取任务结果
+ TaskResultStorage taskResultStorage = getStorageProvider().getTaskResultStorage();
+
+ return null;
+ }
+
+ @Override
+ public TaskMessage deleteTask(String topic, String id) {
+ RScheduledExecutorService executorService = client.getExecutorService(topic);
+ executorService.cancelTask(id);
+ TaskMessage taskMessage = getTask(topic, id);
+
+ // 更新为被删除任务信息
+ TaskResultStorage taskResultStorage = getStorageProvider().getTaskResultStorage();
+ return taskMessage;
+ }
+
+ @Override
+ public StorageProvider getStorageProvider() {
+ return null;
+ }
+
+ private RScheduledExecutorService buildExecutorService(String topic) {
+ RScheduledExecutorService executorService = client.getExecutorService(topic);
+ WorkerOptions workerOptions = WorkerOptions.defaults()
+ .workers(2)
+ .taskTimeout(60, TimeUnit.SECONDS)
+ .addListener(taskStartedListener)
+ .addListener(taskFinishedListener)
+ .addListener(taskSuccessListener)
+ .addListener(taskFailureListener);
+ executorService.registerWorkers(workerOptions);
+ return executorService;
+ }
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskFailureListenerImpl.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskFailureListenerImpl.java
new file mode 100644
index 00000000..32a54ef3
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskFailureListenerImpl.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.broker.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.executor.TaskFailureListener;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class TaskFailureListenerImpl implements TaskFailureListener {
+
+ @Override
+ public void onFailed(String taskId, Throwable exception) {
+ log.error("redisson failed, taskId: {}", taskId, exception);
+ }
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskFinishedListenerImpl.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskFinishedListenerImpl.java
new file mode 100644
index 00000000..52052757
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskFinishedListenerImpl.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.broker.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.executor.TaskFinishedListener;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class TaskFinishedListenerImpl implements TaskFinishedListener {
+
+ @Override
+ public void onFinished(String taskId) {
+ log.info("redisson finished, taskId: {}", taskId);
+ }
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskStartedListenerImpl.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskStartedListenerImpl.java
new file mode 100644
index 00000000..dd74889c
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskStartedListenerImpl.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.broker.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.executor.TaskStartedListener;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class TaskStartedListenerImpl implements TaskStartedListener {
+
+ @Override
+ public void onStarted(String taskId) {
+ log.info("redisson started, taskId: {}", taskId);
+ }
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskSuccessListenerImpl.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskSuccessListenerImpl.java
new file mode 100644
index 00000000..38b3b3a4
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/broker/impl/TaskSuccessListenerImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.broker.impl;
+
+import cn.sliew.milky.common.util.JacksonUtil;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.executor.TaskSuccessListener;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Slf4j
+@Component
+public class TaskSuccessListenerImpl implements TaskSuccessListener {
+
+ private Map taskResultRepository = Maps.newHashMap();
+
+ @Override
+ public void onSucceeded(String taskId, T result) {
+ taskResultRepository.put(taskId, result);
+ log.info("redisson success, taskId: {}, result: {}", taskId, JacksonUtil.toJsonString(result));
+ }
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskDetail.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskDetail.java
new file mode 100644
index 00000000..5cb0b378
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskDetail.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.detail;
+
+public interface TaskDetail {
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskInfo.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskInfo.java
new file mode 100644
index 00000000..de44052c
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskInfo.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.detail;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TaskInfo implements TaskDetail, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private String className;
+ private String methodName;
+ private List params;
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskParam.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskParam.java
new file mode 100644
index 00000000..935bcd78
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/detail/TaskParam.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.detail;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TaskParam implements Serializable {
+
+ public static final long serialVersionUID = 1L;
+
+ private String className;
+ private String actualClassName;
+ private Object object;
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/handler/TaskHandler.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/handler/TaskHandler.java
new file mode 100644
index 00000000..e3f3895c
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/handler/TaskHandler.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.handler;
+
+import cn.sliew.carp.framework.task.server.detail.TaskDetail;
+
+public interface TaskHandler {
+
+ void onTask(String topic, TaskDetail task);
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/serder/Serder.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/serder/Serder.java
new file mode 100644
index 00000000..5964ff0d
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/serder/Serder.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.serder;
+
+import cn.sliew.carp.framework.task.server.detail.TaskDetail;
+
+public interface Serder {
+
+ byte[] serialize(TaskDetail taskDetail);
+
+ TaskDetail deserialize(byte[] bytes);
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/BrokerStorage.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/BrokerStorage.java
new file mode 100644
index 00000000..7090f1cd
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/BrokerStorage.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.storage;
+
+public interface BrokerStorage {
+
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/StorageProvider.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/StorageProvider.java
new file mode 100644
index 00000000..eb4bf1f1
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/StorageProvider.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.storage;
+
+public interface StorageProvider {
+
+ BrokerStorage getBrokerStorage();
+
+ TaskResultStorage getTaskResultStorage();
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/TaskResultStorage.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/TaskResultStorage.java
new file mode 100644
index 00000000..8108b2da
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/storage/TaskResultStorage.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.storage;
+
+import cn.sliew.carp.framework.task.server.broker.TaskMessage;
+
+public interface TaskResultStorage {
+
+ TaskMessage getTask(String taskId);
+
+ TaskMessage getTaskResult(String taskId);
+
+ TaskMessage deleteTask(String taskId);
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/worker/TaskWorker.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/worker/TaskWorker.java
new file mode 100644
index 00000000..536cd975
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/worker/TaskWorker.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.worker;
+
+public interface TaskWorker {
+
+ void start();
+
+ void stop();
+}
diff --git a/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/worker/impl/RedissonTaskWorker.java b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/worker/impl/RedissonTaskWorker.java
new file mode 100644
index 00000000..d7105d6b
--- /dev/null
+++ b/carp-framework/carp-framework-task/src/main/java/cn/sliew/carp/framework/task/server/worker/impl/RedissonTaskWorker.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.task.server.worker.impl;
+
+import cn.sliew.carp.framework.task.TaskExecutor;
+import cn.sliew.carp.framework.task.server.detail.TaskDetail;
+import cn.sliew.carp.framework.task.server.handler.TaskHandler;
+import cn.sliew.carp.framework.task.server.worker.TaskWorker;
+import cn.sliew.milky.common.concurrent.RunnableWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RedissonClient;
+import org.redisson.api.annotation.RInject;
+
+@Slf4j
+public class RedissonTaskWorker implements TaskWorker, RunnableWrapper {
+
+ private RedissonClient client;
+ private TaskHandler taskHandler;
+ private TaskExecutor executor;
+
+ private String topic;
+ private TaskDetail taskDetail;
+
+ @RInject
+ private String taskId;
+
+ public RedissonTaskWorker(String topic, TaskDetail taskDetail) {
+ this.topic = topic;
+ this.taskDetail = taskDetail;
+ }
+
+ @Override
+ public void start() {
+
+ }
+
+ @Override
+ public void stop() {
+
+ }
+
+ @Override
+ public void onBefore() throws Exception {
+ // 保存任务状态
+ }
+
+ @Override
+ public void doRun() throws Exception {
+ // 执行 executor
+ log.info("[}", taskDetail);
+ }
+
+ @Override
+ public void onAfter() throws Exception {
+ // 记录任务成功
+ }
+
+ @Override
+ public void onFailure(Exception e) {
+ // 记录任务失败
+ }
+
+ @Override
+ public void onFinal() {
+ // 最后根据任务执行结果
+ // 成功,标记任务结束
+ // 失败,标记任务失败,如果支持重试,则进行重试
+ }
+
+}
diff --git a/carp-framework/carp-framework-web/pom.xml b/carp-framework/carp-framework-web/pom.xml
index 7a9738f3..f04301cd 100644
--- a/carp-framework/carp-framework-web/pom.xml
+++ b/carp-framework/carp-framework-web/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-framework
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-framework-web
diff --git a/carp-framework/carp-framework-web/src/main/java/cn/sliew/carp/framework/web/exception/ExceptionFactory.java b/carp-framework/carp-framework-web/src/main/java/cn/sliew/carp/framework/web/exception/ExceptionFactory.java
new file mode 100644
index 00000000..de89e48b
--- /dev/null
+++ b/carp-framework/carp-framework-web/src/main/java/cn/sliew/carp/framework/web/exception/ExceptionFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.framework.web.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
+import org.springframework.web.ErrorResponseException;
+
+import java.net.URI;
+
+public enum ExceptionFactory {
+ ;
+
+ public static ErrorResponseException convertException(Exception e) {
+ ProblemDetail pd = ProblemDetail.forStatus(HttpStatus.INTERNAL_SERVER_ERROR);
+ pd.setType(URI.create("https://github.com/flowerfine/carp/issues"));
+ pd.setTitle(e.getMessage());
+ return new ErrorResponseException(HttpStatus.INTERNAL_SERVER_ERROR, pd, e);
+ }
+
+}
diff --git a/carp-framework/carp-framework-web/src/main/java/cn/sliew/carp/framework/web/exception/GlobalExceptionHandler.java b/carp-framework/carp-framework-web/src/main/java/cn/sliew/carp/framework/web/exception/GlobalExceptionHandler.java
index 24bea699..76f99c97 100644
--- a/carp-framework/carp-framework-web/src/main/java/cn/sliew/carp/framework/web/exception/GlobalExceptionHandler.java
+++ b/carp-framework/carp-framework-web/src/main/java/cn/sliew/carp/framework/web/exception/GlobalExceptionHandler.java
@@ -28,16 +28,20 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import java.util.HashMap;
import java.util.Map;
+/**
+ * @see DefaultHandlerExceptionResolver
+ */
@Slf4j
-@ControllerAdvice
-public class GlobalExceptionHandler {
+@RestControllerAdvice
+public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
/**
* All exception handling converters
@@ -53,7 +57,6 @@ public class GlobalExceptionHandler {
REGISTRY.put(BindException.class, new BindExceptionConvertor());
}
- @ResponseBody
@ExceptionHandler(Throwable.class)
public ResponseEntity exception(Throwable exception,
HttpServletRequest request,
@@ -62,7 +65,7 @@ public ResponseEntity exception(Throwable exception,
return new ResponseEntity<>(errorInfo, HttpStatus.OK);
}
- public ResponseVO convert(Throwable exception,HttpServletRequest request, HttpServletResponse response) {
+ public ResponseVO convert(Throwable exception, HttpServletRequest request, HttpServletResponse response) {
ExceptionConvertor exceptionConvertor = REGISTRY.get(exception.getClass());
if (exceptionConvertor == null) {
if (exception instanceof SliewException) {
diff --git a/carp-framework/pom.xml b/carp-framework/pom.xml
index 21a062b1..d8d0a4c2 100644
--- a/carp-framework/pom.xml
+++ b/carp-framework/pom.xml
@@ -23,13 +23,14 @@
cn.sliewcarp
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-frameworkpom
+ carp-framework-bizcarp-framework-commoncarp-framework-dagcarp-framework-exception
@@ -41,6 +42,7 @@
carp-framework-springcarp-framework-taskcarp-framework-web
+ carp-framework-license
\ No newline at end of file
diff --git a/carp-modules/carp-module-alert/pom.xml b/carp-modules/carp-module-alert/pom.xml
index 156511b8..8dc1ba9c 100644
--- a/carp-modules/carp-module-alert/pom.xml
+++ b/carp-modules/carp-module-alert/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-modules
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-module-alert
diff --git a/carp-modules/carp-module-application/carp-module-application-controller/pom.xml b/carp-modules/carp-module-application/carp-module-application-controller/pom.xml
index 2b4cf4d5..c9d3e021 100644
--- a/carp-modules/carp-module-application/carp-module-application-controller/pom.xml
+++ b/carp-modules/carp-module-application/carp-module-application-controller/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-module-application
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-module-application-controller
diff --git a/carp-modules/carp-module-application/carp-module-application-oam/pom.xml b/carp-modules/carp-module-application/carp-module-application-oam/pom.xml
index b75a2c1c..11fcbdf2 100644
--- a/carp-modules/carp-module-application/carp-module-application-oam/pom.xml
+++ b/carp-modules/carp-module-application/carp-module-application-oam/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-module-application
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-module-application-oam
diff --git a/carp-modules/carp-module-application/carp-module-application-vela/pom.xml b/carp-modules/carp-module-application/carp-module-application-vela/pom.xml
index f525107d..4069b77a 100644
--- a/carp-modules/carp-module-application/carp-module-application-vela/pom.xml
+++ b/carp-modules/carp-module-application/carp-module-application-vela/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-module-application
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-module-application-vela
diff --git a/carp-modules/carp-module-application/pom.xml b/carp-modules/carp-module-application/pom.xml
index 28061c9d..32539073 100644
--- a/carp-modules/carp-module-application/pom.xml
+++ b/carp-modules/carp-module-application/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-modules
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-module-application
diff --git a/carp-modules/carp-module-datasource/pom.xml b/carp-modules/carp-module-datasource/pom.xml
index 04235760..c287ab69 100644
--- a/carp-modules/carp-module-datasource/pom.xml
+++ b/carp-modules/carp-module-datasource/pom.xml
@@ -23,7 +23,7 @@
cn.sliewcarp-modules
- 0.0.12-SNAPSHOT
+ 0.0.13-SNAPSHOT../pom.xmlcarp-module-datasource
diff --git a/carp-modules/carp-module-datasource/src/main/java/cn/sliew/carp/module/datasource/modal/AbstractDataSourceProperties.java b/carp-modules/carp-module-datasource/src/main/java/cn/sliew/carp/module/datasource/modal/AbstractDataSourceProperties.java
index 7864f49e..c5b35523 100644
--- a/carp-modules/carp-module-datasource/src/main/java/cn/sliew/carp/module/datasource/modal/AbstractDataSourceProperties.java
+++ b/carp-modules/carp-module-datasource/src/main/java/cn/sliew/carp/module/datasource/modal/AbstractDataSourceProperties.java
@@ -42,6 +42,7 @@
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class AbstractDataSourceProperties implements Polymorphic {
+ @Override
public abstract String getType();
public static final class DataSourceResolver extends PolymorphicResolver {
diff --git a/carp-modules/carp-module-excel/pom.xml b/carp-modules/carp-module-excel/pom.xml
new file mode 100644
index 00000000..d0be12e4
--- /dev/null
+++ b/carp-modules/carp-module-excel/pom.xml
@@ -0,0 +1,52 @@
+
+
+
+
+ 4.0.0
+
+ cn.sliew
+ carp-modules
+ 0.0.13-SNAPSHOT
+ ../pom.xml
+
+ carp-module-excel
+
+
+
+ ${project.parent.groupId}
+ carp-framework-mybatis
+
+
+ ${project.parent.groupId}
+ carp-framework-web
+
+
+
+ com.alibaba
+ easyexcel
+
+
+
+ org.pf4j
+ pf4j
+
+
+
+
\ No newline at end of file
diff --git a/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/config/ExcelOpenAPIConfig.java b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/config/ExcelOpenAPIConfig.java
new file mode 100644
index 00000000..c0dc958a
--- /dev/null
+++ b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/config/ExcelOpenAPIConfig.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.excel.config;
+
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ExcelOpenAPIConfig {
+
+ @Bean
+ public GroupedOpenApi carpDataSourceModuleOpenApi() {
+ return GroupedOpenApi.builder().group("Excel模块")
+ .pathsToMatch("/api/carp/excel/**")
+ .packagesToScan("cn.sliew.carp.module.excel").build();
+ }
+}
\ No newline at end of file
diff --git a/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/annotaion/ImportSpec.java b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/annotaion/ImportSpec.java
new file mode 100644
index 00000000..ebd8bfac
--- /dev/null
+++ b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/annotaion/ImportSpec.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.excel.core.annotaion;
+
+import java.lang.annotation.*;
+
+@Documented
+@Inherited
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ImportSpec {
+
+ String code();
+
+ String name();
+
+ String desc() default "";
+
+ String fileType() default "xlsx";
+}
diff --git a/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/Processor.java b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/Processor.java
new file mode 100644
index 00000000..2fd3d4e9
--- /dev/null
+++ b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/Processor.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.excel.core.processor;
+
+public interface Processor {
+
+}
diff --git a/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/exporter/ExportProcessor.java b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/exporter/ExportProcessor.java
new file mode 100644
index 00000000..5f231744
--- /dev/null
+++ b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/exporter/ExportProcessor.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.excel.core.processor.exporter;
+
+import cn.sliew.carp.module.excel.core.processor.Processor;
+
+public interface ExportProcessor extends Processor {
+}
diff --git a/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/importer/ImportProcessor.java b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/importer/ImportProcessor.java
new file mode 100644
index 00000000..0fa3492b
--- /dev/null
+++ b/carp-modules/carp-module-excel/src/main/java/cn/sliew/carp/module/excel/core/processor/importer/ImportProcessor.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.excel.core.processor.importer;
+
+import cn.sliew.carp.module.excel.core.processor.Processor;
+
+public interface ImportProcessor extends Processor {
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/pom.xml b/carp-modules/carp-module-http-sync/carp-module-http-framework/pom.xml
new file mode 100644
index 00000000..c46ef87b
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ 4.0.0
+
+ cn.sliew
+ carp-module-http-sync
+ 0.0.13-SNAPSHOT
+ ../pom.xml
+
+ carp-module-http-framework
+
+
+
+ ${project.parent.groupId}
+ carp-framework-mybatis
+
+
+ ${project.parent.groupId}
+ carp-framework-pekko
+
+
+
\ No newline at end of file
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractJob.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractJob.java
new file mode 100644
index 00000000..0296bb78
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractJob.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.model.internal.ProcessResult;
+import cn.sliew.carp.module.http.sync.framework.model.internal.SimpleJobContext;
+import cn.sliew.milky.common.exception.Rethrower;
+import cn.sliew.milky.common.util.JacksonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.pekko.Done;
+import org.apache.pekko.NotUsed;
+import org.apache.pekko.actor.typed.ActorSystem;
+import org.apache.pekko.actor.typed.SpawnProtocol;
+import org.apache.pekko.japi.Pair;
+import org.apache.pekko.stream.*;
+import org.apache.pekko.stream.javadsl.*;
+
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public abstract class AbstractJob implements Job {
+
+ protected ActorSystem actorSystem;
+ protected SyncOffsetManager syncOffsetManager;
+ protected SplitManager splitManager;
+
+ public AbstractJob(ActorSystem actorSystem, SyncOffsetManager syncOffsetManager, SplitManager splitManager) {
+ this.actorSystem = actorSystem;
+ this.syncOffsetManager = syncOffsetManager;
+ this.splitManager = splitManager;
+ }
+
+ @Override
+ public void process(String param) {
+ doExecute(param);
+ }
+
+ protected void doExecute(Object param) {
+ SimpleJobContext context = buildJobContext();
+ JobProcessor processor = buildJobProcessor(context);
+ RootTask rootTask = buildRootTask(param);
+
+ Source source = Source.single(rootTask)
+ .mapConcat(root -> processor.map(root))
+ .viaMat(KillSwitches.single(), Keep.right());
+
+ Flow process = Flow.create()
+ .map(subTask -> processor.process(subTask)).mapAsync(1, future -> future);
+
+ Flow subTasks =
+ Flow.fromGraph(
+ GraphDSL.create(
+ b -> {
+ int concurrency = context.getSubTaskParallelism();
+ UniformFanOutShape partition =
+ b.add(Partition.create(concurrency, subTask -> Math.toIntExact(subTask.getIdentifier()) % concurrency));
+ UniformFanInShape merge =
+ b.add(MergeSequence.create(concurrency, result -> result.getSubTask().getIdentifier()));
+
+ for (int i = 0; i < concurrency; i++) {
+ b.from(partition.out(i))
+ .via(b.add(process.async()))
+ .viaFanIn(merge);
+ }
+
+ return FlowShape.of(partition.in(), merge.out());
+ }));
+
+ Pair> pair = source.via(subTasks)
+ .log(getJobName())
+ .toMat(Sink.foreach(result -> processor.reduce(result)), Keep.both())
+ .run(actorSystem);
+ UniqueKillSwitch killSwitch = pair.first();
+ try {
+ pair.second().toCompletableFuture().get(1, TimeUnit.HOURS);
+ } catch (Exception e) {
+ log.error("job 执行异常, job: {}, param: {}", getJobName(), JacksonUtil.toJsonString(param));
+ killSwitch.abort(e);
+ Rethrower.throwAs(e);
+ }
+ }
+
+ public abstract String getJobName();
+
+ protected SimpleJobContext buildJobContext() {
+ SimpleJobContext jobContext = new SimpleJobContext();
+ jobContext.setActorSystem(actorSystem);
+ jobContext.setSyncOffsetManager(syncOffsetManager);
+ jobContext.setSplitManager(splitManager);
+ return jobContext;
+ }
+
+ protected JobProcessor buildJobProcessor(SimpleJobContext context) {
+ return new DefaultJobProcessor(context);
+ }
+
+ protected abstract RootTask buildRootTask(Object param);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractRootTask.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractRootTask.java
new file mode 100644
index 00000000..c3f27c7d
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractRootTask.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.model.internal.SimpleJobContext;
+import cn.sliew.carp.module.http.sync.framework.repository.entity.JobSyncOffset;
+import org.apache.pekko.japi.Pair;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+public abstract class AbstractRootTask implements RootTask {
+
+ private Long rootTaskId;
+
+ public AbstractRootTask(Long rootTaskId) {
+ this.rootTaskId = rootTaskId;
+ }
+
+ @Override
+ public Long getIdentifier() {
+ return rootTaskId;
+ }
+
+ @Override
+ public List split(SimpleJobContext context) {
+ SyncOffsetManager syncOffsetManager = context.getSyncOffsetManager();
+ JobSyncOffset syncOffset = syncOffsetManager.getSyncOffset(context);
+
+ SplitManager splitManager = context.getSplitManager();
+ Optional optional = splitManager.getGradients().stream()
+ .filter(gradient -> splitManager.supportSplit(syncOffset.getSyncOffset(), context.getFinalSyncOffset(), gradient))
+ .findFirst();
+ Duration gradient = null;
+ if (optional.isEmpty()) {
+ boolean backupSupport = splitManager.supportSplit(syncOffset.getSyncOffset(), context.getFinalSyncOffset(), splitManager.getBackoffGradient());
+ if (backupSupport) {
+ gradient = splitManager.getBackoffGradient();
+ }
+ } else {
+ gradient = optional.get();
+ }
+ if (gradient == null) {
+ return Collections.emptyList();
+ }
+ List> splits = context.getSplitManager().split(syncOffset.getSyncOffset(), context.getFinalSyncOffset(), gradient, context.getSubTaskBatchSize());
+
+ List subs = new ArrayList<>();
+ for (int i = 0; i < splits.size(); i++) {
+ Pair pair = splits.get(i);
+ subs.add(build(Long.valueOf(i), pair.first(), pair.second()));
+ }
+ return subs;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractSubTask.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractSubTask.java
new file mode 100644
index 00000000..2d828df4
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/AbstractSubTask.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.model.internal.ProcessResult;
+import cn.sliew.carp.module.http.sync.framework.model.internal.SimpleJobContext;
+import org.apache.pekko.Done;
+import org.apache.pekko.actor.typed.ActorSystem;
+import org.apache.pekko.stream.ActorAttributes;
+import org.apache.pekko.stream.javadsl.Sink;
+import org.apache.pekko.stream.javadsl.Source;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+
+public abstract class AbstractSubTask implements SubTask {
+
+ private final Long subTaskId;
+ private final Root rootTask;
+
+ private final String startSyncOffset;
+ private final String endSyncOffset;
+
+ public AbstractSubTask(Long subTaskId, Root rootTask, String startSyncOffset, String endSyncOffset) {
+ this.subTaskId = subTaskId;
+ this.rootTask = rootTask;
+ this.startSyncOffset = startSyncOffset;
+ this.endSyncOffset = endSyncOffset;
+ }
+
+ @Override
+ public Long getIdentifier() {
+ return subTaskId;
+ }
+
+ @Override
+ public Root getRootTask() {
+ return rootTask;
+ }
+
+ @Override
+ public String getStartSyncOffset() {
+ return startSyncOffset;
+ }
+
+ @Override
+ public String getEndSyncOffset() {
+ return endSyncOffset;
+ }
+
+ @Override
+ public CompletableFuture execute(SimpleJobContext context) {
+ ActorSystem actorSystem = context.getActorSystem();
+ Sink, CompletionStage> sink = Sink.foreachParallel(10, data -> persistData(context, data.getRequest(), data.getResponse()), actorSystem.executionContext());
+ Source, ?> source = fetch(context);
+ CompletionStage completionStage = source
+ // 指定 dispatcher
+// .withAttributes(ActorAttributes.dispatcher("akka.actor.job-sink-dispatcher"))
+ .runWith(sink, actorSystem);
+ return completionStage.thenApply(done -> ProcessResult.success(this)).toCompletableFuture();
+ }
+
+ protected abstract Source, ?> fetch(SimpleJobContext context);
+
+ protected abstract Request buildFirstRequest(SimpleJobContext context);
+
+ protected abstract Response requestRemote(SimpleJobContext context, Request request);
+
+ protected abstract void persistData(SimpleJobContext context, Request request, Response response);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultJobProcessor.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultJobProcessor.java
new file mode 100644
index 00000000..f2788e52
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultJobProcessor.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.model.internal.ProcessResult;
+import cn.sliew.milky.common.exception.Rethrower;
+import cn.sliew.milky.common.util.JacksonUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+@Slf4j
+public class DefaultJobProcessor
+ implements JobProcessor {
+
+ private final Context context;
+
+ public DefaultJobProcessor(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ public Context getContext() {
+ return context;
+ }
+
+ @Override
+ public List map(Root rootTask) {
+ return rootTask.split(getContext());
+ }
+
+ @Override
+ public CompletableFuture process(Sub subTask) {
+ return subTask.execute(context);
+ }
+
+ @Override
+ public ProcessResult reduce(ProcessResult result) {
+ if (result.isSuccess() == false) {
+ log.error("group: {}, job: {}, subJob: {}, 子任务处理失败: {}!",
+ context.getGroup(), context.getJob(), context.getSubJob().orElse(null),
+ result.getMessage(), result.getThrowable());
+ if (result.getThrowable() != null) {
+ Rethrower.throwAs(result.getThrowable());
+ }
+ throw new RuntimeException(result.getMessage());
+ }
+ SubTask subTask = result.getSubTask();
+ log.debug("group: {}, job: {}, subJob: {}, {}-{}, 子任务处理成功! 子任务详情: {}",
+ context.getGroup(), context.getJob(), context.getSubJob().orElse(null),
+ subTask.getRootTask().getIdentifier(), subTask.getIdentifier(),
+ JacksonUtil.toJsonString(subTask));
+ context.getSyncOffsetManager().updateSyncOffset(context, subTask.getEndSyncOffset());
+ return ProcessResult.success(result.getSubTask());
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultSplitManager.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultSplitManager.java
new file mode 100644
index 00000000..b50fcf21
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultSplitManager.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.util.GradientUtil;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+import java.util.List;
+
+@Component
+public class DefaultSplitManager implements SplitManager {
+
+ @Override
+ public List getGradients() {
+ return GradientUtil.getDefaultGradients();
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultSyncOffsetManager.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultSyncOffsetManager.java
new file mode 100644
index 00000000..fff12eb8
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/DefaultSyncOffsetManager.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.model.internal.SimpleJobContext;
+import cn.sliew.carp.module.http.sync.framework.repository.entity.JobSyncOffset;
+import cn.sliew.carp.module.http.sync.framework.repository.mapper.JobSyncOffsetMapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.springframework.stereotype.Component;
+
+@Component
+public class DefaultSyncOffsetManager implements SyncOffsetManager {
+
+ private JobSyncOffsetMapper jobSyncOffsetMapper;
+
+ public DefaultSyncOffsetManager(JobSyncOffsetMapper jobSyncOffsetMapper) {
+ this.jobSyncOffsetMapper = jobSyncOffsetMapper;
+ }
+
+ @Override
+ public JobSyncOffset getSyncOffset(SimpleJobContext context) {
+ LambdaQueryWrapper queryWrapper = buildQueryWrapper(context);
+ JobSyncOffset syncOffset = jobSyncOffsetMapper.selectOne(queryWrapper);
+ if (syncOffset != null) {
+ return syncOffset;
+ }
+ initSyncOffset(context);
+
+ return getSyncOffset(context);
+ }
+
+ @Override
+ public void initSyncOffset(SimpleJobContext context) {
+ JobSyncOffset record = new JobSyncOffset();
+ record.setGroup(context.getGroup());
+ record.setJob(context.getJob());
+ context.getSubJob().ifPresent(subJob -> record.setSubJob(subJob));
+ record.setSyncOffset(context.getInitialSyncOffset());
+ record.setCreator("sync-offset-manager");
+ record.setEditor("sync-offset-manager");
+ jobSyncOffsetMapper.insert(record);
+ }
+
+ @Override
+ public void updateSyncOffset(SimpleJobContext context, String syncOffset) {
+ JobSyncOffset jobSyncOffset = getSyncOffset(context);
+ LambdaQueryWrapper queryWrapper = buildQueryWrapper(context);
+
+ JobSyncOffset record = new JobSyncOffset();
+ record.setGroup(context.getGroup());
+ record.setJob(context.getJob());
+ context.getSubJob().ifPresent(subJob -> record.setSubJob(subJob));
+ record.setLastSyncOffset(jobSyncOffset.getSyncOffset());
+ record.setSyncOffset(syncOffset);
+ record.setEditor("sync-offset-manager");
+ jobSyncOffsetMapper.update(record, queryWrapper);
+ }
+
+ @Override
+ public void resetSyncOffset(SimpleJobContext context) {
+ LambdaQueryWrapper queryWrapper = buildQueryWrapper(context);
+ jobSyncOffsetMapper.delete(queryWrapper);
+ initSyncOffset(context);
+ }
+
+ protected LambdaQueryWrapper buildQueryWrapper(SimpleJobContext context) {
+ LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(JobSyncOffset.class)
+ .eq(JobSyncOffset::getGroup, context.getGroup())
+ .eq(JobSyncOffset::getJob, context.getJob());
+ if (context.getSubJob().isPresent()) {
+ queryWrapper.eq(JobSyncOffset::getSubJob, context.getSubJob().get());
+ }
+ if (context.getAccount().isPresent()) {
+ queryWrapper.eq(JobSyncOffset::getAccount, context.getAccount().get());
+ }
+ if (context.getSubAccount().isPresent()) {
+ queryWrapper.eq(JobSyncOffset::getSubAccount, context.getSubAccount().get());
+ }
+ return queryWrapper;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/FetchResult.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/FetchResult.java
new file mode 100644
index 00000000..b5279629
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/FetchResult.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import lombok.Getter;
+
+@Getter
+public class FetchResult {
+
+ private final Request request;
+ private final Response response;
+
+ public FetchResult(Request request, Response response) {
+ this.request = request;
+ this.response = response;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/Job.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/Job.java
new file mode 100644
index 00000000..98038a45
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/Job.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+public interface Job {
+
+ void process(String param);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/JobContext.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/JobContext.java
new file mode 100644
index 00000000..7a80ab1d
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/JobContext.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import org.apache.pekko.actor.typed.ActorSystem;
+
+import java.util.Optional;
+
+public interface JobContext {
+
+ String getGroup();
+
+ String getJob();
+
+ Optional getSubJob();
+
+ Optional getAccount();
+
+ Optional getSubAccount();
+
+ ActorSystem getActorSystem();
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/JobProcessor.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/JobProcessor.java
new file mode 100644
index 00000000..b94c1f9f
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/JobProcessor.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.model.internal.ProcessResult;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public interface JobProcessor {
+
+ Context getContext();
+
+ List map(Root rootTask);
+
+ CompletableFuture process(Sub subTask);
+
+ ProcessResult reduce(ProcessResult result);
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/LockManager.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/LockManager.java
new file mode 100644
index 00000000..7a9cff40
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/LockManager.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+public interface LockManager {
+
+ boolean lock(JobContext context, RootTask rootTask);
+
+ boolean unlock(JobContext context, RootTask rootTask);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/ParallelJobContext.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/ParallelJobContext.java
new file mode 100644
index 00000000..0c0595eb
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/ParallelJobContext.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+public interface ParallelJobContext extends JobContext {
+
+ default int getSubTaskParallelism() {
+ return 10;
+ }
+
+ default int getSubTaskBatchSize() {
+ return 20;
+ }
+
+ SplitManager getSplitManager();
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/Result.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/Result.java
new file mode 100644
index 00000000..61dcfd17
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/Result.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+public interface Result {
+
+ boolean isSuccess();
+
+ String getMessage();
+
+ Throwable getThrowable();
+
+ SubTask getSubTask();
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/RootTask.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/RootTask.java
new file mode 100644
index 00000000..cbad8257
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/RootTask.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import java.util.List;
+
+public interface RootTask {
+
+ Long getIdentifier();
+
+ List split(Context context);
+
+ Sub build(Long subTaskId, String startSyncOffset, String endSyncOffset);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SplitManager.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SplitManager.java
new file mode 100644
index 00000000..bc58aee5
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SplitManager.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.sliew.carp.module.http.sync.framework.util.GradientUtil;
+import cn.sliew.carp.module.http.sync.framework.util.SyncOffsetHelper;
+import org.apache.pekko.japi.Pair;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public interface SplitManager {
+
+ List getGradients();
+
+ default boolean supportSplit(String startSyncOffset, String endSyncOffset, Duration gradient) {
+ LocalDateTime startTime = LocalDateTime.parse(startSyncOffset, DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
+ LocalDateTime endTime = LocalDateTime.parse(endSyncOffset, DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
+ return SyncOffsetHelper.supportSplit(startTime, endTime, gradient);
+ }
+
+ default List> split(String startSyncOffset, String endSyncOffset, Duration gradient, int total) {
+ LocalDateTime startTime = LocalDateTime.parse(startSyncOffset, DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
+ LocalDateTime endTime = LocalDateTime.parse(endSyncOffset, DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
+ return SyncOffsetHelper.split(startTime, endTime, gradient, total).stream().map(pair -> {
+ return Pair.create(DateUtil.format(pair.first(), DatePattern.NORM_DATETIME_PATTERN), DateUtil.format(pair.first(), DatePattern.NORM_DATETIME_PATTERN));
+ }).collect(Collectors.toUnmodifiableList());
+ }
+
+ default Duration getBackoffGradient() {
+ return GradientUtil.MIN_GRADIENT;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SubTask.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SubTask.java
new file mode 100644
index 00000000..fabbf5fe
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SubTask.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.model.internal.ProcessResult;
+
+import java.util.concurrent.CompletableFuture;
+
+public interface SubTask {
+
+ Long getIdentifier();
+
+ Root getRootTask();
+
+ String getStartSyncOffset();
+
+ String getEndSyncOffset();
+
+ CompletableFuture execute(Context context);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SyncOffsetJobContext.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SyncOffsetJobContext.java
new file mode 100644
index 00000000..a2ac43e5
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SyncOffsetJobContext.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+public interface SyncOffsetJobContext extends ParallelJobContext {
+
+ SyncOffsetManager getSyncOffsetManager();
+
+ String getInitialSyncOffset();
+
+ String getFinalSyncOffset();
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SyncOffsetManager.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SyncOffsetManager.java
new file mode 100644
index 00000000..9d4a4aac
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/SyncOffsetManager.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model;
+
+import cn.sliew.carp.module.http.sync.framework.repository.entity.JobSyncOffset;
+
+public interface SyncOffsetManager {
+
+ JobSyncOffset getSyncOffset(Context context);
+
+ void initSyncOffset(Context context);
+
+ void updateSyncOffset(Context context, String syncOffset);
+
+ void resetSyncOffset(Context context);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/internal/ProcessResult.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/internal/ProcessResult.java
new file mode 100644
index 00000000..65c166f7
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/internal/ProcessResult.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model.internal;
+
+import cn.sliew.carp.module.http.sync.framework.model.Result;
+import cn.sliew.carp.module.http.sync.framework.model.SubTask;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ProcessResult implements Result {
+
+ private boolean success = false;
+ private String message;
+ private Throwable throwable;
+
+ private SubTask subTask;
+
+ @Override
+ public boolean isSuccess() {
+ return success;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ @Override
+ public SubTask getSubTask() {
+ return subTask;
+ }
+
+ public static ProcessResult success(SubTask subTask) {
+ ProcessResult result = new ProcessResult();
+ result.setSuccess(true);
+ result.setSubTask(subTask);
+ result.setMessage("success");
+ return result;
+ }
+
+ public static ProcessResult failure(SubTask subTask) {
+ return failure(subTask, "internal error");
+ }
+
+ public static ProcessResult failure(SubTask subTask, String message) {
+ ProcessResult result = new ProcessResult();
+ result.setSuccess(false);
+ result.setMessage(message);
+ return result;
+ }
+
+ public static ProcessResult failure(SubTask subTask, Throwable throwable) {
+ ProcessResult result = new ProcessResult();
+ result.setSuccess(false);
+ result.setThrowable(throwable);
+ result.setMessage(throwable.getMessage());
+ return result;
+ }
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/internal/SimpleJobContext.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/internal/SimpleJobContext.java
new file mode 100644
index 00000000..435b99ee
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/model/internal/SimpleJobContext.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.model.internal;
+
+import cn.sliew.carp.module.http.sync.framework.model.SplitManager;
+import cn.sliew.carp.module.http.sync.framework.model.SyncOffsetJobContext;
+import cn.sliew.carp.module.http.sync.framework.model.SyncOffsetManager;
+import lombok.Setter;
+import org.apache.pekko.actor.typed.ActorSystem;
+
+import java.util.Optional;
+
+@Setter
+public class SimpleJobContext implements SyncOffsetJobContext {
+
+ private String group;
+ private String job;
+ private String subJob;
+ private String account;
+ private String subAccount;
+
+ private ActorSystem actorSystem;
+
+ private int subTaskParallelism = 2;
+ private int subTaskBatchSize = 1;
+ private SplitManager splitManager;
+
+ private SyncOffsetManager syncOffsetManager;
+ private String initialSyncOffset;
+ private String finalSyncOffset;
+
+ @Override
+ public String getGroup() {
+ return group;
+ }
+
+ @Override
+ public String getJob() {
+ return job;
+ }
+
+ @Override
+ public Optional getSubJob() {
+ return Optional.ofNullable(subJob);
+ }
+
+ @Override
+ public Optional getAccount() {
+ return Optional.ofNullable(account);
+ }
+
+ @Override
+ public Optional getSubAccount() {
+ return Optional.ofNullable(subAccount);
+ }
+
+ @Override
+ public ActorSystem getActorSystem() {
+ return actorSystem;
+ }
+
+ @Override
+ public SplitManager getSplitManager() {
+ return splitManager;
+ }
+
+ @Override
+ public SyncOffsetManager getSyncOffsetManager() {
+ return syncOffsetManager;
+ }
+
+ @Override
+ public String getInitialSyncOffset() {
+ return initialSyncOffset;
+ }
+
+ @Override
+ public String getFinalSyncOffset() {
+ return finalSyncOffset;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/repository/entity/JobSyncOffset.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/repository/entity/JobSyncOffset.java
new file mode 100644
index 00000000..b4c221a3
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/repository/entity/JobSyncOffset.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.repository.entity;
+
+import cn.sliew.carp.framework.mybatis.entity.BaseAuditDO;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@Data
+@TableName("job_sync_offset")
+public class JobSyncOffset extends BaseAuditDO {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableField("`group`")
+ private String group;
+
+ @TableField("job")
+ private String job;
+
+ @TableField("sub_job")
+ private String subJob;
+
+ @TableField("account")
+ private String account;
+
+ @TableField("sub_account")
+ private String subAccount;
+
+ @TableField("last_sync_offset")
+ private String lastSyncOffset;
+
+ @TableField("sync_offset")
+ private String syncOffset;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/repository/mapper/JobSyncOffsetMapper.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/repository/mapper/JobSyncOffsetMapper.java
new file mode 100644
index 00000000..e10aacff
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/repository/mapper/JobSyncOffsetMapper.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.repository.mapper;
+
+import cn.sliew.carp.module.http.sync.framework.repository.entity.JobSyncOffset;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface JobSyncOffsetMapper extends BaseMapper {
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/util/GradientUtil.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/util/GradientUtil.java
new file mode 100644
index 00000000..ac6c4f0e
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/util/GradientUtil.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.util;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+
+public enum GradientUtil {
+ ;
+
+ public static final Duration MIN_GRADIENT = Duration.ofSeconds(1L);
+
+ public static List getDefaultGradients() {
+ return Arrays.asList(
+ Duration.ofMinutes(15L),
+ Duration.ofMinutes(5L),
+ Duration.ofMinutes(2L),
+ Duration.ofMinutes(1L));
+ }
+
+ public static List getSparseGradients() {
+ return Arrays.asList(
+ Duration.ofDays(1L),
+ Duration.ofHours(12L),
+ Duration.ofHours(6L),
+ Duration.ofHours(3L),
+ Duration.ofHours(1L),
+ Duration.ofMinutes(30L)
+ );
+ }
+
+ public static List getMediumGradients() {
+ return Arrays.asList(
+ Duration.ofHours(12L),
+ Duration.ofHours(6L),
+ Duration.ofHours(3L),
+ Duration.ofHours(1L)
+ );
+ }
+
+ public static List getSmallGradients() {
+ return Arrays.asList(
+ Duration.ofHours(1L),
+ Duration.ofMinutes(30L)
+ );
+ }
+
+ public static List getDenseGradients() {
+ return Arrays.asList(
+ Duration.ofMinutes(1L)
+ );
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/util/SyncOffsetHelper.java b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/util/SyncOffsetHelper.java
new file mode 100644
index 00000000..96551492
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/java/cn/sliew/carp/module/http/sync/framework/util/SyncOffsetHelper.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.framework.util;
+
+import org.apache.pekko.japi.Pair;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.util.LinkedList;
+import java.util.List;
+
+public enum SyncOffsetHelper {
+ ;
+
+ public static boolean supportSplit(LocalDateTime startTime, LocalDateTime endTime, Duration gradient) {
+ LocalDateTime nextStart = startTime.plus(gradient);
+ return nextStart.isBefore(endTime);
+ }
+
+ public static List> split(LocalDateTime startTime, LocalDateTime endTime, Duration gradient, int total) {
+ List> pairs = new LinkedList<>();
+ LocalDateTime nextStart = startTime.plus(gradient);
+ for (int i = 0; i < total; i++) {
+ if (nextStart.isAfter(endTime)) {
+ break;
+ }
+ pairs.add(new Pair<>(startTime, nextStart));
+ startTime = nextStart;
+ nextStart = startTime.plus(gradient);
+ }
+ return pairs;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/resources/cn/sliew/carp/module/http/sync/framework/repository/mapper/JobSyncOffsetMapper.xml b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/resources/cn/sliew/carp/module/http/sync/framework/repository/mapper/JobSyncOffsetMapper.xml
new file mode 100644
index 00000000..8893d78a
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-framework/src/main/resources/cn/sliew/carp/module/http/sync/framework/repository/mapper/JobSyncOffsetMapper.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id,
+ `group`, job, sub_job, last_sync_offset, sync_offset, account, sub_account,
+ creator, editor, create_time, update_time
+
+
+
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/pom.xml b/carp-modules/carp-module-http-sync/carp-module-http-job/pom.xml
new file mode 100644
index 00000000..d12d5b2d
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/pom.xml
@@ -0,0 +1,56 @@
+
+
+
+
+ 4.0.0
+
+ cn.sliew
+ carp-module-http-sync
+ 0.0.13-SNAPSHOT
+ ../pom.xml
+
+ carp-module-http-job
+
+
+
+ ${project.parent.groupId}
+ carp-framework-exception
+
+
+
+ ${project.parent.groupId}
+ carp-framework-web
+
+
+
+ ${project.parent.groupId}
+ carp-module-http-framework
+
+
+
+ ${project.parent.groupId}
+ carp-module-http-remote-feign
+
+
+ ${project.parent.groupId}
+ carp-module-http-remote-jst
+
+
+
\ No newline at end of file
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/DataServiceDataSourceConfig.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/DataServiceDataSourceConfig.java
new file mode 100644
index 00000000..ab486ae8
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/DataServiceDataSourceConfig.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.config;
+
+import cn.sliew.carp.framework.mybatis.DataSourceConstants;
+import cn.sliew.carp.framework.mybatis.config.CarpMybatisConfig;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
+import com.baomidou.mybatisplus.core.MybatisConfiguration;
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler;
+import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
+import com.zaxxer.hikari.HikariDataSource;
+import org.apache.ibatis.logging.slf4j.Slf4jImpl;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+
+import javax.sql.DataSource;
+
+@Configuration
+@MapperScan(sqlSessionFactoryRef = DataServiceDataSourceConfig.SQL_SESSION_FACTORY,
+ basePackages = {DataServiceDataSourceConfig.MAPPER_MODULE_HTTP_SYNC_JOB_PACKAGE})
+public class DataServiceDataSourceConfig {
+
+ public static final String MAPPER_MODULE_HTTP_SYNC_JOB_PACKAGE = "cn.sliew.carp.module.http.sync.job.repository.mapper";
+
+ public static final String SQL_SESSION_FACTORY = "dataServiceSqlSessionFactory";
+ public static final String DATA_SOURCE_FACTORY = "dataServiceDataSource";
+ public static final String TRANSACTION_MANAGER_FACTORY = "dataServiceTransactionManager";
+
+ @Autowired
+ private MybatisPlusInterceptor mybatisPlusInterceptor;
+
+ @Primary
+ @Bean(DataServiceDataSourceConfig.DATA_SOURCE_FACTORY)
+ @ConfigurationProperties(prefix = "spring.datasource.dataservice")
+ public DataSource dataServiceDataSource() {
+ return DataSourceBuilder.create().type(HikariDataSource.class)
+ .build();
+ }
+
+ @Primary
+ @Bean(DataServiceDataSourceConfig.TRANSACTION_MANAGER_FACTORY)
+ public DataSourceTransactionManager dataServiceTransactionManager() {
+ return new DataSourceTransactionManager(dataServiceDataSource());
+ }
+
+ @Primary
+ @Bean(DataServiceDataSourceConfig.SQL_SESSION_FACTORY)
+ public SqlSessionFactory dataServiceSqlSessionFactory() throws Exception {
+ MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
+ GlobalConfig globalConfig = GlobalConfigUtils.defaults();
+ globalConfig.setMetaObjectHandler(new CarpMybatisConfig.CarpMetaHandler());
+
+ MybatisPlusProperties props = new MybatisPlusProperties();
+ props.setMapperLocations(new String[]{DataSourceConstants.MAPPER_XML_PATH});
+ factoryBean.setMapperLocations(props.resolveMapperLocations());
+
+ MybatisConfiguration configuration = new MybatisConfiguration();
+ configuration.setDefaultEnumTypeHandler(MybatisEnumTypeHandler.class);
+ configuration.setMapUnderscoreToCamelCase(true);
+ configuration.setLogImpl(Slf4jImpl.class);
+ factoryBean.setConfiguration(configuration);
+ factoryBean.setGlobalConfig(globalConfig);
+ factoryBean.setDataSource(dataServiceDataSource());
+ factoryBean.setPlugins(mybatisPlusInterceptor);
+ return factoryBean.getObject();
+ }
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/HttpSyncFeignConfig.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/HttpSyncFeignConfig.java
new file mode 100644
index 00000000..8e1cafed
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/HttpSyncFeignConfig.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.config;
+
+import cn.sliew.carp.module.http.sync.remote.feign.JacksonQueryMapEncoder;
+import feign.Capability;
+import feign.QueryMapEncoder;
+import feign.codec.Decoder;
+import feign.codec.Encoder;
+import feign.micrometer.MicrometerCapability;
+import feign.okhttp.OkHttpClient;
+import io.micrometer.core.instrument.MeterRegistry;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
+import org.springframework.cloud.openfeign.support.SpringDecoder;
+import org.springframework.cloud.openfeign.support.SpringEncoder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+@Configuration
+@EnableFeignClients(basePackages = {
+ "cn.sliew.carp.module.http.sync"
+})
+public class HttpSyncFeignConfig {
+
+ @Autowired
+ private MappingJackson2HttpMessageConverter jacksonConverter;
+
+ @Bean
+ public OkHttpClient okHttpClient() {
+ return new OkHttpClient();
+ }
+
+ @Bean
+ public Capability capability(MeterRegistry registry) {
+ return new MicrometerCapability(registry);
+ }
+
+ @Bean
+ public QueryMapEncoder queryMapEncoder() {
+ return new JacksonQueryMapEncoder();
+ }
+
+ @Bean
+ public Encoder encoder() {
+ addAdditionalMediaType();
+ HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
+ ObjectFactory objectFactory = () -> httpMessageConverters;
+ return new SpringEncoder(objectFactory);
+ }
+
+ @Bean
+ public Decoder decoder() {
+ addAdditionalMediaType();
+ HttpMessageConverters httpMessageConverters = new HttpMessageConverters(jacksonConverter);
+ ObjectFactory objectFactory = () -> httpMessageConverters;
+ return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
+ }
+
+ private void addAdditionalMediaType() {
+ List supportedMediaTypes = new LinkedList<>(jacksonConverter.getSupportedMediaTypes());
+ supportedMediaTypes.addAll(Arrays.asList(MediaType.TEXT_HTML, MediaType.TEXT_PLAIN));
+ jacksonConverter.setSupportedMediaTypes(supportedMediaTypes);
+ }
+}
\ No newline at end of file
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/HttpSyncOpenAPIConfig.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/HttpSyncOpenAPIConfig.java
new file mode 100644
index 00000000..2283275f
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/config/HttpSyncOpenAPIConfig.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.config;
+
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class HttpSyncOpenAPIConfig {
+
+ @Bean
+ public GroupedOpenApi carpHttpSyncModuleOpenApi() {
+ return GroupedOpenApi.builder().group("Http同步模块")
+ .pathsToMatch("/api/carp/http-sync/**")
+ .packagesToScan("cn.sliew.carp.module.http.sync").build();
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/controller/job/CarpJstController.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/controller/job/CarpJstController.java
new file mode 100644
index 00000000..ca969cf1
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/controller/job/CarpJstController.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.controller.job;
+
+import cn.sliew.carp.framework.common.security.annotations.AnonymousAccess;
+import cn.sliew.carp.framework.web.response.ApiResponseWrapper;
+import cn.sliew.carp.module.http.sync.job.jst.order.JstOrderJob;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@AnonymousAccess
+@RestController
+@ApiResponseWrapper
+@RequestMapping("/api/carp/http-sync/job/jst")
+@Tag(name = "Http同步管理-聚水潭")
+public class CarpJstController {
+
+ @Autowired
+ private JstOrderJob jstOrderJob;
+
+ @GetMapping("jstOrderJob")
+ @Operation(summary = "订单", description = "订单")
+ public void jstOrderJob(@RequestParam("param") String param) {
+ jstOrderJob.process(param);
+ }
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JobGroup.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JobGroup.java
new file mode 100644
index 00000000..aad50814
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JobGroup.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum JobGroup {
+
+ JST("jst", "聚水潭"),
+ ;
+
+ private String group;
+ private String desc;
+
+ JobGroup(String group, String desc) {
+ this.group = group;
+ this.desc = desc;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JobType.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JobType.java
new file mode 100644
index 00000000..22980948
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JobType.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum JobType {
+
+ NORMAL("normal", "普通任务"),
+ ;
+
+ private String type;
+ private String desc;
+
+ JobType(String type, String desc) {
+ this.type = type;
+ this.desc = desc;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JstApiEnum.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JstApiEnum.java
new file mode 100644
index 00000000..b95ebad2
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JstApiEnum.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum JstApiEnum {
+
+ SHOPS_QUERY("shops.query", "店铺查询"),
+ WMS_PARTNER_QUERY("wms.partner.query", "仓库查询"),
+ CATEGORY_QUERY("category.query", "商品类目查询"),
+ LOGISTIC_QUERY("logistic.query", "发货信息查询"),
+ COMBINE_SKU_QUERY("combine.sku.query", "组合商品查询"),
+ INVENTORY_COUNT_QUERY("inventory.count.query", "库存盘点查询"),
+ INVENTORY_QUERY("inventory.query", "库存查询"),
+ PACK_QUERY("pack.query", "箱及仓位库存查询-按照修改时间查询"),
+ MALL_ITEM_QUERY("mall.item.query", "普通商品查询(按款查询)"),
+ PURCHASEIN_QUERY("purchasein.query", "采购入库查询"),
+ PURCHASEOUT_QUERY("purchaseout.query", "采购退货查询"),
+ PURCHASE_QUERY("purchase.query", "采购单查询"),
+ SKUMAP_QUERY("skumap.query", "商品映射查询"),
+ SKU_QUERY("sku.query", "普通商品资料查询(按sku查询)"),
+ SUPPLIER_QUERY("supplier.query", "供应商查询"),
+ AFTERSALE_RECEIVED_QUERY("aftersale.received.query", "实际收货查询"),
+ ALLOCATE_QUERY("allocate.query", "调拨单查询"),
+ ORDER_ACTION_QUERY("order.action.query", "订单操作日志查询"),
+ OTHER_INOUT_QUERY("other.inout.query", "其它出入库查询"),
+ JUSHUITAN_INOUT_WATER_QUERY("jushuitan.inout.water.query", "进出仓流水"),
+ JUSHUITAN_TRACKINFO_QUERY("jushuitan.trackinfo.query", "通过唯一码查询物流日志"),
+
+ ORDERS_SINGLE_QUERY("orders.single.query", "订单查询"),
+ REFUND_SINGLE_QUERY("refund.single.query", "退货退款查询"),
+ ORDERS_OUT_SIMPLE_QUERY("orders.out.simple.query", "销售出库查询"),
+
+ ORDERS_HISTORY_QUERY("orders.history.query", "历史订单查询"),
+ REFUND_HISTORY_QUERY("refund.history.query", "历史退货退款查询"),
+ JUSHUITAN_SALEOUT_HISTORY_QUERY("jushuitan.saleout.history.query", "历史销售出库单查询"),
+
+ JUSHUITAN_ORDER_LIST_QUERY("jushuitan.order.list.query", "聚水潭奇门云订单"),
+ JUSHUITAN_REFUND_LIST_QUERY("jushuitan.refund.list.query", "聚水潭奇门云售后"),
+ JUSHUITAN_SALEOUT_LIST_QUERY("jushuitan.saleout.list.query", "聚水潭奇门云销售出库"),
+ ;
+
+ private String api;
+ private String desc;
+
+ JstApiEnum(String api, String desc) {
+ this.api = api;
+ this.desc = desc;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JstJob.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JstJob.java
new file mode 100644
index 00000000..eb505007
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/enums/JstJob.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum JstJob {
+
+ NORMAL_ORDERS_SINGLE_QUERY(JobGroup.JST, JobType.NORMAL, JstApiEnum.ORDERS_SINGLE_QUERY, "订单查询"),
+ ;
+
+ private JobGroup group;
+ private JobType type;
+ private JstApiEnum api;
+ private String desc;
+
+ JstJob(JobGroup group, JobType type, JstApiEnum api, String desc) {
+ this.group = group;
+ this.type = type;
+ this.api = api;
+ this.desc = desc;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/AbstractJstJob.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/AbstractJstJob.java
new file mode 100644
index 00000000..0b85b3c9
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/AbstractJstJob.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.jst;
+
+import cn.sliew.carp.module.http.sync.framework.model.AbstractJob;
+import cn.sliew.carp.module.http.sync.framework.model.RootTask;
+import cn.sliew.carp.module.http.sync.framework.model.SplitManager;
+import cn.sliew.carp.module.http.sync.framework.model.SyncOffsetManager;
+import cn.sliew.carp.module.http.sync.framework.model.internal.SimpleJobContext;
+import cn.sliew.carp.module.http.sync.job.enums.JstJob;
+import cn.sliew.carp.module.http.sync.job.remote.JstRemoteService;
+import cn.sliew.carp.module.http.sync.job.repository.entity.jst.JstAuth;
+import cn.sliew.carp.module.http.sync.job.repository.mapper.jst.JstAuthMapper;
+import cn.sliew.carp.module.http.sync.job.task.jst.AbstractJstRootTask;
+import cn.sliew.milky.common.util.JacksonUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import org.apache.pekko.actor.typed.ActorSystem;
+import org.apache.pekko.actor.typed.SpawnProtocol;
+
+import static cn.sliew.milky.common.check.Ensures.checkState;
+
+public abstract class AbstractJstJob extends AbstractJob {
+
+ protected final JstRemoteService jstRemoteService;
+ private final JstAuthMapper jstAuthMapper;
+
+ public AbstractJstJob(ActorSystem actorSystem, SyncOffsetManager syncOffsetManager, SplitManager splitManager, JstRemoteService jstRemoteService, JstAuthMapper jstAuthMapper) {
+ super(actorSystem, syncOffsetManager, splitManager);
+ this.jstRemoteService = jstRemoteService;
+ this.jstAuthMapper = jstAuthMapper;
+ }
+
+ @Override
+ public String getJobName() {
+ return String.format("%s.%s.%s", getJstJob().getGroup().getGroup(), getJstJob().getApi().getApi(), getJstJob().getType().getType());
+ }
+
+ @Override
+ protected SimpleJobContext buildJobContext() {
+ SimpleJobContext jobContext = super.buildJobContext();
+ JstJob jstJob = getJstJob();
+ jobContext.setGroup(jstJob.getGroup().getGroup());
+ jobContext.setJob(jstJob.getApi().getApi());
+ jobContext.setSubJob(jstJob.getType().getType());
+ return jobContext;
+ }
+
+ @Override
+ protected RootTask buildRootTask(Object param) {
+ JstJobParam jstJobParam = JacksonUtil.parseJsonString((String) param, JstJobParam.class);
+ LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(JstAuth.class)
+ .eq(JstAuth::getAppKey, jstJobParam.getAppKey())
+ .eq(JstAuth::getCompany, jstJobParam.getCompany());
+
+ JstAuth jstAuth = jstAuthMapper.selectOne(queryWrapper);
+ checkState(jstAuth != null);
+
+ return buildJstRootTask(jstAuth);
+ }
+
+ protected abstract JstJob getJstJob();
+
+ protected abstract AbstractJstRootTask buildJstRootTask(JstAuth jstAuth);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/JstJobParam.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/JstJobParam.java
new file mode 100644
index 00000000..90cb66fb
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/JstJobParam.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.jst;
+
+import lombok.Data;
+
+@Data
+public class JstJobParam {
+
+ private String appKey;
+ private String company;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/order/JstOrderJob.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/order/JstOrderJob.java
new file mode 100644
index 00000000..8ecb7f89
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/jst/order/JstOrderJob.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.jst.order;
+
+import cn.sliew.carp.module.http.sync.framework.model.SplitManager;
+import cn.sliew.carp.module.http.sync.framework.model.SyncOffsetManager;
+import cn.sliew.carp.module.http.sync.framework.model.internal.SimpleJobContext;
+import cn.sliew.carp.module.http.sync.job.enums.JstJob;
+import cn.sliew.carp.module.http.sync.job.jst.AbstractJstJob;
+import cn.sliew.carp.module.http.sync.job.remote.JstRemoteService;
+import cn.sliew.carp.module.http.sync.job.repository.entity.jst.JstAuth;
+import cn.sliew.carp.module.http.sync.job.repository.mapper.jst.JstAuthMapper;
+import cn.sliew.carp.module.http.sync.job.repository.mapper.jst.JstOrderMapper;
+import cn.sliew.carp.module.http.sync.job.task.jst.AbstractJstRootTask;
+import cn.sliew.carp.module.http.sync.job.task.jst.order.JstOrderRootTask;
+import org.apache.pekko.actor.typed.ActorSystem;
+import org.apache.pekko.actor.typed.SpawnProtocol;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JstOrderJob extends AbstractJstJob {
+
+ private final JstOrderMapper jstOrderMapper;
+
+ public JstOrderJob(ActorSystem actorSystem, SyncOffsetManager syncOffsetManager, SplitManager splitManager, JstRemoteService jstRemoteService, JstAuthMapper jstAuthMapper, JstOrderMapper jstOrderMapper) {
+ super(actorSystem, syncOffsetManager, splitManager, jstRemoteService, jstAuthMapper);
+ this.jstOrderMapper = jstOrderMapper;
+ }
+
+ @Override
+ protected JstJob getJstJob() {
+ return JstJob.NORMAL_ORDERS_SINGLE_QUERY;
+ }
+
+ @Override
+ protected SimpleJobContext buildJobContext() {
+ SimpleJobContext jobContext = super.buildJobContext();
+ jobContext.setInitialSyncOffset("2024-01-01 00:00:00");
+ jobContext.setFinalSyncOffset("2024-11-11 00:00:00");
+
+ jobContext.setSubTaskParallelism(2);
+ jobContext.setSubTaskBatchSize(1);
+ return jobContext;
+ }
+
+ @Override
+ protected AbstractJstRootTask buildJstRootTask(JstAuth jstAuth) {
+ return new JstOrderRootTask(System.currentTimeMillis(), jstRemoteService, jstAuth, jstOrderMapper);
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/remote/JstRemoteService.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/remote/JstRemoteService.java
new file mode 100644
index 00000000..ba58fb0d
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/remote/JstRemoteService.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.remote;
+
+import cn.sliew.carp.module.http.sync.job.repository.entity.jst.JstAuth;
+import cn.sliew.carp.module.http.sync.job.repository.mapper.jst.JstAuthMapper;
+import cn.sliew.carp.module.http.sync.job.util.ApiUtil;
+import cn.sliew.carp.module.http.sync.remote.jst.api.JstOrderClient;
+import cn.sliew.carp.module.http.sync.remote.jst.request.order.OrdersSingleQuery;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.order.JstOrdersResult;
+import cn.sliew.milky.common.util.JacksonUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.google.common.base.Joiner;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+public class JstRemoteService {
+
+ private URI uri = URI.create("https://api.jushuitan.com/");
+
+ @Autowired
+ private JstAuthMapper jstAuthMapper;
+ @Autowired
+ private JstOrderClient jstOrderClient;
+
+ private String sign(JstAuth auth, String param) {
+ Map params = new HashMap();
+ params.put("app_key", auth.getAppKey());
+ params.put("access_token", auth.getAccessToken());
+ params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000L));
+ params.put("version", "2");
+ params.put("charset", "utf-8");
+ params.put("biz", param);
+ String sign = ApiUtil.getSign(auth.getAppSecret(), params);
+ params.put("sign", sign);
+ return Joiner.on("&").withKeyValueSeparator("=").join(params);
+ }
+
+ private JstAuth getAuth(String appKey, String company) {
+ LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(JstAuth.class)
+ .eq(JstAuth::getAppKey, appKey)
+ .eq(JstAuth::getCompany, company);
+ return jstAuthMapper.selectOne(queryWrapper);
+ }
+
+ public JstNewResult getOrders(JstAuth auth, OrdersSingleQuery query) {
+ return jstOrderClient.getOrders(uri, sign(auth, JacksonUtil.toJsonString(query)));
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/BaseSyncMeta.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/BaseSyncMeta.java
new file mode 100644
index 00000000..e2aace44
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/BaseSyncMeta.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.repository.entity;
+
+import cn.sliew.carp.framework.mybatis.entity.BaseAuditDO;
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class BaseSyncMeta extends BaseAuditDO {
+
+ @TableField("sync_start_time")
+ private Date syncStartTime;
+
+ @TableField("sync_end_time")
+ private Date syncEndTime;
+
+ @TableField("sync_page_index")
+ private Integer syncPageIndex;
+
+ @TableField("sync_page_size")
+ private Integer syncPageSize;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/jst/JstAuth.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/jst/JstAuth.java
new file mode 100644
index 00000000..c49bda39
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/jst/JstAuth.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.repository.entity.jst;
+
+import cn.sliew.carp.framework.mybatis.entity.BaseAuditDO;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("jst_auth")
+public class JstAuth extends BaseAuditDO {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableField("app_key")
+ private String appKey;
+
+ @TableField("app_secret")
+ private String appSecret;
+
+ @TableField("company")
+ private String company;
+
+ @TableField("access_token")
+ private String accessToken;
+
+ @TableField("refresh_token")
+ private String refreshToken;
+
+ @TableField("expires_in")
+ private Long expiresIn;
+
+ @TableField("expires_date")
+ private Date expiresDate;
+
+ @TableField("scope")
+ private String scope;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/jst/JstOrder.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/jst/JstOrder.java
new file mode 100644
index 00000000..e68fe783
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/entity/jst/JstOrder.java
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.repository.entity.jst;
+
+import cn.sliew.carp.module.http.sync.job.repository.entity.BaseSyncMeta;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("jst_order")
+public class JstOrder extends BaseSyncMeta {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableField("app_key")
+ private String appKey;
+
+ @TableField("company")
+ private String company;
+
+ @TableField("is_cod")
+ private String isCod;
+
+ @TableField("l_id")
+ private String lId;
+
+ @TableField("send_date")
+ private Date sendDate;
+
+ @TableField("pay_date")
+ private Date payDate;
+
+ @TableField("freight")
+ private String freight;
+
+ @TableField("receiver_address")
+ private String receiverAddress;
+
+ @TableField("receiver_district")
+ private String receiverDistrict;
+
+ @TableField("wms_co_id")
+ private String wmsCoId;
+
+ @TableField("logistics_company")
+ private String logisticsCompany;
+
+ @TableField("as_id")
+ private String asId;
+
+ @TableField("free_amount")
+ private String freeAmount;
+
+ @TableField("shop_name")
+ private String shopName;
+
+ @TableField("question_type")
+ private String questionType;
+
+ @TableField("outer_pay_id")
+ private String outerPayId;
+
+ @TableField("so_id")
+ private String soId;
+
+ @TableField("`type`")
+ private String type;
+
+ @TableField("order_from")
+ private String orderFrom;
+
+ @TableField("`status`")
+ private String status;
+
+ @TableField("pay_amount")
+ private String payAmount;
+
+ @TableField("shop_buyer_id")
+ private String shopBuyerId;
+
+ @TableField("open_id")
+ private String openId;
+
+ @TableField("shop_status")
+ private String shopStatus;
+
+ @TableField("receiver_mobile")
+ private String receiverMobile;
+
+ @TableField("receiver_phone")
+ private String receiverPhone;
+
+ @TableField("order_date")
+ private Date orderDate;
+
+ @TableField("question_desc")
+ private String questionDesc;
+
+ @TableField("receiver_city")
+ private String receiverCity;
+
+ @TableField("receiver_state")
+ private String receiverState;
+
+ @TableField("receiver_name")
+ private String receiverName;
+
+ @TableField("o_id")
+ private Long oId;
+
+ @TableField("shop_id")
+ private Long shopId;
+
+ @TableField("co_id")
+ private Long coId;
+
+ @TableField("remark")
+ private String remark;
+
+ @TableField("drp_co_id_from")
+ private String drpCoIdFrom;
+
+ @TableField("modified")
+ private Date modified;
+
+ @TableField("labels")
+ private String labels;
+
+ @TableField("paid_amount")
+ private String paidAmount;
+
+ @TableField("currency")
+ private String currency;
+
+ @TableField("buyer_message")
+ private String buyerMessage;
+
+ @TableField("lc_id")
+ private String lcId;
+
+ @TableField("invoice_title")
+ private String invoiceTitle;
+
+ @TableField("invoice_type")
+ private String invoiceType;
+
+ @TableField("buyer_tax_no")
+ private String buyerTaxNo;
+
+ @TableField("creator_name")
+ private String creatorName;
+
+ @TableField("plan_delivery_date")
+ private Date planDeliveryDate;
+
+ @TableField("node")
+ private String node;
+
+ @TableField("receiver_town")
+ private String receiverTown;
+
+ @TableField("drp_co_id_to")
+ private String drpCoIdTo;
+
+ @TableField("shop_site")
+ private String shopSite;
+
+ @TableField("un_lid")
+ private String unLid;
+
+ @TableField("end_time")
+ private Date endTime;
+
+ @TableField("receiver_country")
+ private String receiverCountry;
+
+ @TableField("receiver_zip")
+ private String receiverZip;
+
+ @TableField("seller_flag")
+ private Integer sellerFlag;
+
+ @TableField("receiver_email")
+ private String receiverEmail;
+
+ @TableField("referrer_id")
+ private String referrerId;
+
+ @TableField("referrer_name")
+ private String referrerName;
+
+ @TableField("created")
+ private String created;
+
+ @TableField("pays")
+ private String pays;
+
+ @TableField("items")
+ private String items;
+
+ @TableField("skus")
+ private String skus;
+
+ @TableField("f_weight")
+ private String fWeight;
+
+ @TableField("weight")
+ private String weight;
+
+ @TableField("ts")
+ private Long ts;
+
+ @TableField("buyer_id")
+ private String buyerId;
+
+ @TableField("buyer_paid_amount")
+ private String buyerPaidAmount;
+
+ @TableField("seller_income_amount")
+ private String sellerIncomeAmount;
+
+ @TableField("chosen_channel")
+ private String chosenChannel;
+
+ @TableField("link_o_id")
+ private String linkOId;
+
+ @TableField("merge_so_id")
+ private String mergeSoId;
+
+ @TableField("shipment")
+ private String shipment;
+
+ @TableField("sign_time")
+ private String signTime;
+
+ @TableField("cb_finances")
+ private String cbFinances;
+
+ @TableField("f_freight")
+ private String fFreight;
+
+ @TableField("batch_id")
+ private String batchId;
+
+ @TableField("produced_date")
+ private String producedDate;
+
+ @TableField("tem_ext_data")
+ private String temExtData;
+
+ @TableField("discount_rate")
+ private String discountRate;
+
+ @TableField("tag")
+ private String tag;
+
+ @TableField("amount")
+ private String amount;
+
+ @TableField("is_split")
+ private String isSplit;
+
+ @TableField("is_merge")
+ private String isMerge;
+
+ @TableField("glasses")
+ private String glasses;
+
+ @TableField("outer_as_id")
+ private String outerAsId;
+
+ @TableField("outer_so_id")
+ private String outerSoId;
+
+ @TableField("__raw_so_ids__")
+ private String rawSoIds;
+
+ @TableField("ext_datas")
+ private String extDatas;
+
+ @TableField("raw_so_id")
+ private String rawSoId;
+
+ @TableField("drp_from")
+ private String drpFrom;
+
+ @TableField("drp_to")
+ private String drpTo;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstAuthMapper.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstAuthMapper.java
new file mode 100644
index 00000000..f2b060dd
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstAuthMapper.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.repository.mapper.jst;
+
+import cn.sliew.carp.module.http.sync.job.repository.entity.jst.JstAuth;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface JstAuthMapper extends BaseMapper {
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstOrderMapper.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstOrderMapper.java
new file mode 100644
index 00000000..5badd205
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstOrderMapper.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.repository.mapper.jst;
+
+import cn.sliew.carp.module.http.sync.job.repository.entity.jst.JstOrder;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface JstOrderMapper extends BaseMapper {
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/AbstractJstRootTask.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/AbstractJstRootTask.java
new file mode 100644
index 00000000..cd4ec925
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/AbstractJstRootTask.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.task.jst;
+
+import cn.sliew.carp.module.http.sync.framework.model.AbstractRootTask;
+import cn.sliew.carp.module.http.sync.job.remote.JstRemoteService;
+import cn.sliew.carp.module.http.sync.job.repository.entity.jst.JstAuth;
+import lombok.Getter;
+
+@Getter
+public abstract class AbstractJstRootTask extends AbstractRootTask {
+
+ private JstRemoteService jstRemoteService;
+ private JstAuth jstAuth;
+
+ public AbstractJstRootTask(Long rootTaskId, JstRemoteService jstRemoteService, JstAuth jstAuth) {
+ super(rootTaskId);
+ this.jstRemoteService = jstRemoteService;
+ this.jstAuth = jstAuth;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/AbstractJstSubTask.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/AbstractJstSubTask.java
new file mode 100644
index 00000000..baec8cde
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/AbstractJstSubTask.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.task.jst;
+
+import cn.sliew.carp.module.http.sync.framework.model.AbstractSubTask;
+
+public abstract class AbstractJstSubTask extends AbstractSubTask {
+
+ public AbstractJstSubTask(Long subTaskId, Root rootTask, String startSyncOffset, String endSyncOffset) {
+ super(subTaskId, rootTask, startSyncOffset, endSyncOffset);
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/order/JstOrderRootTask.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/order/JstOrderRootTask.java
new file mode 100644
index 00000000..db703415
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/order/JstOrderRootTask.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.task.jst.order;
+
+import cn.sliew.carp.module.http.sync.job.remote.JstRemoteService;
+import cn.sliew.carp.module.http.sync.job.repository.mapper.jst.JstOrderMapper;
+import cn.sliew.carp.module.http.sync.job.task.jst.AbstractJstRootTask;
+import cn.sliew.carp.module.http.sync.job.repository.entity.jst.JstAuth;
+
+public class JstOrderRootTask extends AbstractJstRootTask {
+
+ private JstOrderMapper jstOrderMapper;
+
+ public JstOrderRootTask(Long rootTaskId, JstRemoteService jstRemoteService, JstAuth jstAuth, JstOrderMapper jstOrderMapper) {
+ super(rootTaskId, jstRemoteService, jstAuth);
+ this.jstOrderMapper = jstOrderMapper;
+ }
+
+ @Override
+ public JstOrderSubTask build(Long subTaskId, String startSyncOffset, String endSyncOffset) {
+ return new JstOrderSubTask(subTaskId, this, startSyncOffset, endSyncOffset, getJstRemoteService(), jstOrderMapper);
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/order/JstOrderSubTask.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/order/JstOrderSubTask.java
new file mode 100644
index 00000000..ea82bef9
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/order/JstOrderSubTask.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.task.jst.order;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.sliew.carp.framework.exception.SliewException;
+import cn.sliew.carp.module.http.sync.framework.model.FetchResult;
+import cn.sliew.carp.module.http.sync.framework.model.internal.SimpleJobContext;
+import cn.sliew.carp.module.http.sync.job.remote.JstRemoteService;
+import cn.sliew.carp.module.http.sync.job.repository.entity.jst.JstOrder;
+import cn.sliew.carp.module.http.sync.job.repository.mapper.jst.JstOrderMapper;
+import cn.sliew.carp.module.http.sync.job.task.jst.AbstractJstSubTask;
+import cn.sliew.carp.module.http.sync.job.task.jst.util.JstResultWrapper;
+import cn.sliew.carp.module.http.sync.job.task.jst.util.JstUtil;
+import cn.sliew.carp.module.http.sync.remote.jst.request.order.OrdersSingleQuery;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.order.JstOrdersResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.order.OrdersSingleDO;
+import cn.sliew.milky.common.util.JacksonUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.pekko.japi.Pair;
+import org.apache.pekko.stream.javadsl.Source;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+@Slf4j
+public class JstOrderSubTask extends AbstractJstSubTask {
+
+ private final JstRemoteService remoteService;
+ private final JstOrderMapper jstOrderMapper;
+
+ public JstOrderSubTask(Long subTaskId, JstOrderRootTask rootTask, String startSyncOffset, String endSyncOffset, JstRemoteService remoteService, JstOrderMapper jstOrderMapper) {
+ super(subTaskId, rootTask, startSyncOffset, endSyncOffset);
+ this.remoteService = remoteService;
+ this.jstOrderMapper = jstOrderMapper;
+ }
+
+ @Override
+ protected Source, ?> fetch(SimpleJobContext context) {
+ OrdersSingleQuery first = buildFirstRequest(context);
+ return Source.unfoldAsync(first, key -> {
+ if (key == null) {
+ return CompletableFuture.completedFuture(Optional.empty());
+ }
+ JstOrdersResult jstOrdersResult = requestRemote(context, key);
+ FetchResult fetchResult = new FetchResult<>(key, jstOrdersResult);
+ if (jstOrdersResult.isHasNext()) {
+ OrdersSingleQuery next = BeanUtil.copyProperties(key, OrdersSingleQuery.class);
+ next.setPageIndex(key.getPageIndex() + 1);
+ return CompletableFuture.completedFuture(Optional.of(Pair.create(next, fetchResult)));
+ }
+ return CompletableFuture.completedFuture(Optional.of(Pair.create(null, fetchResult)));
+ });
+ }
+
+ @Override
+ protected OrdersSingleQuery buildFirstRequest(SimpleJobContext context) {
+ OrdersSingleQuery query = new OrdersSingleQuery();
+ query.setModifiedBegin(getStartSyncOffset());
+ query.setModifiedEnd(getEndSyncOffset());
+ query.setPageIndex(1);
+ query.setPageSize(50);
+ return query;
+ }
+
+ @Override
+ protected JstOrdersResult requestRemote(SimpleJobContext context, OrdersSingleQuery request) {
+ JstNewResult jstNewResult = remoteService.getOrders(getRootTask().getJstAuth(), request);
+ if (jstNewResult.isSuccess()) {
+ JstOrdersResult jstResult = jstNewResult.getData();
+ JstResultWrapper jstResultWrapper = JstUtil.convertResult(jstResult, OrdersSingleDO::getOId);
+ log.debug("请求聚水潭接口返回结果, {}, request: {}, result: {}",
+ context.getGroup(), JacksonUtil.toJsonString(request), JacksonUtil.toJsonString(jstResultWrapper));
+ return jstResult;
+ }
+ log.error("请求聚水潭接口失败! method: {}, code: {}, msg: {}, query: {}",
+ context.getGroup(), jstNewResult.getCode(), jstNewResult.getMsg(), JacksonUtil.toJsonString(request));
+ throw new SliewException(Objects.toString(jstNewResult.getCode()), jstNewResult.getMsg());
+ }
+
+ @Override
+ protected void persistData(SimpleJobContext context, OrdersSingleQuery request, JstOrdersResult response) {
+ if (CollectionUtils.isEmpty(response.getDatas())) {
+ return;
+ }
+ response.getDatas().forEach(data -> upsert(request, data));
+ }
+
+ private void upsert(OrdersSingleQuery request, OrdersSingleDO data) {
+ JstOrder record = convert(request, data);
+
+ LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(JstOrder.class)
+ .eq(JstOrder::getAppKey, record.getAppKey())
+ .eq(JstOrder::getCompany, record.getCompany())
+ .eq(JstOrder::getOId, record.getOId())
+ .select(JstOrder::getId);
+
+ JstOrder jstOrder = jstOrderMapper.selectOne(queryWrapper);
+ if (jstOrder != null) {
+ record.setId(jstOrder.getId());
+ record.setEditor("sync-task");
+ jstOrderMapper.updateById(record);
+ } else {
+ record.setCreator("sync-task");
+ record.setEditor("sync-task");
+ jstOrderMapper.insert(record);
+ }
+ }
+
+ private JstOrder convert(OrdersSingleQuery request, OrdersSingleDO data) {
+ JstOrder record = BeanUtil.copyProperties(data, JstOrder.class);
+ if (CollectionUtils.isEmpty(data.getItems()) == false) {
+ record.setItems(JacksonUtil.toJsonString(data.getItems()));
+ }
+ if (org.springframework.util.CollectionUtils.isEmpty(data.getPays()) == false) {
+ record.setPays(JacksonUtil.toJsonString(data.getPays()));
+ }
+ if (org.springframework.util.CollectionUtils.isEmpty(data.getRawSoIds()) == false) {
+ record.setRawSoIds(JacksonUtil.toJsonString(data.getRawSoIds()));
+ }
+ record.setSyncStartTime(DateUtil.parse(request.getModifiedBegin(), DatePattern.NORM_DATETIME_PATTERN).toJdkDate());
+ record.setSyncEndTime(DateUtil.parse(request.getModifiedEnd(), DatePattern.NORM_DATETIME_PATTERN).toJdkDate());
+ record.setSyncPageIndex(request.getPageIndex());
+ record.setSyncPageSize(request.getPageSize());
+ return record;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/util/JstResultWrapper.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/util/JstResultWrapper.java
new file mode 100644
index 00000000..d67fb65d
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/util/JstResultWrapper.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.task.jst.util;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.lang.Nullable;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class JstResultWrapper {
+
+ @JsonProperty("page_index")
+ private int pageIndex;
+
+ @JsonProperty("page_size")
+ private int pageSize;
+
+ @Nullable
+ @JsonProperty("data_count")
+ private int dataCount;
+
+ @Nullable
+ @JsonProperty("page_count")
+ private int pageCount;
+
+ @JsonProperty("has_next")
+ private boolean hasNext;
+
+ @JsonProperty("issuccess")
+ private boolean issuccess;
+
+ private int code;
+ private String msg;
+ private List datas;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/util/JstUtil.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/util/JstUtil.java
new file mode 100644
index 00000000..34ea1624
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/task/jst/util/JstUtil.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.task.jst.util;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import org.springframework.util.CollectionUtils;
+
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public enum JstUtil {
+ ;
+
+ public static JstResultWrapper convertResult(JstResult jstResult, Function convert) {
+ JstResultWrapper jstResultWrapper = BeanUtil.copyProperties(jstResult, JstResultWrapper.class);
+ if (CollectionUtils.isEmpty(jstResult.getDatas()) == false) {
+ jstResultWrapper.setDatas(jstResult.getDatas().stream().map(convert).collect(Collectors.toList()));
+ }
+ return jstResultWrapper;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/util/ApiUtil.java b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/util/ApiUtil.java
new file mode 100644
index 00000000..de348dd3
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/java/cn/sliew/carp/module/http/sync/job/util/ApiUtil.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.job.util;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.security.MessageDigest;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * 聚水潭开放平台下载 jar 包内的工具类,copy 过来的
+ */
+public enum ApiUtil {
+ ;
+
+ public static String getSign(String signKey, Map params) {
+ String sortedStr = getSortedParamStr(params);
+ String paraStr = signKey + sortedStr;
+ return createSign(paraStr);
+ }
+
+ public static String getSortedParamStr(Map params) {
+ Set sortedParams = new TreeSet(params.keySet());
+ StringBuilder stringBuilder = new StringBuilder();
+ for (String key : sortedParams) {
+ if (!"sign".equalsIgnoreCase(key)) {
+ String value = params.get(key);
+ if (StringUtils.isNotBlank(value)) {
+ stringBuilder.append(key).append(value);
+ }
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ public static String createSign(String str) {
+ if (str != null && str.length() != 0) {
+ char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ try {
+ MessageDigest mdTemp = MessageDigest.getInstance("MD5");
+ mdTemp.update(str.getBytes("UTF-8"));
+ byte[] md = mdTemp.digest();
+ int j = md.length;
+ char[] buf = new char[j * 2];
+ int k = 0;
+
+ for (int i = 0; i < j; ++i) {
+ byte byte0 = md[i];
+ buf[k++] = hexDigits[byte0 >>> 4 & 15];
+ buf[k++] = hexDigits[byte0 & 15];
+ }
+
+ return new String(buf);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/resources/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstAuthMapper.xml b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/resources/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstAuthMapper.xml
new file mode 100644
index 00000000..07b0051c
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/resources/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstAuthMapper.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id,
+ creator,
+ create_time,
+ editor,
+ update_time,
+ app_key, app_secret, company, access_token, refresh_token, expires_in, expires_date, scope
+
+
+
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/resources/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstOrderMapper.xml b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/resources/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstOrderMapper.xml
new file mode 100644
index 00000000..e7149171
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-job/src/main/resources/cn/sliew/carp/module/http/sync/job/repository/mapper/jst/JstOrderMapper.xml
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id,
+ creator,
+ create_time,
+ editor,
+ update_time,
+ app_key, company, is_cod, l_id, send_date, pay_date, freight, receiver_address, receiver_district, wms_co_id, logistics_company, as_id, free_amount, shop_name, question_type, outer_pay_id, so_id, `type`, order_from, `status`, pay_amount, shop_buyer_id, open_id, shop_status, receiver_mobile, receiver_phone, order_date, question_desc, receiver_city, receiver_state, receiver_name, o_id, shop_id, co_id, remark, drp_co_id_from, modified, labels, paid_amount, currency, buyer_message, lc_id, invoice_title, invoice_type, buyer_tax_no, creator_name, plan_delivery_date, node, receiver_town, drp_co_id_to, shop_site, un_lid, end_time, receiver_country, receiver_zip, seller_flag, receiver_email, referrer_id, referrer_name, created, pays, items, skus, f_weight, weight, ts, buyer_id, buyer_paid_amount, seller_income_amount, chosen_channel, link_o_id, merge_so_id, shipment, sign_time, cb_finances, f_freight, batch_id, produced_date, tem_ext_data, discount_rate, tag, amount, is_split, is_merge, glasses, outer_as_id, outer_so_id, __raw_so_ids__, ext_datas, raw_so_id, drp_from, drp_to, sync_start_time, sync_end_time, sync_page_index, sync_page_size
+
+
+
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-feign/pom.xml b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-feign/pom.xml
new file mode 100644
index 00000000..e44854da
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-feign/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+
+ 4.0.0
+
+ cn.sliew
+ carp-module-http-remote
+ 0.0.13-SNAPSHOT
+ ../pom.xml
+
+ carp-module-http-remote-feign
+
+
+
+ ${project.parent.groupId}
+ carp-framework-common
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ io.github.openfeign
+ feign-okhttp
+
+
+ io.github.openfeign
+ feign-jackson
+
+
+ io.github.openfeign
+ feign-micrometer
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-feign/src/main/java/cn/sliew/carp/module/http/sync/remote/feign/JacksonQueryMapEncoder.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-feign/src/main/java/cn/sliew/carp/module/http/sync/remote/feign/JacksonQueryMapEncoder.java
new file mode 100644
index 00000000..1161ad88
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-feign/src/main/java/cn/sliew/carp/module/http/sync/remote/feign/JacksonQueryMapEncoder.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.feign;
+
+import cn.sliew.milky.common.util.JacksonUtil;
+import feign.QueryMapEncoder;
+
+import java.util.Map;
+
+public class JacksonQueryMapEncoder implements QueryMapEncoder {
+
+ @Override
+ public Map encode(Object o) {
+ String jsonString = JacksonUtil.toJsonString(o);
+ return JacksonUtil.parseJsonString(jsonString, Map.class);
+ }
+}
\ No newline at end of file
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/pom.xml b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/pom.xml
new file mode 100644
index 00000000..58372378
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/pom.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ 4.0.0
+
+ cn.sliew
+ carp-module-http-remote
+ 0.0.13-SNAPSHOT
+ ../pom.xml
+
+ carp-module-http-remote-jst
+
+
+ 0.0.1
+
+
+
+
+ ${project.parent.groupId}
+ carp-module-http-remote-feign
+
+
+
\ No newline at end of file
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstAuthClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstAuthClient.java
new file mode 100644
index 00000000..c83fed66
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstAuthClient.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.auth.JstAccessTokenDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.cloud.openfeign.SpringQueryMap;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+import java.util.Map;
+
+@FeignClient(value = "jstAuthClient", url = "EMPTY")
+public interface JstAuthClient {
+
+ @PostMapping(value = "/openWeb/auth/getInitToken", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult accessToken(URI uri, @SpringQueryMap Map params);
+
+ @PostMapping(value = "/openWeb/auth/refreshToken", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult refreshToken(URI uri, @RequestBody String paramStr);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstBaseClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstBaseClient.java
new file mode 100644
index 00000000..4b208039
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstBaseClient.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.base.ShopDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.base.WmsPartnerDO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+
+@FeignClient(value = "jstBaseClient", url = "EMPTY")
+public interface JstBaseClient {
+
+ @PostMapping(value = "/open/shops/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getShops(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/wms/partner/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getWmsPartner(URI uri, @RequestBody String paramStr);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstInventoryClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstInventoryClient.java
new file mode 100644
index 00000000..0ede7e04
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstInventoryClient.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.inventory.InventoryCountDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.inventory.JstInventoryResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.inventory.PackDO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+
+@FeignClient(value = "jstInventoryClient", url = "EMPTY")
+public interface JstInventoryClient {
+
+ @PostMapping(value = "/open/pack/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getPack(URI uri, @RequestBody String sign);
+
+ @PostMapping(value = "/open/inventory/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult getInventoryQuery(URI uri, String sign);
+
+ @PostMapping(value = "/open/inventory/count/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getInventoryCount(URI uri, String sign);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstItemClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstItemClient.java
new file mode 100644
index 00000000..55947695
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstItemClient.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.item.*;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+
+@FeignClient(value = "jstItemClient", url = "EMPTY")
+public interface JstItemClient {
+
+ @PostMapping(value = "/open/skumap/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getSkumap(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/mall/item/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getMallItem(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/combine/sku/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getCombineSku(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/sku/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getSku(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/category/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getCategoryInfo(URI uri, @RequestBody String paramStr);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstLogisticClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstLogisticClient.java
new file mode 100644
index 00000000..80b4dd52
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstLogisticClient.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.logistics.JstLogisticResult;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+
+@FeignClient(value = "jstLogisticClient", url = "EMPTY")
+public interface JstLogisticClient {
+
+ @PostMapping(value = "/open/logistic/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult getLogisticInfo(URI uri, @RequestBody String paramStr);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstOrderClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstOrderClient.java
new file mode 100644
index 00000000..45d18d7c
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstOrderClient.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.order.JstOrdersResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.order.OrderActionDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.order.OrdersOutSimpleDO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+
+@FeignClient(value = "jstOrderClient", url = "EMPTY")
+public interface JstOrderClient {
+
+ @PostMapping(value = "/open/orders/single/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult getOrders(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/orders/out/simple/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getOrdersOut(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/order/action/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getOrderAction(URI uri, @RequestBody String paramStr);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstPurchaseClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstPurchaseClient.java
new file mode 100644
index 00000000..0571329a
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstPurchaseClient.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.purchase.PurchaseDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.purchase.PurchaseinDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.purchase.PurchaseoutDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.purchase.SupplierDO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+
+@FeignClient(value = "jstPurchaseClient", url = "EMPTY")
+public interface JstPurchaseClient {
+
+ @PostMapping(value = "/open/purchase/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getPurchase(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/purchasein/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getPurchasein(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/purchaseout/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getPurchaseout(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/supplier/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getSupplier(URI uri, @RequestBody String paramStr);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstRefundClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstRefundClient.java
new file mode 100644
index 00000000..1a3d7f91
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstRefundClient.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.refund.RefundSingleDO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+
+@FeignClient(value = "jstRefundClient", url = "EMPTY")
+public interface JstRefundClient {
+
+ @PostMapping(value = "/open/refund/single/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getRefund(URI uri, @RequestBody String paramStr);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstWmsClient.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstWmsClient.java
new file mode 100644
index 00000000..f3ee3552
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/api/JstWmsClient.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.api;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstNewResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.refund.AllocateDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.refund.InoutWaterDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.refund.OtherInoutDO;
+import cn.sliew.carp.module.http.sync.remote.jst.response.refund.TrackinfoDO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.net.URI;
+
+@FeignClient(value = "jstWmsClient", url = "EMPTY")
+public interface JstWmsClient {
+
+ @PostMapping(value = "/open/allocate/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getAllocate(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/jushuitan/trackinfo/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getTrackinfo(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/jushuitan/inout/water/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getInoutWater(URI uri, @RequestBody String paramStr);
+
+ @PostMapping(value = "/open/other/inout/query", headers = {"Content-Type", "application/x-www-form-urlencoded;charset=utf-8", "Accept", "application/json"})
+ JstNewResult> getOtherInout(URI uri, @RequestBody String paramStr);
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/ModifiedTimeQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/ModifiedTimeQuery.java
new file mode 100644
index 00000000..21069efe
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/ModifiedTimeQuery.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class ModifiedTimeQuery extends PagedQuery {
+
+ @Schema(description = "修改起始时间,起始时间和 结束时间必须同时存在,时间间隔不能超过七天")
+ @JsonProperty("modified_begin")
+ private String modifiedBegin;
+
+ @Schema(description = "修改起始时间,起始时间和 结束时间必须同时存在,时间间隔不能超过七天")
+ @JsonProperty("modified_end")
+ private String modifiedEnd;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/PagedQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/PagedQuery.java
new file mode 100644
index 00000000..51ca8808
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/PagedQuery.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class PagedQuery {
+
+ @Schema(description = "第几页,从1 开始")
+ @JsonProperty("page_index")
+ private int pageIndex = 1;
+
+ @Schema(description = "默认 30,最大不超过 50")
+ @JsonProperty("page_size")
+ private int pageSize = 50;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/base/ShopsQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/base/ShopsQuery.java
new file mode 100644
index 00000000..fd84cfac
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/base/ShopsQuery.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.base;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.PagedQuery;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class ShopsQuery extends PagedQuery {
+
+ /**
+ * 店铺主账号,不支持模糊查询
+ * 请求参数为返回结果中的 short_name 字段,不支持模糊查询,必须完全匹配
+ * 如果不传店铺名,则返回全部店铺
+ */
+ private List nicks;
+
+ private List shopIds;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/base/WmsPartnerQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/base/WmsPartnerQuery.java
new file mode 100644
index 00000000..9eca5080
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/base/WmsPartnerQuery.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.base;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.PagedQuery;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class WmsPartnerQuery extends PagedQuery {
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/InventoryCountQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/InventoryCountQuery.java
new file mode 100644
index 00000000..4cf17670
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/InventoryCountQuery.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.inventory;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class InventoryCountQuery extends ModifiedTimeQuery {
+
+ /**
+ * 指定盘点单号,多个用逗号分隔,最多50,和时间段不能同时为空
+ */
+ @JsonProperty("io_ids")
+ private String ioIds;
+
+ /**
+ * 状态;WaitConfirm:待确认,Confirmed:生效,Archive:归档,Cancelled:取消,Delete:作废
+ */
+ @JsonProperty("status")
+ private String status;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/InventoryQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/InventoryQuery.java
new file mode 100644
index 00000000..3cb19c1e
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/InventoryQuery.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.inventory;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class InventoryQuery extends ModifiedTimeQuery {
+
+ /**
+ * 分仓公司编号,值不传或为0查询所有仓的总库存,其它为指定仓的库存
+ */
+ @JsonProperty("wms_co_id")
+ private Integer wmsCoId;
+
+ /**
+ * 商品编码,多个用逗号分隔,最多20,与修改时间不能同时为空
+ */
+ @JsonProperty("sku_ids")
+ private String skuIds;
+
+ /**
+ * 时间戳,防漏单,如果用ts查询不需要传时间查询条件
+ */
+ @JsonProperty("ts")
+ private Long ts;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/PackQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/PackQuery.java
new file mode 100644
index 00000000..05c65c70
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/inventory/PackQuery.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.inventory;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.PagedQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class PackQuery extends PagedQuery {
+
+ /**
+ * 商品编码列表,最多20个sku
+ */
+ @JsonProperty("sku_ids")
+ private List skuIds;
+
+ /**
+ * 仓库编号
+ */
+ @JsonProperty("wms_co_id")
+ private Integer wmsCoId;
+
+ /**
+ * 类型,Bin=仓位库存,DefaultPack=暂存位 Pack=装箱库存
+ */
+ @JsonProperty("pack_type")
+ private String packType;
+
+ /**
+ * 查询起始时间;时间条件与商品编码不能同时为空
+ */
+ @JsonProperty("start_time")
+ private String modifiedBegin;
+
+ /**
+ * 查询截止时间,时间间 隔最大1天
+ */
+ @JsonProperty("end_time")
+ private String modifiedEnd;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/CategoryQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/CategoryQuery.java
new file mode 100644
index 00000000..ed54ba86
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/CategoryQuery.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.item;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class CategoryQuery extends ModifiedTimeQuery {
+
+ /**
+ * 类目id集合
+ */
+ @JsonProperty("c_ids")
+ private List cIds;
+
+ /**
+ * 父级类目id集合
+ */
+ @JsonProperty("parent_c_ids")
+ private List parentCIds;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/CombineSkuQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/CombineSkuQuery.java
new file mode 100644
index 00000000..468c5506
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/CombineSkuQuery.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.item;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CombineSkuQuery extends ModifiedTimeQuery {
+
+ /**
+ * 商品编码列表,字符串形式,按逗号分隔
+ */
+ @JsonProperty("sku_ids")
+ private String skuIds;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/MallItemQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/MallItemQuery.java
new file mode 100644
index 00000000..c9474108
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/MallItemQuery.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.item;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class MallItemQuery extends ModifiedTimeQuery {
+
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/SkuQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/SkuQuery.java
new file mode 100644
index 00000000..9a120609
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/SkuQuery.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.item;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class SkuQuery extends ModifiedTimeQuery {
+
+ /**
+ * 商品编码列表,字符串形式,按逗号分隔
+ */
+ @JsonProperty("sku_ids")
+ private String skuIds;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/SkumapQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/SkumapQuery.java
new file mode 100644
index 00000000..b6339c29
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/item/SkumapQuery.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.item;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class SkumapQuery extends ModifiedTimeQuery {
+
+ /**
+ * 商品编码列表,字符串形式,按逗号分隔
+ */
+ @JsonProperty("sku_ids")
+ private String skuIds;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/logistics/LogisticQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/logistics/LogisticQuery.java
new file mode 100644
index 00000000..c48306fd
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/logistics/LogisticQuery.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.logistics;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class LogisticQuery extends ModifiedTimeQuery {
+
+ /**
+ * 店铺编号
+ */
+ @JsonProperty("shop_id")
+ private Integer shopId;
+
+ /**
+ * 平台订单编号,最多20
+ */
+ @JsonProperty("so_ids")
+ private List soIds;
+
+ /**
+ * 日期类型,默认发货时间,0=修改时间,1=制单日期,2=订单日期,3=发货时间
+ */
+ @JsonProperty("date_type")
+ private Integer dateType = 0;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/logistics/LogisticscompanyQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/logistics/LogisticscompanyQuery.java
new file mode 100644
index 00000000..aba8bffe
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/logistics/LogisticscompanyQuery.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.logistics;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class LogisticscompanyQuery extends ModifiedTimeQuery {
+
+ /**
+ * 公司编号,该值存在时查询对应公司或分仓下的启用的物流公司信息,否则查询系统内所有的物流公司信息
+ */
+ @JsonProperty("wms_co_id")
+ private Long wmsCoId;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/AftersaleReceivedQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/AftersaleReceivedQuery.java
new file mode 100644
index 00000000..35fa41d2
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/AftersaleReceivedQuery.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.order;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class AftersaleReceivedQuery extends ModifiedTimeQuery {
+
+ /**
+ * 外部订单号列表
+ */
+ @JsonProperty("so_ids")
+ private List soIds;
+ /**
+ * ERP 内部订单号,唯一
+ */
+ @JsonProperty("o_ids")
+ private List oIds;
+
+ /**
+ * 退货店铺
+ */
+ @JsonProperty("shop_id")
+ private String shopId;
+
+ /**
+ * 日期类型,0:修改时间,1:创建日期,2:订单日期,4:实际出/入库时间
+ */
+ @JsonProperty("date_type")
+ private Integer dateType = 0;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrderActionQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrderActionQuery.java
new file mode 100644
index 00000000..db348358
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrderActionQuery.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.order;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class OrderActionQuery extends ModifiedTimeQuery {
+
+ /**
+ * 内部订单号
+ */
+ @JsonProperty("o_id")
+ private Long oId;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrdersOutSimpleQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrdersOutSimpleQuery.java
new file mode 100644
index 00000000..012f20f6
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrdersOutSimpleQuery.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.order;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class OrdersOutSimpleQuery extends ModifiedTimeQuery {
+
+ /**
+ * 店铺编号
+ */
+ @JsonProperty("shop_id")
+ private Integer shopId;
+
+ /**
+ * shop_id为0且is_offline_shop为true查询线下店铺单据
+ */
+ @JsonProperty("is_offline_shop")
+ private Boolean isOfflineShop;
+
+ /**
+ * 指定线上订单号,和时间段不能同时为空
+ */
+ @JsonProperty("so_ids")
+ private List soIds;
+
+ /**
+ * 单据状态: WaitConfirm=待出库; Confirmed=已出库; Cancelled=作废
+ */
+ @JsonProperty("status")
+ private String status;
+
+ /**
+ * 出库仓编号
+ */
+ @JsonProperty("wms_co_id")
+ private Integer wmsCoId;
+
+ /**
+ * 内部单号最大50条;与时间条件不能同时为空
+ */
+ @JsonProperty("o_ids")
+ private List oIds;
+
+ /**
+ * 物流单号;不超过20条
+ */
+ @JsonProperty("l_ids")
+ private List lIds;
+
+ /**
+ * 拣货批次号;不超过50条 与时间条件不能同时为空
+ */
+ @JsonProperty("wave_ids")
+ private List waveIds;
+
+ /**
+ * 时间戳,sql server中的行版本号,该字段查询防止分页过程中漏单
+ */
+ @JsonProperty("start_ts")
+ private Long startTs;
+
+ /**
+ * 是否查询总条数默认true,如果使用start_ts查询,该值传false否则影响查询效率
+ */
+ @JsonProperty("is_get_total")
+ private Boolean isGetTotal;
+
+ /**
+ * 出库单号列表,最大50
+ */
+ @JsonProperty("io_ids")
+ private List ioIds;
+
+ /**
+ * 货主编码
+ */
+ @JsonProperty("owner_co_id")
+ private Long ownerCoId;
+
+ /**
+ * 是否获取跨境财务信息
+ */
+ @JsonProperty("is_get_cbfinance")
+ private Boolean isGetCbfinance;
+
+ /**
+ * 时间类型 0:修改时间modified,1:创建时间created,2:出库时间io_date;默认0
+ */
+ @JsonProperty("date_type")
+ private Integer dateType = 0;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrdersSingleQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrdersSingleQuery.java
new file mode 100644
index 00000000..2c1cc6fd
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/order/OrdersSingleQuery.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.order;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class OrdersSingleQuery extends ModifiedTimeQuery {
+
+ /**
+ * 店铺编号
+ */
+ @JsonProperty("shop_id")
+ private Integer shopId;
+
+ /**
+ * 线上单号,最大限制20条
+ */
+ @JsonProperty("so_ids")
+ private List soIds;
+
+ /**
+ * 待付款:WaitPay;发货中:Delivering;被合并:Merged;异常:Question;被拆分:Split;等供销商|外仓发货:WaitOuterSent;已付款待审核:WaitConfirm;已客审待财审:WaitFConfirm;已发货:Sent;取消:Cancelled
+ */
+ @JsonProperty("status")
+ private String status;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseQuery.java
new file mode 100644
index 00000000..19be1d4d
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseQuery.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.purchase;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class PurchaseQuery extends ModifiedTimeQuery {
+
+ /**
+ * 外部订单号列表
+ */
+ @JsonProperty("so_ids")
+ private List soIds;
+
+ /**
+ * 采购单号列表
+ */
+ @JsonProperty("po_ids")
+ private List poIds;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseinQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseinQuery.java
new file mode 100644
index 00000000..d637283f
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseinQuery.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.purchase;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class PurchaseinQuery extends ModifiedTimeQuery {
+
+ /**
+ * 采购单号列表,与修改时间不能同时为空.采购单号最大不能超过30条
+ */
+ @JsonProperty("po_ids")
+ private List poIds;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseoutQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseoutQuery.java
new file mode 100644
index 00000000..00066806
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/PurchaseoutQuery.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.purchase;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class PurchaseoutQuery extends ModifiedTimeQuery {
+
+ /**
+ * 指定线上订单号,和时间段不能同时为空
+ */
+ @JsonProperty("so_ids")
+ private List soIds;
+
+ /**
+ * 单据状态,Confirmed=生效,WaitConfirm待审核,Creating=草拟,Archive=归档,Cancelled=作废
+ */
+ private String status;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/SupplierQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/SupplierQuery.java
new file mode 100644
index 00000000..71fa85f7
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/purchase/SupplierQuery.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.purchase;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class SupplierQuery extends ModifiedTimeQuery {
+
+ /**
+ * 供应商编码
+ */
+ @JsonProperty("supplier_codes")
+ private List supplierCodes;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/refund/RefundSingleQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/refund/RefundSingleQuery.java
new file mode 100644
index 00000000..36b50929
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/refund/RefundSingleQuery.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.refund;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class RefundSingleQuery extends ModifiedTimeQuery {
+
+ /**
+ * 指定线上订单号,和时间段不能同时为空
+ */
+ @JsonProperty("so_ids")
+ private List soIds;
+
+ /**
+ * 指定买家账号,最多50
+ */
+ @JsonProperty("shop_buyer_ids")
+ private List shopBuyerIds;
+
+ /**
+ * 店铺编号
+ */
+ @JsonProperty("shop_id")
+ private Integer shopId;
+
+ /**
+ * shop_id为0且is_offline_shop为true查询线下店铺单据
+ */
+ @JsonProperty("is_offline_shop")
+ private Boolean isOfflineShop;
+
+ /**
+ * 指定内部单号,和时间段不能同时为空
+ */
+ @JsonProperty("o_ids")
+ private List oIds;
+
+ /**
+ * 指定售后单号,和时间段不能同时为空
+ */
+ @JsonProperty("as_ids")
+ private List asIds;
+
+ /**
+ * 售后单状态(WaitConfirm:待确认,Confirmed:已确认,Cancelled:作废,Merged:被合并)
+ */
+ @JsonProperty("status")
+ private String status;
+
+ /**
+ * 时间戳,sql server中的行版本号,该字段查询防止分页过程中漏单
+ */
+ @JsonProperty("start_ts")
+ private Long startTs;
+
+ /**
+ * 是否查询总条数默认true,如果使用start_ts查询,该值传false否则影响查询效率
+ */
+ @JsonProperty("is_get_total")
+ private Boolean isGetTotal;
+
+ /**
+ * 货物状态(BUYER_NOT_RECEIVED:买家未收到货,BUYER_RECEIVED:买家已收到货,BUYER_RETURNED_GOODS:买家已退货,SELLER_RECEIVED:卖家已收到退货)
+ */
+ @JsonProperty("good_status")
+ private String goodStatus;
+
+ /**
+ * 售后类型,普通退货,其它,拒收退货,仅退款,投诉,补发,换货,维修
+ */
+ @JsonProperty("type")
+ private String type;
+
+ /**
+ * 货主编码
+ */
+ @JsonProperty("owner_co_id")
+ private Long ownerCoId;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/AllocateQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/AllocateQuery.java
new file mode 100644
index 00000000..68c14d27
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/AllocateQuery.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.wms;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class AllocateQuery extends ModifiedTimeQuery {
+
+ /**
+ * 指定线上订单号,和时间段不能同时为空
+ */
+ @JsonProperty("so_ids")
+ private List soIds;
+
+ /**
+ * 调拨单号
+ */
+ @JsonProperty("io_ids")
+ private List ioIds;
+
+ /**
+ * 调拨类型(调拨出,调拨入)
+ */
+ @JsonProperty("type")
+ private String type;
+
+ /**
+ * 0:修改时间,modified。 2:出入库时间 io_date,未传入时默认为0
+ */
+ @JsonProperty("date_type")
+ private Integer dateType;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/InoutWaterQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/InoutWaterQuery.java
new file mode 100644
index 00000000..7c4d70ef
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/InoutWaterQuery.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.wms;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.PagedQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class InoutWaterQuery extends PagedQuery {
+
+ @Schema(description = "开始时间")
+ @JsonProperty("start_time")
+ private String startTime;
+
+ @Schema(description = "结束时间")
+ @JsonProperty("end_time")
+ private String endEime;
+
+ @Schema(description = "默认0,0=修改时间;1=制单日期;2=出入库时间")
+ @JsonProperty("date_type")
+ private Integer dateType;
+
+ @Schema(description = "单据类型,采购进仓,采购退货,调拨出,调拨入,加工出仓,加工进仓,盘点,销售出仓,销售退货,其它出库,其它进仓,其它退货")
+ @JsonProperty("type")
+ private String type;
+
+ @Schema(description = "分仓编号")
+ @JsonProperty("wms_co_id")
+ private Integer wmsCoId;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/OtherInoutQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/OtherInoutQuery.java
new file mode 100644
index 00000000..3f8342c0
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/OtherInoutQuery.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.wms;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class OtherInoutQuery extends ModifiedTimeQuery {
+
+ @Schema(description = "指定线上订单号,和时间段不能同时为空,,最多50个")
+ @JsonProperty("so_ids")
+ private List soIds;
+
+ @Schema(description = "单据类型:其它退货,其它出库,其它进仓")
+ @JsonProperty("types")
+ private List types;
+
+ @Schema(description = "单据状态,Confirmed生效,WaitConfirm待审核,OuterConfirming外部确认中,Cancelled取消(单据生效后的作废),Delete作废(单据生效前的作废)")
+ @JsonProperty("status")
+ private String status;
+
+ @Schema(description = "分仓编号")
+ @JsonProperty("wms_co_id")
+ private Long wmsCoId;
+
+ @Schema(description = "出仓单号列表,最多50个")
+ @JsonProperty("io_ids")
+ private List ioIds;
+
+ @Schema(description = "0:修改时间,modified。 2:出入库时间 io_date,未传入时默认为0")
+ @JsonProperty("date_type")
+ private Integer dateType;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/TrackinfoQuery.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/TrackinfoQuery.java
new file mode 100644
index 00000000..22b69240
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/request/wms/TrackinfoQuery.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.request.wms;
+
+import cn.sliew.carp.module.http.sync.remote.jst.request.ModifiedTimeQuery;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class TrackinfoQuery extends ModifiedTimeQuery {
+
+ @Schema(description = "唯一码")
+ @JsonProperty("sku_sn")
+ private String skuSn;
+
+ @Schema(description = "快递单号")
+ @JsonProperty("l_id")
+ private String lId;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/JstNewResult.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/JstNewResult.java
new file mode 100644
index 00000000..3c021bed
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/JstNewResult.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class JstNewResult {
+
+ private Integer code;
+ private String msg;
+ private T data;
+ @JsonProperty("request_id")
+ private String requestId;
+
+ public boolean isSuccess() {
+ return code != null && code == 0;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/JstResult.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/JstResult.java
new file mode 100644
index 00000000..6bd0b2cf
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/JstResult.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.lang.Nullable;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class JstResult {
+
+ @JsonProperty("page_index")
+ private int pageIndex;
+
+ @JsonProperty("page_size")
+ private int pageSize;
+
+ @Nullable
+ @JsonProperty("data_count")
+ private int dataCount;
+
+ @Nullable
+ @JsonProperty("page_count")
+ private int pageCount;
+
+ @JsonProperty("has_next")
+ private boolean hasNext;
+
+ @JsonProperty("issuccess")
+ private boolean issuccess;
+
+ private int code;
+ private String msg;
+ private List datas;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/auth/JstAccessTokenDO.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/auth/JstAccessTokenDO.java
new file mode 100644
index 00000000..387613ae
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/auth/JstAccessTokenDO.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.auth;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class JstAccessTokenDO {
+
+ /**
+ * 访问令牌
+ */
+ @JsonProperty("access_token")
+ private String accessToken;
+
+ /**
+ * access_token访问过期时间【单位是秒】,还有多少秒后过期
+ */
+ @JsonProperty("expires_in")
+ private Long expiresIn;
+
+ /**
+ * 更新令牌
+ */
+ @JsonProperty("refresh_token")
+ private String refreshToken;
+
+ /**
+ * 固定值:all
+ */
+ @JsonProperty("scope")
+ private String scope;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/JstShopsResult.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/JstShopsResult.java
new file mode 100644
index 00000000..a3423e1a
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/JstShopsResult.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.base;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class JstShopsResult {
+
+ private int code;
+ private boolean issuccess;
+ private String msg;
+
+ private List shops;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/ShopDO.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/ShopDO.java
new file mode 100644
index 00000000..59d98ffd
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/ShopDO.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.base;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ShopDO {
+
+ @JsonProperty("shop_id")
+ private Long shopId;
+
+ @JsonProperty("shop_name")
+ private String shopName;
+
+ @JsonProperty("co_id")
+ private Long coId;
+
+ @JsonProperty("shop_site")
+ private String shopSite;
+
+ @JsonProperty("shop_url")
+ private String shopUrl;
+
+ @JsonProperty("created")
+ private String created;
+
+ @JsonProperty("nick")
+ private String nick;
+
+ @JsonProperty("session_expired")
+ private String sessionExpired;
+
+ @JsonProperty("session_uid")
+ private String sessionUid;
+
+ @JsonProperty("short_name")
+ private String shortName;
+
+ @JsonProperty("organization")
+ private String organization;
+
+ @JsonProperty("group_id")
+ private Long groupId;
+
+ @JsonProperty("group_name")
+ private String groupName;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/WmsPartnerDO.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/WmsPartnerDO.java
new file mode 100644
index 00000000..f5671fc0
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/base/WmsPartnerDO.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.base;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class WmsPartnerDO {
+
+ /**
+ * 分仓名称
+ */
+ @JsonProperty("name")
+ private String name;
+
+ /**
+ * 主仓公司编号
+ */
+ @JsonProperty("co_id")
+ private Integer coId;
+
+ /**
+ * 分仓编号
+ */
+ @JsonProperty("wms_co_id")
+ private Integer wmsCoId;
+
+ /**
+ * 是否为主仓,true=主仓
+ */
+ @JsonProperty("is_main")
+ private String isMain;
+
+ /**
+ * 仓储列表里的状态,不是仓库账号的状态
+ */
+ @JsonProperty("status")
+ private String status;
+
+ /**
+ * 我方备注
+ */
+ @JsonProperty("remark1")
+ private String remark1;
+
+ /**
+ * 对方备注
+ */
+ @JsonProperty("remark2")
+ private String remark2;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/InventoryCountDO.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/InventoryCountDO.java
new file mode 100644
index 00000000..03467790
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/InventoryCountDO.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.inventory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class InventoryCountDO {
+
+ /**
+ * 单据类型
+ */
+ @JsonProperty("type")
+ private String type;
+
+ /**
+ * 盘点单号
+ */
+ @JsonProperty("io_id")
+ private Long ioId;
+
+ /**
+ * 单据日期
+ */
+ @JsonProperty("io_date")
+ private String ioDate;
+
+ /**
+ * 状态;WaitConfirm:待确认,Confirmed:生效,Archive:归档,Cancelled:取消,Delete:作废
+ */
+ @JsonProperty("status")
+ private String status;
+
+ /**
+ * 仓库名称
+ */
+ @JsonProperty("warehouse")
+ private String warehouse;
+
+ /**
+ * 创建人
+ */
+ @JsonProperty("creator_name")
+ private String creatorName;
+
+ /**
+ * 备注
+ */
+ @JsonProperty("remark")
+ private String remark;
+
+ /**
+ * 仓库编号,主仓=1,销退仓=2, 进货仓=3,次品仓 = 4
+ */
+ @JsonProperty("wh_id")
+ private Long whId;
+
+ /**
+ * 分仓编号
+ */
+ @JsonProperty("wms_co_id")
+ private Long wmsCoId;
+
+ /**
+ * 修改时间
+ */
+ @JsonProperty("modified")
+ private String modified;
+
+ /**
+ * 商品集合
+ */
+ private List items;
+
+ /**
+ * 批次集合,获取该节点系统中相关业务项需配置
+ */
+ private List batchs;
+
+ /**
+ * labels
+ */
+ @JsonProperty("labels")
+ private List labels;
+
+ /**
+ * ts
+ */
+ @JsonProperty("ts")
+ private Long ts;
+
+ /**
+ * f_status
+ */
+ @JsonProperty("f_status")
+ private String fStatus;
+
+ /**
+ * lock_wh_id
+ */
+ @JsonProperty("lock_wh_id")
+ private Integer lockWhId;
+
+ /**
+ * 唯一码集合,获取该节点系统中相关业务项需配置
+ */
+ @JsonProperty("sns")
+ private List sns;
+
+ @Getter
+ @Setter
+ public static class ItemDO {
+
+ /**
+ * 盘点单号
+ */
+ @JsonProperty("io_id")
+ private Long ioId;
+
+ /**
+ * 子单号
+ */
+ @JsonProperty("ioi_id")
+ private Long ioiId;
+
+ /**
+ * 商品编码
+ */
+ @JsonProperty("sku_id")
+ private String skuId;
+
+ /**
+ * 商品名称
+ */
+ @JsonProperty("name")
+ private String name;
+
+ /**
+ * 颜色及规格
+ */
+ @JsonProperty("properties_value")
+ private String propertiesValue;
+
+ /**
+ * 盘点后数量
+ */
+ @JsonProperty("r_qty")
+ private Integer rQty;
+
+ /**
+ * 盈亏数量
+ */
+ @JsonProperty("qty")
+ private Integer qty;
+ }
+
+ @Getter
+ @Setter
+ public static class BatchDO {
+
+ /**
+ * 批次号
+ */
+ @JsonProperty("batch_no")
+ private String batchNo;
+
+ /**
+ * 商品编码
+ */
+ @JsonProperty("sku_id")
+ private String skuId;
+
+ /**
+ * 数量
+ */
+ @JsonProperty("qty")
+ private Integer qty;
+
+ /**
+ * 批次日期
+ */
+ @JsonProperty("product_date")
+ private String productDate;
+
+ /**
+ * 供应商编号
+ */
+ @JsonProperty("supplier_id")
+ private Long supplierId;
+
+ /**
+ * 供应商名称
+ */
+ @JsonProperty("supplier_name")
+ private String supplierName;
+
+ /**
+ * 有效期至
+ */
+ @JsonProperty("expiration_date")
+ private String expirationDate;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/InventoryDO.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/InventoryDO.java
new file mode 100644
index 00000000..c5faf68b
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/InventoryDO.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.inventory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class InventoryDO {
+
+ /**
+ * 商品编码
+ */
+ @JsonProperty("sku_id")
+ private String skuId;
+
+ /**
+ * 款式编码
+ */
+ @JsonProperty("i_id")
+ private String iId;
+
+ /**
+ * 主仓实际库存
+ */
+ @JsonProperty("qty")
+ private Integer qty;
+
+ /**
+ * 虚拟库存
+ */
+ @JsonProperty("order_lock")
+ private Integer orderLock;
+
+ /**
+ * 店铺编号
+ */
+ @JsonProperty("virtual_qty")
+ private Integer virtualQty;
+
+ /**
+ * 采购在途数
+ */
+ @JsonProperty("purchase_qty")
+ private Integer purchaseQty;
+
+ /**
+ * 销退仓库存
+ */
+ @JsonProperty("return_qty")
+ private Integer returnQty;
+
+ /**
+ * 进货仓库存
+ */
+ @JsonProperty("in_qty")
+ private Integer inQty;
+
+ /**
+ * 次品库存
+ */
+ @JsonProperty("defective_qty")
+ private Integer defectiveQty;
+
+ /**
+ * 修改时间,用此时间作为下一次查询的起始时间
+ */
+ @JsonProperty("modified")
+ private String modified;
+
+ /**
+ * 安全库存下限
+ */
+ @JsonProperty("min_qty")
+ private Integer minQty;
+
+ /**
+ * 安全库存上限
+ */
+ @JsonProperty("max_qty")
+ private Integer maxQty;
+
+ /**
+ * 商品名称
+ */
+ @JsonProperty("name")
+ private String name;
+
+ /**
+ * 仓库待发数
+ */
+ @JsonProperty("pick_lock")
+ private Integer pickLock;
+
+ /**
+ * 调拨在途数
+ */
+ @JsonProperty("allocate_qty")
+ private Integer allocateQty;
+
+ /**
+ * 时间戳
+ */
+ @JsonProperty("ts")
+ private Long ts;
+
+ /**
+ * 自定义仓1
+ */
+ @JsonProperty("customize_qty_1")
+ private Integer customizeQty1;
+
+ /**
+ * 自定义仓2
+ */
+ @JsonProperty("customize_qty_2")
+ private Integer customizeQty2;
+
+ /**
+ * 自定义仓3
+ */
+ @JsonProperty("customize_qty_3")
+ private Integer customizeQty3;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/JstInventoryResult.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/JstInventoryResult.java
new file mode 100644
index 00000000..1a7f6978
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/JstInventoryResult.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.inventory;
+
+import cn.sliew.carp.module.http.sync.remote.jst.response.JstResult;
+import cn.sliew.carp.module.http.sync.remote.jst.response.inventory.InventoryDO;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class JstInventoryResult extends JstResult {
+
+ @JsonIgnoreProperties(allowGetters = false, allowSetters = true)
+ private List inventorys;
+
+ @Override
+ public List getDatas() {
+ return inventorys;
+ }
+
+ @Override
+ public void setDatas(List datas) {
+ this.inventorys = inventorys;
+ }
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/PackDO.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/PackDO.java
new file mode 100644
index 00000000..43c09dfe
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/inventory/PackDO.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.inventory;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class PackDO {
+
+ /**
+ * 仓库id
+ */
+ @JsonProperty("wms_co_id")
+ private Integer wmsCoId;
+
+ /**
+ * 箱号
+ */
+ @JsonProperty("pack_id")
+ private String packId;
+
+ /**
+ * 仓库编号;1=主仓,2=销退仓, 3=进货仓,4=次品仓
+ */
+ @JsonProperty("wh_id")
+ private Integer whId;
+
+ /**
+ * 类型
+ */
+ @JsonProperty("pack_type")
+ private String packType;
+
+ /**
+ * 仓位
+ */
+ @JsonProperty("bin")
+ private String bin;
+
+ /**
+ * 明细仓位
+ */
+ @JsonProperty("item_bin")
+ private String itemBin;
+
+ /**
+ * 商品编码
+ */
+ @JsonProperty("sku_id")
+ private String skuId;
+
+ /**
+ * 数量
+ */
+ @JsonProperty("qty")
+ private Integer qty;
+
+ /**
+ * 有效期
+ */
+ @JsonProperty("expiration_date")
+ private String expirationDate;
+
+ /**
+ * 生产日期
+ */
+ @JsonProperty("product_date")
+ private String productDate;
+
+ /**
+ * 生产批次
+ */
+ @JsonProperty("batch_no")
+ private String batchNo;
+
+ /**
+ * 修改时间
+ */
+ @JsonProperty("modified")
+ private String modified;
+
+ /**
+ * 供应商ID
+ */
+ @JsonProperty("supplier_id")
+ private String supplierId;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/item/CategoryDO.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/item/CategoryDO.java
new file mode 100644
index 00000000..6b7dcc8d
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/item/CategoryDO.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.item;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CategoryDO {
+
+ /**
+ * 类目id
+ */
+ @JsonProperty("c_id")
+ private Long cId;
+
+ /**
+ * 父级类目id
+ */
+ @JsonProperty("parent_c_id")
+ private Long parentCId;
+
+ /**
+ * 修改时间
+ */
+ @JsonProperty("modified")
+ private String modified;
+
+ /**
+ * 类目名称
+ */
+ @JsonProperty("name")
+ private String name;
+}
diff --git a/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/item/CombineSkuDO.java b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/item/CombineSkuDO.java
new file mode 100644
index 00000000..8291805e
--- /dev/null
+++ b/carp-modules/carp-module-http-sync/carp-module-http-remote/carp-module-http-remote-jst/src/main/java/cn/sliew/carp/module/http/sync/remote/jst/response/item/CombineSkuDO.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package cn.sliew.carp.module.http.sync.remote.jst.response.item;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
+@Getter
+@Setter
+public class CombineSkuDO {
+
+ /**
+ * 组合款式编码
+ */
+ @JsonProperty("i_id")
+ private String iId;
+
+ /**
+ * 组合商品名称
+ */
+ @JsonProperty("name")
+ private String name;
+
+ /**
+ * 简称
+ */
+ @JsonProperty("short_name")
+ private String shortName;
+
+ /**
+ * 虚拟分类
+ */
+ @JsonProperty("vc_name")
+ private String vcName;
+
+ /**
+ * 图片地址
+ */
+ @JsonProperty("pic")
+ private String pic;
+
+ /**
+ * 组合颜色及规格
+ */
+ @JsonProperty("properties_value")
+ private String propertiesValue;
+
+ /**
+ * 组合售价
+ */
+ @JsonProperty("sale_price")
+ private BigDecimal salePrice;
+
+ /**
+ * 组合重量
+ */
+ @JsonProperty("weight")
+ private BigDecimal weight;
+
+ /**
+ * 组合装编码
+ */
+ @JsonProperty("sku_id")
+ private String skuId;
+
+ /**
+ * 组合装商品成本价
+ */
+ @JsonProperty("cost_price")
+ private Integer costPrice;
+
+ /**
+ * 修改时间
+ */
+ @JsonProperty("modified")
+ private String modified;
+
+ /**
+ * 创建时间
+ */
+ @JsonProperty("created")
+ private String created;
+
+ /**
+ * 商品列表
+ */
+ private List