Browse Source

feat : 数据同步服务, 数据拉取接口代码提交

bilingfeng 2 years ago
parent
commit
6e0200e35f
29 changed files with 1259 additions and 2 deletions
  1. 4 0
      game-platform/game-platform-serve/pom.xml
  2. 30 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/controller/PlatformDeYangController.java
  3. 12 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/dao/mapper/GamePlatformAccountMapper.java
  4. 12 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/dao/mapper/GamePlatformMapper.java
  5. 51 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/enums/GamePlatformEnum.java
  6. 15 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/exception/UnsupportedException.java
  7. 37 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/dto/PlatformDeYangAccountDTO.java
  8. 5 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/dto/PlatformDeYangOrderDTO.java
  9. 5 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/dto/PlatformDeYangUserDTO.java
  10. 90 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/entity/GamePlatform.java
  11. 100 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/entity/GamePlatformAccount.java
  12. 10 1
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/entity/PlatformDeYangOrder.java
  13. 10 1
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/entity/PlatformDeYangUser.java
  14. 28 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/res/PlatformDeYangBaseRes.java
  15. 22 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/res/PlatformDeYangOrderRes.java
  16. 22 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/res/PlatformDeYangUserRes.java
  17. 12 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/IGamePlatformAccountService.java
  18. 20 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/IGamePlatformService.java
  19. 10 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/IPlatformDeYangOrderService.java
  20. 10 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/IPlatformDeYangUserService.java
  21. 18 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/impl/GamePlatformAccountServiceImpl.java
  22. 26 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/impl/GamePlatformServiceImpl.java
  23. 42 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/impl/PlatformDeYangOrderServiceImpl.java
  24. 49 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/impl/PlatformDeYangUserServiceImpl.java
  25. 97 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/platform/PlatformBaseService.java
  26. 222 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/platform/PlatformDeYangService.java
  27. 99 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/task/SyncPlatformOrderTask.java
  28. 99 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/task/SyncPlatformUserTask.java
  29. 102 0
      game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/utils/SpringUtils.java

+ 4 - 0
game-platform/game-platform-serve/pom.xml

@@ -75,6 +75,10 @@
             <groupId>com.zanxiang.module</groupId>
             <artifactId>zx-web</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.zanxiang.module</groupId>
+            <artifactId>zx-redis</artifactId>
+        </dependency>
         <!-- Mybatis Plus -->
         <dependency>
             <groupId>com.baomidou</groupId>

+ 30 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/controller/PlatformDeYangController.java

@@ -1,15 +1,23 @@
 package com.zanxiang.game.platform.serve.controller;
 
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatform;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatformAccount;
+import com.zanxiang.game.platform.serve.service.IGamePlatformAccountService;
+import com.zanxiang.game.platform.serve.service.IGamePlatformService;
+import com.zanxiang.game.platform.serve.service.platform.PlatformDeYangService;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 /**
  * @author : lingfeng
  * @time : 2023-05-22
@@ -21,6 +29,15 @@ import org.springframework.web.bind.annotation.RestController;
 @RequestMapping("/deYang/game")
 public class PlatformDeYangController {
 
+    @Autowired
+    private IGamePlatformService gamePlatformService;
+
+    @Autowired
+    private IGamePlatformAccountService gamePlatformAccountService;
+
+    @Autowired
+    private PlatformDeYangService platformDeYangService;
+
     @ApiOperation(value = "用户信息同步接口")
     @GetMapping("/user")
     @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
@@ -36,4 +53,17 @@ public class PlatformDeYangController {
         System.out.println("德扬订单信息手动同步");
         return ResultVO.ok(Boolean.FALSE);
     }
+
+    @ApiOperation(value = "测试")
+    @GetMapping("/test")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<Boolean> test() {
+        GamePlatform gamePlatform = gamePlatformService.getById(1L);
+        List<GamePlatformAccount> list = gamePlatformAccountService.list();
+        list.forEach(l -> {
+            platformDeYangService.syncUserByAccount(gamePlatform, l, null, null);
+        });
+        return ResultVO.ok(Boolean.FALSE);
+    }
+
 }

+ 12 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/dao/mapper/GamePlatformAccountMapper.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.platform.serve.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatformAccount;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : ${description}
+ */
+public interface GamePlatformAccountMapper extends BaseMapper<GamePlatformAccount> {
+}

+ 12 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/dao/mapper/GamePlatformMapper.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.platform.serve.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatform;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : ${description}
+ */
+public interface GamePlatformMapper extends BaseMapper<GamePlatform> {
+}

+ 51 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/enums/GamePlatformEnum.java

@@ -0,0 +1,51 @@
+package com.zanxiang.game.platform.serve.enums;
+
+import com.zanxiang.game.platform.serve.service.platform.PlatformBaseService;
+import com.zanxiang.game.platform.serve.service.platform.PlatformDeYangService;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 游戏平台枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum GamePlatformEnum {
+
+    /**
+     * 德扬游戏
+     */
+    DE_YANG("DE_YANG", "德扬游戏", PlatformDeYangService.class);
+
+    /**
+     * 平台key
+     */
+    private final String platformKey;
+
+    /**
+     * 平台名称
+     */
+    private final String platformName;
+
+    /**
+     * 实现类
+     */
+    private final Class<? extends PlatformBaseService> clazz;
+
+    /**
+     * 根据游戏平台key获取枚举
+     *
+     * @param key : 游戏平台key
+     * @return : 游戏平台枚举
+     */
+    public static GamePlatformEnum getByKey(String key) {
+        for (GamePlatformEnum gamePlatformEnum : GamePlatformEnum.values()) {
+            if (gamePlatformEnum.getPlatformKey().equals(key)) {
+                return gamePlatformEnum;
+            }
+        }
+        return null;
+    }
+}

+ 15 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/exception/UnsupportedException.java

@@ -0,0 +1,15 @@
+package com.zanxiang.game.platform.serve.exception;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 自定义异常
+ */
+public class UnsupportedException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public UnsupportedException(String msg) {
+        super(msg);
+    }
+}

+ 37 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/dto/PlatformDeYangAccountDTO.java

@@ -0,0 +1,37 @@
+package com.zanxiang.game.platform.serve.pojo.dto;
+
+import lombok.Data;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 德扬账号
+ */
+@Data
+public class PlatformDeYangAccountDTO {
+
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 账号
+     */
+    private String account;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 账号id
+     */
+    private String agentId;
+
+    /**
+     * 密钥
+     */
+    private String secret;
+}

+ 5 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/dto/PlatformDeYangOrderDTO.java

@@ -82,4 +82,9 @@ public class PlatformDeYangOrderDTO {
      * 回传信息
      */
     private String toufang_back;
+
+    /**
+     * 分销号id
+     */
+    private String agent_id2;
 }

+ 5 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/dto/PlatformDeYangUserDTO.java

@@ -102,4 +102,9 @@ public class PlatformDeYangUserDTO {
      * 注册UA
      */
     private String user_agent;
+
+    /**
+     * 分销号id
+     */
+    private String agent_id2;
 }

+ 90 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/entity/GamePlatform.java

@@ -0,0 +1,90 @@
+package com.zanxiang.game.platform.serve.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 游戏平台
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName("t_game_platform")
+public class GamePlatform implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.INPUT)
+    private Long id;
+
+    /**
+     * 平台名称
+     */
+    private String platformName;
+
+    /**
+     * 平台的 key
+     */
+    private String platformKey;
+
+    /**
+     * 普通账号访问链接
+     */
+    private String link;
+
+    /**
+     * vip账号访问链接
+     */
+    private String vipLink;
+
+    /**
+     * 平台参数
+     */
+    private String configParam;
+
+    /**
+     * 开始有数据的日期(方便拉数据)
+     */
+    private LocalDate beginTime;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 创建者
+     */
+    private Long createBy;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 更新者
+     */
+    private Long updateBy;
+}

+ 100 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/entity/GamePlatformAccount.java

@@ -0,0 +1,100 @@
+package com.zanxiang.game.platform.serve.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 游戏账号表
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName("t_game_platform_account")
+public class GamePlatformAccount implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 未使用状态
+     */
+    public static final Integer UN_USE_STATUS = 0;
+
+    /**
+     * 已使用状态
+     */
+    public static final Integer USE_STATUS = 1;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.INPUT)
+    private Long id;
+
+    /**
+     * 平台的 key
+     */
+    private String platformKey;
+
+    /**
+     * 所属期数
+     */
+    private Long periodId;
+
+    /**
+     * 账号
+     */
+    private String account;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 账号的配置参数,json数据
+     */
+    private String configParam;
+
+    /**
+     * 状态,0:未使用,1:已使用
+     */
+    private Integer status;
+
+    /**
+     * 是否删除, 0 : 未删除, 1 : 已删除
+     */
+    @TableLogic
+    private Boolean deleted;
+
+    /**
+     * 创建者
+     */
+    private Long createBy;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新者
+     */
+    private Long updateBy;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 10 - 1
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/entity/PlatformDeYangOrder.java

@@ -10,7 +10,6 @@ import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 import java.time.LocalDateTime;
-import java.util.Date;
 
 /**
  * @author : lingfeng
@@ -32,6 +31,11 @@ public class PlatformDeYangOrder implements Serializable {
     @TableId(value = "order_id", type = IdType.INPUT)
     private String orderId;
 
+    /**
+     * 平台的 key
+     */
+    private String platformKey;
+
     /**
      * 平台账号id, 用户唯一标识
      */
@@ -96,4 +100,9 @@ public class PlatformDeYangOrder implements Serializable {
      * 回传信息
      */
     private String touFangBack;
+
+    /**
+     * 分销号id
+     */
+    private String agentId;
 }

+ 10 - 1
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/entity/PlatformDeYangUser.java

@@ -10,7 +10,6 @@ import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 import java.time.LocalDateTime;
-import java.util.Date;
 
 /**
  * @author : lingfeng
@@ -32,6 +31,11 @@ public class PlatformDeYangUser implements Serializable {
     @TableId(value = "uid", type = IdType.INPUT)
     private Long uid;
 
+    /**
+     * 平台的 key
+     */
+    private String platformKey;
+
     /**
      * 公众号openId
      */
@@ -116,4 +120,9 @@ public class PlatformDeYangUser implements Serializable {
      * 注册UA
      */
     private String userAgent;
+
+    /**
+     * 分销号id
+     */
+    private String agentId;
 }

+ 28 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/res/PlatformDeYangBaseRes.java

@@ -0,0 +1,28 @@
+package com.zanxiang.game.platform.serve.pojo.res;
+
+import lombok.Data;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 德扬接口返回超类
+ */
+@Data
+public class PlatformDeYangBaseRes {
+
+    /**
+     * 状态码
+     */
+    private Long status;
+
+    /**
+     * 错误消息
+     */
+    private String msg;
+
+    /**
+     * 分页总数
+     */
+    //todo : 字段需要与德扬定义德接口一致
+    private Integer totalPage;
+}

+ 22 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/res/PlatformDeYangOrderRes.java

@@ -0,0 +1,22 @@
+package com.zanxiang.game.platform.serve.pojo.res;
+
+import com.zanxiang.game.platform.serve.pojo.dto.PlatformDeYangOrderDTO;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 订单信息返回
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class PlatformDeYangOrderRes extends PlatformDeYangBaseRes {
+
+    /**
+     * 订单列表
+     */
+    private List<PlatformDeYangOrderDTO> list;
+}

+ 22 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/pojo/res/PlatformDeYangUserRes.java

@@ -0,0 +1,22 @@
+package com.zanxiang.game.platform.serve.pojo.res;
+
+import com.zanxiang.game.platform.serve.pojo.dto.PlatformDeYangUserDTO;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 用户信息返回
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class PlatformDeYangUserRes extends PlatformDeYangBaseRes {
+
+    /**
+     * 用户信息列表
+     */
+    private List<PlatformDeYangUserDTO> list;
+}

+ 12 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/IGamePlatformAccountService.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.platform.serve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatformAccount;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description :
+ */
+public interface IGamePlatformAccountService extends IService<GamePlatformAccount> {
+}

+ 20 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/IGamePlatformService.java

@@ -0,0 +1,20 @@
+package com.zanxiang.game.platform.serve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatform;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description :
+ */
+public interface IGamePlatformService extends IService<GamePlatform> {
+
+    /**
+     * 通过平台关键
+     *
+     * @param platformKey 平台关键
+     * @return {@link GamePlatform}
+     */
+    GamePlatform getByPlatformKey(String platformKey);
+}

+ 10 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/IPlatformDeYangOrderService.java

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.zanxiang.game.platform.serve.pojo.dto.PlatformDeYangOrderDTO;
 import com.zanxiang.game.platform.serve.pojo.entity.PlatformDeYangOrder;
 
+import java.util.List;
+
 /**
  * @author : lingfeng
  * @time : 2023-05-22
@@ -18,4 +20,12 @@ public interface IPlatformDeYangOrderService extends IService<PlatformDeYangOrde
      * @return {@link Boolean}
      */
     Boolean addOrUpdate(PlatformDeYangOrderDTO orderDTO);
+
+    /**
+     * 保存或更新
+     *
+     * @param orderList 订单列表
+     * @return boolean
+     */
+    boolean saveOrUpdate(List<PlatformDeYangOrder> orderList);
 }

+ 10 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/IPlatformDeYangUserService.java

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.zanxiang.game.platform.serve.pojo.dto.PlatformDeYangUserDTO;
 import com.zanxiang.game.platform.serve.pojo.entity.PlatformDeYangUser;
 
+import java.util.List;
+
 /**
  * @author : lingfeng
  * @time : 2023-05-22
@@ -18,4 +20,12 @@ public interface IPlatformDeYangUserService extends IService<PlatformDeYangUser>
      * @return {@link Boolean}
      */
     Boolean addOrUpdate(PlatformDeYangUserDTO userDTO);
+
+    /**
+     * 保存或更新
+     *
+     * @param userList 用户列表
+     * @return boolean
+     */
+    boolean saveOrUpdate(List<PlatformDeYangUser> userList);
 }

+ 18 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/impl/GamePlatformAccountServiceImpl.java

@@ -0,0 +1,18 @@
+package com.zanxiang.game.platform.serve.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.platform.serve.dao.mapper.GamePlatformAccountMapper;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatformAccount;
+import com.zanxiang.game.platform.serve.service.IGamePlatformAccountService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 游戏账号
+ */
+@Slf4j
+@Service
+public class GamePlatformAccountServiceImpl extends ServiceImpl<GamePlatformAccountMapper, GamePlatformAccount> implements IGamePlatformAccountService {
+}

+ 26 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/impl/GamePlatformServiceImpl.java

@@ -0,0 +1,26 @@
+package com.zanxiang.game.platform.serve.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.platform.serve.dao.mapper.GamePlatformMapper;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatform;
+import com.zanxiang.game.platform.serve.service.IGamePlatformService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 游戏平台
+ */
+@Slf4j
+@Service
+public class GamePlatformServiceImpl extends ServiceImpl<GamePlatformMapper, GamePlatform> implements IGamePlatformService {
+
+    @Override
+    public GamePlatform getByPlatformKey(String platformKey) {
+        return getOne(new LambdaQueryWrapper<GamePlatform>()
+                .eq(GamePlatform::getPlatformKey, platformKey)
+        );
+    }
+}

+ 42 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/impl/PlatformDeYangOrderServiceImpl.java

@@ -1,14 +1,26 @@
 package com.zanxiang.game.platform.serve.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.game.platform.serve.dao.mapper.PlatformDeYangOrderMapper;
+import com.zanxiang.game.platform.serve.enums.GamePlatformEnum;
 import com.zanxiang.game.platform.serve.pojo.dto.PlatformDeYangOrderDTO;
 import com.zanxiang.game.platform.serve.pojo.entity.PlatformDeYangOrder;
 import com.zanxiang.game.platform.serve.service.IPlatformDeYangOrderService;
+import com.zanxiang.module.redis.annotation.Lock;
 import com.zanxiang.module.util.DateUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.logging.log4j.util.Strings;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * @author : lingfeng
@@ -23,6 +35,7 @@ public class PlatformDeYangOrderServiceImpl extends ServiceImpl<PlatformDeYangOr
     public Boolean addOrUpdate(PlatformDeYangOrderDTO orderDTO) {
         return super.saveOrUpdate(PlatformDeYangOrder.builder()
                 .orderId(orderDTO.getOrderid())
+                .platformKey(GamePlatformEnum.DE_YANG.getPlatformKey())
                 .uid(orderDTO.getUid())
                 .mpOpenId(orderDTO.getWecha_id())
                 .gameName(orderDTO.getGame_name())
@@ -36,6 +49,35 @@ public class PlatformDeYangOrderServiceImpl extends ServiceImpl<PlatformDeYangOr
                 .tunnelId(orderDTO.getTunnel_id())
                 .productName(orderDTO.getProduct_name())
                 .touFangBack(orderDTO.getToufang_back())
+                .agentId(orderDTO.getAgent_id2())
                 .build());
     }
+
+    @Lock(prefix = "platform:deYangOrderService:saveOrUpdate", waitTime = 3, leaseTime = 3, timeUnit = TimeUnit.MINUTES)
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean saveOrUpdate(List<PlatformDeYangOrder> orderList) {
+        if (CollectionUtils.isEmpty(orderList)) {
+            return true;
+        }
+        Map<String, PlatformDeYangOrder> oldMap = list(new LambdaQueryWrapper<PlatformDeYangOrder>()
+                .in(PlatformDeYangOrder::getOrderId, orderList.stream().map(PlatformDeYangOrder::getOrderId).collect(Collectors.toList()))
+        ).stream().collect(Collectors.toMap(PlatformDeYangOrder::getOrderId, Function.identity()));
+        List<PlatformDeYangOrder> addList = new ArrayList<>(orderList.size());
+        for (PlatformDeYangOrder order : orderList) {
+            PlatformDeYangOrder old = oldMap.remove(order.getOrderId());
+            if (old == null) {
+                addList.add(order);
+            } else {
+                order.setOrderId(old.getOrderId());
+                if (!order.equals(old)) {
+                    updateById(order);
+                }
+            }
+        }
+        if (CollectionUtils.isNotEmpty(addList)) {
+            saveBatch(addList);
+        }
+        return true;
+    }
 }

+ 49 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/impl/PlatformDeYangUserServiceImpl.java

@@ -1,14 +1,26 @@
 package com.zanxiang.game.platform.serve.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.game.platform.serve.dao.mapper.PlatformDeYangUserMapper;
+import com.zanxiang.game.platform.serve.enums.GamePlatformEnum;
 import com.zanxiang.game.platform.serve.pojo.dto.PlatformDeYangUserDTO;
 import com.zanxiang.game.platform.serve.pojo.entity.PlatformDeYangUser;
 import com.zanxiang.game.platform.serve.service.IPlatformDeYangUserService;
+import com.zanxiang.module.redis.annotation.Lock;
 import com.zanxiang.module.util.DateUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.logging.log4j.util.Strings;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * @author : lingfeng
@@ -21,8 +33,16 @@ public class PlatformDeYangUserServiceImpl extends ServiceImpl<PlatformDeYangUse
 
     @Override
     public Boolean addOrUpdate(PlatformDeYangUserDTO userDTO) {
+        //判断用户信息是否已经存在
+        PlatformDeYangUser platformDeYangUser = super.getById(userDTO.getUid());
+        //已存在的用户, ua如果有的话不更新, 游戏方每次传过来的是当前登录的ua
+        if (platformDeYangUser != null && Strings.isNotBlank(platformDeYangUser.getUserAgent())) {
+            userDTO.setUser_agent(null);
+        }
+        //更新或者保存数据
         return super.saveOrUpdate(PlatformDeYangUser.builder()
                 .uid(userDTO.getUid())
+                .platformKey(GamePlatformEnum.DE_YANG.getPlatformKey())
                 .mpOpenId(userDTO.getWecha_id())
                 .qcSign(userDTO.getN_wecha_id())
                 .time(Strings.isBlank(userDTO.getTime()) ? null : DateUtil.parseLocalDateTime(userDTO.getTime()))
@@ -40,6 +60,35 @@ public class PlatformDeYangUserServiceImpl extends ServiceImpl<PlatformDeYangUse
                 .appId(userDTO.getAppid())
                 .appName(userDTO.getAppname())
                 .userAgent(userDTO.getUser_agent())
+                .agentId(userDTO.getAgent_id2())
                 .build());
     }
+
+    @Lock(prefix = "platform:deYangUserService:saveOrUpdate", waitTime = 3, leaseTime = 3, timeUnit = TimeUnit.MINUTES)
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean saveOrUpdate(List<PlatformDeYangUser> userList) {
+        if (CollectionUtils.isEmpty(userList)) {
+            return true;
+        }
+        Map<Long, PlatformDeYangUser> oldMap = list(new LambdaQueryWrapper<PlatformDeYangUser>()
+                .in(PlatformDeYangUser::getUid, userList.stream().map(PlatformDeYangUser::getUid).collect(Collectors.toList()))
+        ).stream().collect(Collectors.toMap(PlatformDeYangUser::getUid, Function.identity()));
+        List<PlatformDeYangUser> addList = new ArrayList<>(userList.size());
+        for (PlatformDeYangUser user : userList) {
+            PlatformDeYangUser old = oldMap.remove(user.getUid());
+            if (old == null) {
+                addList.add(user);
+            } else {
+                user.setUid(old.getUid());
+                if (!user.equals(old)) {
+                    updateById(user);
+                }
+            }
+        }
+        if (CollectionUtils.isNotEmpty(addList)) {
+            saveBatch(addList);
+        }
+        return true;
+    }
 }

+ 97 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/platform/PlatformBaseService.java

@@ -0,0 +1,97 @@
+package com.zanxiang.game.platform.serve.service.platform;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zanxiang.game.platform.serve.enums.GamePlatformEnum;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatform;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatformAccount;
+import com.zanxiang.game.platform.serve.service.IGamePlatformAccountService;
+import com.zanxiang.game.platform.serve.service.IGamePlatformService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 超类
+ */
+@Slf4j
+public abstract class PlatformBaseService {
+
+    @Lazy
+    @Autowired
+    private IGamePlatformService getByPlatformKey;
+
+    @Lazy
+    @Autowired
+    private IGamePlatformAccountService gamePlatformAccountService;
+
+    /**
+     * 同步指定时间段的订单
+     *
+     * @param startDate 开始日期
+     * @param endDate   结束日期
+     * @return boolean
+     */
+    public boolean syncPlatformOrder(LocalDateTime startDate, LocalDateTime endDate) {
+        GamePlatform gamePlatform = getByPlatformKey.getByPlatformKey(getGamePlatformEnum().getPlatformKey());
+        List<GamePlatformAccount> gamePlatformAccountList = gamePlatformAccountService.list(new LambdaQueryWrapper<GamePlatformAccount>()
+                .eq(GamePlatformAccount::getPlatformKey, gamePlatform.getPlatformKey())
+                .eq(GamePlatformAccount::getStatus, GamePlatformAccount.USE_STATUS));
+        for (GamePlatformAccount account : gamePlatformAccountList) {
+            try {
+                syncOrderByAccount(gamePlatform, account, startDate, endDate);
+            } catch (Exception e) {
+                log.error("同步游戏平台订单失败!accountId: {}, error : {}", account.getId(), e.getMessage());
+            }
+        }
+        return true;
+    }
+
+    public boolean syncPlatformUser(LocalDateTime startDate, LocalDateTime endDate) {
+        GamePlatform gamePlatform = getByPlatformKey.getByPlatformKey(getGamePlatformEnum().getPlatformKey());
+        List<GamePlatformAccount> gamePlatformAccountList = gamePlatformAccountService.list(new LambdaQueryWrapper<GamePlatformAccount>()
+                .eq(GamePlatformAccount::getPlatformKey, gamePlatform.getPlatformKey())
+                .eq(GamePlatformAccount::getStatus, GamePlatformAccount.USE_STATUS));
+        for (GamePlatformAccount account : gamePlatformAccountList) {
+            try {
+                syncUserByAccount(gamePlatform, account, startDate, endDate);
+            } catch (Exception e) {
+                log.error("同步游戏平台用户失败!accountId: {}, error : {}", account.getId(), e.getMessage());
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 获取游戏平台枚举信息
+     *
+     * @return {@link GamePlatformEnum}
+     */
+    public abstract GamePlatformEnum getGamePlatformEnum();
+
+    /**
+     * 游戏平台订单同步
+     *
+     * @param account      账户
+     * @param startDate    开始日期
+     * @param endDate      结束日期
+     * @param gamePlatform 游戏平台
+     * @return boolean
+     */
+    public abstract boolean syncUserByAccount(GamePlatform gamePlatform, GamePlatformAccount account, LocalDateTime startDate, LocalDateTime endDate);
+
+    /**
+     * 游戏平台同步用户
+     *
+     * @param account      账户
+     * @param startDate    开始日期
+     * @param endDate      结束日期
+     * @param gamePlatform 游戏平台
+     * @return boolean
+     */
+    public abstract boolean syncOrderByAccount(GamePlatform gamePlatform, GamePlatformAccount account, LocalDateTime startDate, LocalDateTime endDate);
+}

+ 222 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/service/platform/PlatformDeYangService.java

@@ -0,0 +1,222 @@
+package com.zanxiang.game.platform.serve.service.platform;
+
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.zanxiang.game.platform.serve.enums.GamePlatformEnum;
+import com.zanxiang.game.platform.serve.pojo.dto.PlatformDeYangOrderDTO;
+import com.zanxiang.game.platform.serve.pojo.dto.PlatformDeYangUserDTO;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatform;
+import com.zanxiang.game.platform.serve.pojo.entity.GamePlatformAccount;
+import com.zanxiang.game.platform.serve.pojo.entity.PlatformDeYangOrder;
+import com.zanxiang.game.platform.serve.pojo.entity.PlatformDeYangUser;
+import com.zanxiang.game.platform.serve.pojo.res.PlatformDeYangOrderRes;
+import com.zanxiang.game.platform.serve.pojo.res.PlatformDeYangUserRes;
+import com.zanxiang.game.platform.serve.service.IPlatformDeYangOrderService;
+import com.zanxiang.game.platform.serve.service.IPlatformDeYangUserService;
+import com.zanxiang.module.util.DateUtil;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.URIUtil;
+import com.zanxiang.module.util.encryption.Md5Util;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-05-24
+ * @description : 德扬数据同步
+ */
+@Slf4j
+@Service
+public class PlatformDeYangService extends PlatformBaseService {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Autowired
+    private IPlatformDeYangOrderService platformDeYangOrderService;
+
+    @Autowired
+    private IPlatformDeYangUserService platformDeYangUserService;
+
+    @Override
+    public GamePlatformEnum getGamePlatformEnum() {
+        return GamePlatformEnum.DE_YANG;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean syncOrderByAccount(GamePlatform gamePlatform, GamePlatformAccount account, LocalDateTime startDate, LocalDateTime endDate) {
+        Map<String, String> platformParam = JsonUtil.toMap(gamePlatform.getConfigParam(), Map.class, String.class);
+        Map<String, String> accountParam = JsonUtil.toMap(account.getConfigParam(), Map.class, String.class);
+        startDate = startDate == null ? LocalDateTime.of(gamePlatform.getBeginTime(), LocalTime.MIDNIGHT) : startDate;
+        endDate = endDate == null ? LocalDateTime.now() : endDate;
+
+        String appSecret = accountParam.get("secret");
+        String host = platformParam.get("host");
+        String agentId = accountParam.get("agent_id2");
+        Map<String, String> params = new HashMap<>(6);
+        params.put("name", account.getAccount());
+        params.put("agent_id2", agentId);
+
+        LocalDate searchDate = startDate.toLocalDate();
+        do {
+            int page = 1, totalPage = 0;
+            params.put("seach_date", searchDate.toString());
+            do {
+                params.put("p", String.valueOf(page));
+                params.put("time", String.valueOf(System.currentTimeMillis() / 1000));
+                params.remove("sign");
+                params.put("sign", sign(appSecret, params));
+                String url = host + "/qc_order_list/";
+                url = URIUtil.fillUrlParams(url, params, true);
+                PlatformDeYangOrderRes res;
+                try {
+                    res = restTemplate.getForObject(url, PlatformDeYangOrderRes.class);
+                } catch (Exception e) {
+                    log.error("同步德扬订单信息异常, accountId: {}, message: {}", account.getId(), e.getMessage());
+                    break;
+                }
+                if (res == null || CollectionUtils.isEmpty(res.getList())) {
+                    log.error("同步德扬订单信息,返回结果为空, accountId: {}, res : {}", account.getId(), JsonUtil.toString(res));
+                    break;
+                }
+                //总页数赋值
+                if (res.getTotalPage() != null) {
+                    totalPage = res.getTotalPage();
+                }
+                //数据处理
+                platformDeYangOrderService.saveOrUpdate(this.transformOrder(gamePlatform.getPlatformKey(), agentId, res.getList()));
+            } while (page++ <= totalPage);
+            //日期递增
+            searchDate = searchDate.plusDays(1);
+        } while (!searchDate.isAfter(endDate.toLocalDate()));
+
+
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean syncUserByAccount(GamePlatform gamePlatform, GamePlatformAccount account, LocalDateTime startDate, LocalDateTime endDate) {
+        startDate = startDate == null ? LocalDateTime.of(gamePlatform.getBeginTime(), LocalTime.MIDNIGHT) : startDate;
+        endDate = endDate == null ? LocalDateTime.now() : endDate;
+        Map<String, String> accountParam = JsonUtil.toMap(account.getConfigParam(), Map.class, String.class);
+        Map<String, String> platformParam = JsonUtil.toMap(gamePlatform.getConfigParam(), Map.class, String.class);
+
+        String host = platformParam.get("host");
+        String appSecret = accountParam.get("secret");
+        String agentId = accountParam.get("agent_id2");
+        Map<String, String> params = new HashMap<>(7);
+        params.put("name", account.getAccount());
+        params.put("agent_id2", agentId);
+
+        LocalDate searchDate = startDate.toLocalDate();
+        do {
+            int page = 1, totalPage = 0;
+            params.put("seach_date", searchDate.toString());
+            do {
+                params.put("p", String.valueOf(page));
+                params.put("time", String.valueOf(System.currentTimeMillis() / 1000));
+                params.remove("sign");
+                params.put("sign", sign(appSecret, params));
+                String url = host + "/qc_user_list/";
+                url = URIUtil.fillUrlParams(url, params, true);
+                PlatformDeYangUserRes res;
+                try {
+                    res = restTemplate.getForObject(url, PlatformDeYangUserRes.class);
+                } catch (Exception e) {
+                    log.error("同步德扬订单信息异常, accountId: {}, message: {}", account.getId(), e.getMessage());
+                    break;
+                }
+                if (res == null) {
+                    log.error("同步德扬用户信息,返回结果为空, accountId: {}, res : {}", account.getId(), JsonUtil.toString(res));
+                    break;
+                }
+                //总页数赋值
+                if (res.getTotalPage() != null) {
+                    totalPage = res.getTotalPage();
+                }
+                //数据处理
+                platformDeYangUserService.saveOrUpdate(this.transformUser(gamePlatform.getPlatformKey(), agentId, res.getList()));
+            } while (page++ <= totalPage);
+            //日期递增
+            searchDate = searchDate.plusDays(1);
+        } while (!searchDate.isAfter(endDate.toLocalDate()));
+        return true;
+    }
+
+    private String sign(String secret, Map<String, String> params) {
+        List<String> paramKeyList = new ArrayList<>(params.keySet());
+        Collections.sort(paramKeyList);
+        StringBuilder temp = new StringBuilder();
+        for (String paramKey : paramKeyList) {
+            if (Objects.equals(paramKey, "seach_date")) {
+                continue;
+            }
+            temp.append(paramKey).append("=").append(params.get(paramKey)).append("&");
+        }
+        String res = temp.substring(0, temp.length() - 1) + secret;
+        return Md5Util.encrypt32(res);
+    }
+
+    private List<PlatformDeYangOrder> transformOrder(String platformKey, String agentId, List<PlatformDeYangOrderDTO> orderList) {
+        if (CollectionUtils.isEmpty(orderList)) {
+            return Collections.emptyList();
+        }
+        return orderList.stream().map(order -> PlatformDeYangOrder.builder()
+                .orderId(order.getOrderid())
+                .platformKey(platformKey)
+                .uid(order.getUid())
+                .mpOpenId(order.getWecha_id())
+                .gameName(order.getGame_name())
+                .payStatus(order.getPay_status())
+                .price(order.getPrice())
+                .addTime(order.getAddtime() == null ? null : DateUtil.secondToLocalDateTime(order.getAddtime()))
+                .payType(order.getPay_type())
+                .payTime(Strings.isBlank(order.getPay_time()) ? null : DateUtil.parseLocalDateTime(order.getPay_time()))
+                .roleName(order.getRole_name())
+                .roleArea(order.getRole_area())
+                .tunnelId(order.getTunnel_id())
+                .productName(order.getProduct_name())
+                .touFangBack(order.getToufang_back())
+                .agentId(agentId)
+                .build()).collect(Collectors.toList());
+    }
+
+    private List<PlatformDeYangUser> transformUser(String platformKey, String agentId, List<PlatformDeYangUserDTO> userList) {
+        if (CollectionUtils.isEmpty(userList)) {
+            return Collections.emptyList();
+        }
+        return userList.stream().map(user -> PlatformDeYangUser.builder()
+                .uid(user.getUid())
+                .platformKey(platformKey)
+                .mpOpenId(user.getWecha_id())
+                .qcSign(user.getN_wecha_id())
+                .time(Strings.isBlank(user.getTime()) ? null : DateUtil.parseLocalDateTime(user.getTime()))
+                .tunnelId(user.getTunnel_id())
+                .updateTime(Strings.isBlank(user.getUpdate_time()) ? null : DateUtil.parseLocalDateTime(user.getUpdate_time()))
+                .allPrice(user.getAll_price())
+                .gamePrice(user.getGame_price())
+                .mobile(user.getMobile())
+                .trueName(user.getTrue_name())
+                .code(user.getCode())
+                .gameName(user.getGame_name())
+                .roleName(user.getRole_name())
+                .roleArea(user.getRole_area())
+                .ip(user.getIp())
+                .appId(user.getAppid())
+                .appName(user.getAppname())
+                .userAgent(user.getUser_agent())
+                .agentId(agentId)
+                .build()).collect(Collectors.toList());
+    }
+}

+ 99 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/task/SyncPlatformOrderTask.java

@@ -0,0 +1,99 @@
+package com.zanxiang.game.platform.serve.task;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.zanxiang.game.platform.serve.enums.GamePlatformEnum;
+import com.zanxiang.game.platform.serve.exception.UnsupportedException;
+import com.zanxiang.game.platform.serve.service.platform.PlatformBaseService;
+import com.zanxiang.game.platform.serve.utils.SpringUtils;
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author : lingfeng
+ * @time : 2021-08-03
+ * @description : 同步书城订单信息
+ */
+@Slf4j
+@Component
+@RefreshScope
+public class SyncPlatformOrderTask {
+
+    private static final String LOCK_SYNC_ORDER_ROLLBACK = "platform:lockSyncOrderRollback";
+
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+
+    @Value("${sys-config.task_is_run}")
+    private boolean run;
+
+    /**
+     * 线程池
+     */
+    private static final ExecutorService THREAD_POOL_EARLY_MORNING = new ThreadPoolExecutor(
+            3,
+            3,
+            0,
+            TimeUnit.MINUTES,
+            new LinkedBlockingQueue<>(),
+            new ThreadFactoryBuilder()
+                    .setNameFormat("async-order-early-morning-%d").build());
+
+    /**
+     * 每天凌晨 2点回滚前 10天的数据
+     */
+    @Scheduled(cron = "0 0 2 * * ?")
+    public void rollback() {
+        if (!run) {
+            return;
+        }
+        long begin = System.currentTimeMillis();
+        LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
+        LocalDateTime startTime = endTime.minusDays(10);
+        for (GamePlatformEnum gamePlatformEnum : GamePlatformEnum.values()) {
+            if (gamePlatformEnum.getClazz() == null) {
+                continue;
+            }
+            THREAD_POOL_EARLY_MORNING.execute(() -> {
+                if (!distributedLockComponent.doLock(LOCK_SYNC_ORDER_ROLLBACK + "_" + gamePlatformEnum.getPlatformKey(), 0L, 12L, TimeUnit.HOURS)) {
+                    return;
+                }
+                long start = System.currentTimeMillis();
+                execute(gamePlatformEnum, startTime, endTime);
+                long end = System.currentTimeMillis();
+                if (end - begin > 60 * 60 * 1000) {
+                    log.error("游戏平台【{}】同步订单(两点回滚)完成, 用时:{}, 调度用时:{}", gamePlatformEnum.getPlatformName(), (end - start) / 1000, (end - begin) / 1000);
+                }
+            });
+        }
+    }
+
+    /**
+     * 订单同步执行
+     *
+     * @param gamePlatformEnum 游戏平台枚举
+     * @param startTime        开始时间
+     * @param endTime          结束时间
+     */
+    private void execute(GamePlatformEnum gamePlatformEnum, LocalDateTime startTime, LocalDateTime endTime) {
+        try {
+            PlatformBaseService service = SpringUtils.getBean(gamePlatformEnum.getClazz());
+            service.syncPlatformOrder(startTime, endTime);
+        } catch (UnsupportedException ignored) {
+        } catch (Exception e) {
+            log.error("同步游戏平台【{}】的订单异常, 异常原因: {}", gamePlatformEnum.getPlatformName(), e.getMessage(), e);
+        }
+    }
+}

+ 99 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/task/SyncPlatformUserTask.java

@@ -0,0 +1,99 @@
+package com.zanxiang.game.platform.serve.task;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.zanxiang.game.platform.serve.enums.GamePlatformEnum;
+import com.zanxiang.game.platform.serve.exception.UnsupportedException;
+import com.zanxiang.game.platform.serve.service.platform.PlatformBaseService;
+import com.zanxiang.game.platform.serve.utils.SpringUtils;
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-08-22
+ * @description : 用户粉丝同步
+ */
+@Slf4j
+@Component
+@RefreshScope
+public class SyncPlatformUserTask {
+
+    private static final String LOCK_SYNC_USER_ROLLBACK = "platform:lockSyncUserRollback";
+
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+
+    @Value("${sys-config.task_is_run}")
+    private boolean run;
+
+    /**
+     * 线程池
+     */
+    private static final ExecutorService THREAD_POOL_EARLY_MORNING = new ThreadPoolExecutor(
+            3,
+            3,
+            0,
+            TimeUnit.MINUTES,
+            new LinkedBlockingQueue<>(),
+            new ThreadFactoryBuilder()
+                    .setNameFormat("async-user-early-morning-%d").build());
+
+    /**
+     * 每天凌晨 1点回滚前 10天的数据
+     */
+    @Scheduled(cron = "0 0 1 * * ? ")
+    public void rollback() {
+        if (!run) {
+            return;
+        }
+        long begin = System.currentTimeMillis();
+        LocalDateTime endTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
+        LocalDateTime startTime = endTime.minusDays(10);
+        for (GamePlatformEnum gamePlatformEnum : GamePlatformEnum.values()) {
+            if (gamePlatformEnum.getClazz() == null) {
+                continue;
+            }
+            THREAD_POOL_EARLY_MORNING.execute(() -> {
+                if (!distributedLockComponent.doLock(LOCK_SYNC_USER_ROLLBACK + "_" + gamePlatformEnum.getPlatformKey(), 0L, 12L, TimeUnit.HOURS)) {
+                    return;
+                }
+                long start = System.currentTimeMillis();
+                execute(gamePlatformEnum, startTime, endTime);
+                long end = System.currentTimeMillis();
+                if (end - begin > 60 * 60 * 1000) {
+                    log.error("游戏平台 {}同步用户(一点回滚)完成, 用时:{}, 调度用时:{}", gamePlatformEnum.getPlatformName(), (end - start) / 1000, (end - begin) / 1000);
+                }
+            });
+        }
+    }
+
+    /**
+     * 用户同步执行
+     *
+     * @param startTime        : 当前时间
+     * @param endTime          : 当前时间
+     * @param gamePlatformEnum : 游戏平台枚举
+     */
+    private void execute(GamePlatformEnum gamePlatformEnum, LocalDateTime startTime, LocalDateTime endTime) {
+        try {
+            PlatformBaseService service = SpringUtils.getBean(gamePlatformEnum.getClazz());
+            service.syncPlatformUser(startTime, endTime);
+        } catch (UnsupportedException ignored) {
+        } catch (Exception e) {
+            log.error("同步游戏平台【{}】的用户异常, 异常原因: {}", gamePlatformEnum.getPlatformName(), e.getMessage(), e);
+        }
+    }
+}

+ 102 - 0
game-platform/game-platform-serve/src/main/java/com/zanxiang/game/platform/serve/utils/SpringUtils.java

@@ -0,0 +1,102 @@
+package com.zanxiang.game.platform.serve.utils;
+
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring工具类 方便在非spring管理环境中获取bean
+ *
+ * @author ruoyi
+ */
+@Component
+public final class SpringUtils implements BeanFactoryPostProcessor {
+    /**
+     * Spring应用上下文环境
+     */
+    private static ConfigurableListableBeanFactory beanFactory;
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+        SpringUtils.beanFactory = beanFactory;
+    }
+
+    /**
+     * 获取对象
+     *
+     * @param name
+     * @return Object 一个以所给名字注册的bean的实例
+     * @throws BeansException
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name) throws BeansException {
+        return (T) beanFactory.getBean(name);
+    }
+
+    /**
+     * 获取类型为requiredType的对象
+     *
+     * @param clz
+     * @return
+     * @throws BeansException
+     */
+    public static <T> T getBean(Class<T> clz) throws BeansException {
+        T result = (T) beanFactory.getBean(clz);
+        return result;
+    }
+
+    /**
+     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
+     *
+     * @param name
+     * @return boolean
+     */
+    public static boolean containsBean(String name) {
+        return beanFactory.containsBean(name);
+    }
+
+    /**
+     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
+     *
+     * @param name
+     * @return boolean
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.isSingleton(name);
+    }
+
+    /**
+     * @param name
+     * @return Class 注册对象的类型
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.getType(name);
+    }
+
+    /**
+     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
+     *
+     * @param name
+     * @return
+     * @throws NoSuchBeanDefinitionException
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 获取aop代理对象
+     *
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker) {
+        return (T) AopContext.currentProxy();
+    }
+}