Ver código fonte

文化中心

dengsixing 1 mês atrás
pai
commit
1294ba317b
24 arquivos alterados com 802 adições e 192 exclusões
  1. 12 0
      pom.xml
  2. 95 0
      src/main/java/com/fdkankan/external/Interceptor/SignVerificationAspect.java
  3. 21 0
      src/main/java/com/fdkankan/external/ScenePushBean.java
  4. 10 0
      src/main/java/com/fdkankan/external/annotation/SignVerification.java
  5. 39 0
      src/main/java/com/fdkankan/external/controller/XinxizhongxinController.java
  6. 2 0
      src/main/java/com/fdkankan/external/entity/Scene.java
  7. 46 0
      src/main/java/com/fdkankan/external/entity/ZgxxzxPushLog.java
  8. 2 2
      src/main/java/com/fdkankan/external/generate/Codegen.java
  9. 18 0
      src/main/java/com/fdkankan/external/httpclient/MyClient.java
  10. 82 0
      src/main/java/com/fdkankan/external/listener/DemoDataListener.java
  11. 14 0
      src/main/java/com/fdkankan/external/mapper/ZgxxzxPushLogMapper.java
  12. 14 0
      src/main/java/com/fdkankan/external/request/TaskPageRequest.java
  13. 32 0
      src/main/java/com/fdkankan/external/response/PageInfo.java
  14. 97 0
      src/main/java/com/fdkankan/external/response/Result.java
  15. 17 0
      src/main/java/com/fdkankan/external/schedule/ScheduleJob.java
  16. 2 1
      src/main/java/com/fdkankan/external/service/ISceneOfflinePackagePushService.java
  17. 14 0
      src/main/java/com/fdkankan/external/service/IZgxxzxPushLogService.java
  18. 19 0
      src/main/java/com/fdkankan/external/service/XinxizhongxinService.java
  19. 69 76
      src/main/java/com/fdkankan/external/service/impl/SceneOfflinePackagePushServiceImpl.java
  20. 146 0
      src/main/java/com/fdkankan/external/service/impl/XinxizhongxinServiceImpl.java
  21. 18 0
      src/main/java/com/fdkankan/external/service/impl/ZgxxzxPushLogServiceImpl.java
  22. 19 113
      src/main/resources/bootstrap-dev.yml
  23. 7 0
      src/main/resources/bootstrap-prod.yml
  24. 7 0
      src/main/resources/bootstrap-test.yml

+ 12 - 0
pom.xml

@@ -92,6 +92,12 @@
         </dependency>
 
         <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+            <version>4.0.3</version>
+        </dependency>
+
+        <dependency>
             <groupId>cn.hutool</groupId>
             <artifactId>hutool-all</artifactId>
             <version>${hutool-version}</version>
@@ -199,6 +205,12 @@
             <version>3.22.12</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.fdkankan</groupId>
+            <artifactId>4dkankan-utils-sign</artifactId>
+            <version>3.0.0-SNAPSHOT</version>
+        </dependency>
+
     </dependencies>
 
     <dependencyManagement>

+ 95 - 0
src/main/java/com/fdkankan/external/Interceptor/SignVerificationAspect.java

@@ -0,0 +1,95 @@
+package com.fdkankan.external.Interceptor;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.constant.ServerCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.external.httpclient.MyClient;
+import com.fdkankan.external.response.Result;
+import com.fdkankan.sign.RsaUtils;
+import com.fdkankan.sign.SignUtils;
+import lombok.extern.log4j.Log4j2;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+@Log4j2
+@Aspect
+@Component
+@Order(101)
+public class SignVerificationAspect {
+
+	private static final String GET_PRIVATEKEY_API = "/ucenter/_inner/pdsfsdfsrvateddsfeky/";
+
+	@Value("${ucenter.publicKey}")
+	private String publicKey;
+	@Value("${ucenter.appId}")
+	private String ucenterAppId;
+
+	@Value("${4dkk.fdService.basePath}")
+	private String fdServiceBasePath;
+
+	@Resource
+	private MyClient myClient;
+
+	/**
+	 * 前置通知 用于判断用户协作场景是否有协作权限
+	 *
+	 * @param joinPoint
+	 *            切点
+	 * @throws IOException
+	 */
+	@Before("@annotation(com.fdkankan.external.annotation.SignVerification)")
+	public void doBefore(JoinPoint joinPoint) throws Exception {
+		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+
+		String XUA = request.getHeader("X-UA");
+		if(StrUtil.isNotEmpty(XUA)){
+			return;
+		}
+
+		String sign = request.getHeader("sign");
+		String appId = request.getHeader("appId");
+		if(StrUtil.isEmpty(sign) || StrUtil.isEmpty(appId)){
+			throw new BusinessException(ErrorCode.AUTH_FAIL);
+		}
+
+		//通过appid查询私钥
+		JSONObject playload = new JSONObject();
+		playload.put("appId", ucenterAppId);
+		playload.put("timestamp", System.currentTimeMillis());
+		String ucenterSign = RsaUtils.encipher(playload.toJSONString(), publicKey);
+		Map<String, String> headerMap = new HashMap<>();
+		headerMap.put("sign", ucenterSign);
+		headerMap.put("appId", ucenterAppId);
+		String url = fdServiceBasePath + GET_PRIVATEKEY_API + appId;
+		Result result = myClient.get(url, headerMap);
+		if(result.getCode() != ServerCode.SUCCESS.code()){
+			throw new RuntimeException("系统异常");
+		}
+		JSONObject data = (JSONObject) result.getData();
+		if(Objects.isNull(data)){
+			throw new BusinessException(ErrorCode.AUTH_FAIL);
+		}
+		String privateKey = data.getString("privateKey");
+
+		//签名解密
+		if(!SignUtils.checkSign(sign, appId, privateKey)){
+			throw new BusinessException(ErrorCode.AUTH_FAIL);
+		}
+	}
+
+}

+ 21 - 0
src/main/java/com/fdkankan/external/ScenePushBean.java

@@ -0,0 +1,21 @@
+package com.fdkankan.external;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ScenePushBean {
+
+    private String num;
+    private String zipType;
+    private Long version;
+    private String destUrl;
+    private String taskId;
+
+
+}

+ 10 - 0
src/main/java/com/fdkankan/external/annotation/SignVerification.java

@@ -0,0 +1,10 @@
+package com.fdkankan.external.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SignVerification {
+    String description() default "";
+}

+ 39 - 0
src/main/java/com/fdkankan/external/controller/XinxizhongxinController.java

@@ -0,0 +1,39 @@
+package com.fdkankan.external.controller;
+
+import com.fdkankan.external.entity.ZgxxzxPushLog;
+import com.fdkankan.external.request.TaskPageRequest;
+import com.fdkankan.external.response.PageInfo;
+import com.fdkankan.external.service.IZgxxzxPushLogService;
+import com.fdkankan.external.service.XinxizhongxinService;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+@RestController
+@RequestMapping("/xxzx")
+public class XinxizhongxinController {
+
+    @Autowired
+    private XinxizhongxinService xinxizhongxinService;
+    @Autowired
+    private IZgxxzxPushLogService zgxxzxPushLogService;
+
+    @SignVerification
+    @PostMapping("import")
+    private ResultData importExcel(@RequestParam("file")MultipartFile file) throws IOException {
+        xinxizhongxinService.importExcel(file);
+        return ResultData.ok();
+    }
+
+    @SignVerification
+    @PostMapping("taskList")
+    private ResultData<PageInfo<ZgxxzxPushLog>> taskList(@RequestBody TaskPageRequest request) throws IOException {
+        return ResultData.ok(xinxizhongxinService.taskList(request));
+    }
+
+
+
+}

+ 2 - 0
src/main/java/com/fdkankan/external/entity/Scene.java

@@ -1,5 +1,6 @@
 package com.fdkankan.external.entity;
 
+import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.mybatisflex.annotation.Id;
 import com.mybatisflex.annotation.KeyType;
 import com.mybatisflex.annotation.Table;
@@ -57,6 +58,7 @@ public class Scene implements Serializable {
     /**
      * 逻辑未删除值0,逻辑已删除值1
      */
+    @TableLogic(value = "0", delval = "1")
     private String deleted;
 
     /**

+ 46 - 0
src/main/java/com/fdkankan/external/entity/ZgxxzxPushLog.java

@@ -0,0 +1,46 @@
+package com.fdkankan.external.entity;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.mybatisflex.annotation.Id;
+import com.mybatisflex.annotation.KeyType;
+import com.mybatisflex.annotation.Table;
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.sql.Date;
+import java.sql.Timestamp;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ *  实体类。
+ *
+ * @author dsx
+ * @since 2025-11-07
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(value = "t_zgxxzx_push_log")
+public class ZgxxzxPushLog implements Serializable {
+
+    @Id(keyType = KeyType.Auto)
+    private BigInteger id;
+
+    @ExcelProperty("字符串标题")
+    private String num;
+
+    private String title;
+
+    /**
+     * -1-失败,0-等待中,1-成功,2-推送中
+     */
+    private Integer status;
+
+    private Date createTime;
+
+    private Date updateTime;
+
+}

+ 2 - 2
src/main/java/com/fdkankan/external/generate/Codegen.java

@@ -13,11 +13,11 @@ public class Codegen {
     public static void main(String[] args) {
         //配置数据源
         HikariDataSource dataSource = new HikariDataSource();
-        dataSource.setJdbcUrl("jdbc:mysql://120.24.144.164:3306/4dkankan_v4");
+        dataSource.setJdbcUrl("jdbc:mysql://120.24.144.164:3306/4dkankan_center_external");
         dataSource.setUsername("root");
         dataSource.setPassword("4Dage@4Dage#@168");
 
-        String[] tables = new String[]{"t_scene_not_display"};//,"t_scene_offline_package_push","t_department_camera"
+        String[] tables = new String[]{"t_zgxxzx_push_log"};//,"t_scene_offline_package_push","t_department_camera"
 
                 //创建配置内容,两种风格都可以。
         GlobalConfig globalConfig = createGlobalConfigUseStyle1(tables);

+ 18 - 0
src/main/java/com/fdkankan/external/httpclient/MyClient.java

@@ -0,0 +1,18 @@
+package com.fdkankan.external.httpclient;
+
+
+import com.dtflys.forest.annotation.Get;
+import com.dtflys.forest.annotation.Header;
+import com.dtflys.forest.annotation.Var;
+import com.fdkankan.external.response.Result;
+
+import java.util.Map;
+
+public interface MyClient {
+
+    @Get(url = "${url}")
+    Result get(@Var("url") String url, @Header Map<String, String> headerMap);
+
+
+
+}

+ 82 - 0
src/main/java/com/fdkankan/external/listener/DemoDataListener.java

@@ -0,0 +1,82 @@
+package com.fdkankan.external.listener;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.read.listener.ReadListener;
+import com.alibaba.excel.util.ListUtils;
+import com.alibaba.fastjson.JSON;
+import com.fdkankan.external.entity.ZgxxzxPushLog;
+import com.fdkankan.external.service.IScenePlusService;
+import com.fdkankan.external.service.IZgxxzxPushLogService;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+@Slf4j
+public class DemoDataListener implements ReadListener<ZgxxzxPushLog> {
+
+    /**
+     * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
+     */
+    private static final int BATCH_COUNT = 100;
+    /**
+     * 缓存的数据
+     */
+    private List<ZgxxzxPushLog> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
+    /**
+     * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
+     */
+    private IZgxxzxPushLogService zgxxzxPushLogService;
+
+    private IScenePlusService scenePlusService;
+
+
+    /**
+     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
+     *
+     * @param demoDAO
+     */
+    public DemoDataListener(IZgxxzxPushLogService zgxxzxPushLogService, IScenePlusService scenePlusService) {
+        this.zgxxzxPushLogService = zgxxzxPushLogService;
+        this.scenePlusService = scenePlusService;
+    }
+
+    /**
+     * 这个每一条数据解析都会来调用
+     *
+     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
+     * @param context
+     */
+    @Override
+    public void invoke(ZgxxzxPushLog data, AnalysisContext context) {
+        log.info("解析到一条数据:{}", JSON.toJSONString(data));
+        scenePlusService.getByNum(data.getNum());
+        cachedDataList.add(data);
+        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
+        if (cachedDataList.size() >= BATCH_COUNT) {
+            saveData();
+            // 存储完成清理 list
+            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
+        }
+    }
+
+    /**
+     * 所有数据解析完成了 都会来调用
+     *
+     * @param context
+     */
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext context) {
+        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
+        saveData();
+        log.info("所有数据解析完成!");
+    }
+
+    /**
+     * 加上存储数据库
+     */
+    private void saveData() {
+        log.info("{}条数据,开始存储数据库!", cachedDataList.size());
+        zgxxzxPushLogService.saveBatch(cachedDataList);
+        log.info("存储数据库成功!");
+    }
+}

+ 14 - 0
src/main/java/com/fdkankan/external/mapper/ZgxxzxPushLogMapper.java

@@ -0,0 +1,14 @@
+package com.fdkankan.external.mapper;
+
+import com.mybatisflex.core.BaseMapper;
+import com.fdkankan.external.entity.ZgxxzxPushLog;
+
+/**
+ *  映射层。
+ *
+ * @author dsx
+ * @since 2025-11-07
+ */
+public interface ZgxxzxPushLogMapper extends BaseMapper<ZgxxzxPushLog> {
+
+}

+ 14 - 0
src/main/java/com/fdkankan/external/request/TaskPageRequest.java

@@ -0,0 +1,14 @@
+package com.fdkankan.external.request;
+
+import com.fdkankan.web.request.RequestBase;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class TaskPageRequest extends RequestBase {
+    private String num;
+    private String title;
+    @NotNull(message = "status不能为空")
+    private Integer status;
+}

+ 32 - 0
src/main/java/com/fdkankan/external/response/PageInfo.java

@@ -0,0 +1,32 @@
+package com.fdkankan.external.response;
+
+import com.mybatisflex.core.paginate.Page;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class PageInfo<T> {
+
+    private long pageNum;
+
+    private long pageSize;
+
+    private long total;
+
+    private T list;
+
+    public static PageInfo PageInfo(Page page){
+        return PageInfo.builder()
+                .pageNum(page.getPageNumber())
+                .pageSize(page.getPageSize())
+                .total(page.getTotalRow())
+                .list(page.getRecords())
+                .build();
+    }
+
+}

+ 97 - 0
src/main/java/com/fdkankan/external/response/Result.java

@@ -0,0 +1,97 @@
+package com.fdkankan.external.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 通用返回类,此类是V3版本的,v3版本停了后要删除
+ *
+ * @author
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Result<T> implements Serializable {
+    private static final long serialVersionUID = -1491499610244557029L;
+    public static final String SUCCESS_MSG = "操作成功";
+    public static int CODE_SUCCESS = 0;
+    public static int CODE_FAILURE = -1;
+    public static String[] NOOP = new String[]{};
+
+    /**
+     * 处理状态:0: 成功, 1: 失败
+     */
+    private int code;
+    /**
+     * 消息
+     */
+    private String msg;
+    /**
+     * 返回数据
+     */
+    private T data;
+    /**
+     * 处理成功,并返回数据
+     *
+     * @param data 数据对象
+     * @return data
+     */
+    public static Result success(Object data) {
+        return new Result(CODE_SUCCESS, SUCCESS_MSG, data);
+    }
+    /**
+     * 处理成功
+     *
+     * @return data
+     */
+    public static Result success() {
+        return new Result(CODE_SUCCESS, SUCCESS_MSG, NOOP);
+    }
+    /**
+     * 处理成功
+     *
+     * @param msg 消息
+     * @return data
+     */
+    public static Result success(String msg) {
+        return new Result(CODE_SUCCESS, msg, NOOP);
+    }
+    /**
+     * 处理成功
+     *
+     * @param msg  消息
+     * @param data 数据对象
+     * @return data
+     */
+    public static Result success(String msg, Object data) {
+        return new Result(CODE_SUCCESS, msg, data);
+    }
+    /**
+     * 处理失败,并返回数据(一般为错误信息)
+     *
+     * @param code 错误代码
+     * @param msg  消息
+     * @return data
+     */
+    public static Result failure(int code, String msg) {
+        return new Result(code, msg, NOOP);
+    }
+    /**
+     * 处理失败
+     *
+     * @param msg 消息
+     * @return data
+     */
+    public static Result failure(String msg) {
+        return failure(CODE_FAILURE, msg);
+    }
+
+    @Override
+    public String toString() {
+        return "JsonResult [code=" + code + ", msg=" + msg + ", data="
+                + data + "]";
+    }
+}

+ 17 - 0
src/main/java/com/fdkankan/external/schedule/ScheduleJob.java

@@ -1,6 +1,7 @@
 package com.fdkankan.external.schedule;
 
 import com.fdkankan.external.service.ISceneOfflinePackagePushService;
+import com.fdkankan.external.service.XinxizhongxinService;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -14,6 +15,8 @@ public class ScheduleJob {
 
     @Autowired
     private ISceneOfflinePackagePushService sceneOfflinePackagePushService;
+    @Autowired
+    private XinxizhongxinService xinxizhongxinService;
 
 
 //    /**
@@ -38,4 +41,18 @@ public class ScheduleJob {
 //        log.info("中国文物信息中心场景推送任务结束");
 //    }
 
+    @Scheduled(fixedDelay = 30*1000)
+    public void scenePush4Zgwwxxzx() {
+        log.info("中国文物信息中心场景推送任务开始");
+        xinxizhongxinService.pushScene();
+        log.info("中国文物信息中心场景推送任务结束");
+    }
+
+    @Scheduled(fixedDelay = 30*1000)
+    public void syncPushResult() {
+        log.info("中国文物信息中心场景推送场景结果同步开始");
+        xinxizhongxinService.syncPushResult();
+        log.info("中国文物信息中心场景推送场景结果同步结束");
+    }
+
 }

+ 2 - 1
src/main/java/com/fdkankan/external/service/ISceneOfflinePackagePushService.java

@@ -1,5 +1,6 @@
 package com.fdkankan.external.service;
 
+import com.fdkankan.external.ScenePushBean;
 import com.mybatisflex.core.service.IService;
 import com.fdkankan.external.entity.SceneOfflinePackagePush;
 
@@ -17,6 +18,6 @@ public interface ISceneOfflinePackagePushService extends IService<SceneOfflinePa
 
     SceneOfflinePackagePush getLastByCondition(SceneOfflinePackagePush condition);
 
-    void scenePushHandler(SceneOfflinePackagePush push);
+    void scenePushHandler(ScenePushBean scenePushBean) throws Exception;
 
 }

+ 14 - 0
src/main/java/com/fdkankan/external/service/IZgxxzxPushLogService.java

@@ -0,0 +1,14 @@
+package com.fdkankan.external.service;
+
+import com.mybatisflex.core.service.IService;
+import com.fdkankan.external.entity.ZgxxzxPushLog;
+
+/**
+ *  服务层。
+ *
+ * @author dsx
+ * @since 2025-11-07
+ */
+public interface IZgxxzxPushLogService extends IService<ZgxxzxPushLog> {
+
+}

+ 19 - 0
src/main/java/com/fdkankan/external/service/XinxizhongxinService.java

@@ -0,0 +1,19 @@
+package com.fdkankan.external.service;
+
+import com.fdkankan.external.entity.ZgxxzxPushLog;
+import com.fdkankan.external.request.TaskPageRequest;
+import com.fdkankan.external.response.PageInfo;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+public interface XinxizhongxinService {
+
+    void importExcel(MultipartFile file) throws IOException;
+
+    PageInfo<ZgxxzxPushLog> taskList(TaskPageRequest request);
+
+    void pushScene();
+
+    void syncPushResult();
+}

+ 69 - 76
src/main/java/com/fdkankan/external/service/impl/SceneOfflinePackagePushServiceImpl.java

@@ -19,6 +19,7 @@ import com.fdkankan.common.constant.FileSizeUnitType;
 import com.fdkankan.common.constant.SceneSource;
 import com.fdkankan.common.util.DateExtUtil;
 import com.fdkankan.common.util.FileSizeUtil;
+import com.fdkankan.external.ScenePushBean;
 import com.fdkankan.external.bean.DownloadProcessBean;
 import com.fdkankan.external.bean.LaserDownloadBean;
 import com.fdkankan.external.callback.ErrorCallback;
@@ -165,7 +166,7 @@ public class SceneOfflinePackagePushServiceImpl extends ServiceImpl<SceneOffline
                             push.setZipType("laser");
                             push.setVersion(scene.getOfflineVerForPush());
                             try {
-                                sceneOfflinePackagePushService.scenePushHandler(push);
+//                                sceneOfflinePackagePushService.scenePushHandler(push);
                             }catch (Exception e){
                                 log.error("场景推送失败,num:{}",scenePlus.getNum(), e);
                             }
@@ -198,7 +199,7 @@ public class SceneOfflinePackagePushServiceImpl extends ServiceImpl<SceneOffline
                             push.setZipType("kankan");
                             push.setVersion(version);
                             try {
-                                sceneOfflinePackagePushService.scenePushHandler(push);
+//                                sceneOfflinePackagePushService.scenePushHandler(push);
                             }catch (Exception e){
                                 log.error("场景推送失败,num:{}",scenePlus.getNum(), e);
                             }
@@ -313,91 +314,83 @@ public class SceneOfflinePackagePushServiceImpl extends ServiceImpl<SceneOffline
     }
 
     @Override
-    public void scenePushHandler(SceneOfflinePackagePush push){
-        String num = push.getNum();
-        String zipType = push.getZipType();
-        int version = push.getVersion();
+    public void scenePushHandler(ScenePushBean scenePushBean) throws Exception {
+        String id = scenePushBean.getTaskId();
+        String num = scenePushBean.getNum();
+        String zipType = scenePushBean.getZipType();
+        Long version = scenePushBean.getVersion();
         String downloadUrl = null;
+        ScenePlus scenePlus = scenePlusService.getByNum(num);
+        ScenePlusExt scenePlusExt = scenePlusExtService.getByPlusId(scenePlus.getId());
+        String title = scenePlus.getTitle();
+        if("laser".equals(zipType)){
+            downloadUrl = this.genZipUrl4Laser(num);
+        }else{
+            downloadUrl = this.genZipUrl4Kankan(num);
+        }
 
+        //开始推送到第三方服务
+        if(StrUtil.isEmpty(downloadUrl)){
+            throw new RuntimeException("场景下载失败,下载链接为空,场景码:" + num);
+        }
 
-        try {
-            if("laser".equals(zipType)){
-                downloadUrl = this.genZipUrl4Laser(num);
-            }else{
-                downloadUrl = this.genZipUrl4Kankan(num);
-            }
-
-            //开始推送到第三方服务
-            if(StrUtil.isEmpty(downloadUrl)){
-                throw new RuntimeException("场景下载失败,下载链接为空,场景码:" + num);
-            }
-
-            //下载到本地
-            String zipPath = offlineZipDir.concat(num).concat(".zip");
-            HttpUtil.downloadFile(downloadUrl, zipPath);
-
-            String dirPath = null;
-            String unzipPath = offlineZipDir.concat(num).concat("-").concat(zipType).concat("-").concat(String.valueOf(version));
-            ZipUtil.unzip(zipPath, unzipPath, Charset.forName("GBK"));
-            if("laser".equals(zipType)){
-                dirPath = unzipPath.concat("/www");
-            }else{
-                dirPath = unzipPath.concat("/wwwroot/scene_view_data");
-            }
-            String zipDir = dirPath.concat("/zip/");
-            FileUtil.del(zipDir);
-            String volumeName = zipDir.concat(num).concat(".zip");
-            FileUtil.mkParentDirs(volumeName);
-            String cmd = "cd " + dirPath + " && zip -r " + volumeName + " " + num + " -s 500M";
-            log.info("压缩命令:{}", cmd);
-            CmdUtils.callLineSh(cmd, 200);
-            log.info("分卷压缩完成");
-
-            List<String> fileList = FileUtil.listFileNames(zipDir);
-            if(CollUtil.isEmpty(fileList)){
-                throw new RuntimeException("压缩包不存在");
-            }
-
-            String id = UUID.fastUUID().toString();
-            int index = 1;
-            for (String file : fileList) {
-                Map<String, Object> params = new HashMap<>();
-                params.put("id", id);
-                params.put("action", "upload");
-                params.put("fileName", file);
-                params.put("file", FileUtil.file(zipDir.concat(file)));
-                log.info("开发发送第{}个压缩包", index);
-                String post = HttpUtil.post(push.getDestUrl(), params, 60 * 60 * 1000);
-                log.info("第{}个场景推送成功,接收端返回结果:{}", index, post);
-                ++index;
-            }
+        //下载到本地
+        String zipPath = offlineZipDir.concat(num).concat(".zip");
+        HttpUtil.downloadFile(downloadUrl, zipPath);
+
+        String dirPath = null;
+        String unzipPath = offlineZipDir.concat(num).concat("-").concat(zipType).concat("-").concat(String.valueOf(version));
+        ZipUtil.unzip(zipPath, unzipPath, Charset.forName("GBK"));
+        if("laser".equals(zipType)){
+            dirPath = unzipPath.concat("/www");
+        }else{
+            dirPath = unzipPath.concat("/wwwroot/scene_view_data");
+        }
+        String zipDir = dirPath.concat("/zip/");
+        FileUtil.del(zipDir);
+        String volumeName = zipDir.concat(num).concat(".zip");
+        FileUtil.mkParentDirs(volumeName);
+        String cmd = "cd " + dirPath + " && zip -r " + volumeName + " " + num + " -s 500M";
+        log.info("压缩命令:{}", cmd);
+        CmdUtils.callLineSh(cmd, 200);
+        log.info("分卷压缩完成");
+
+        List<String> fileList = FileUtil.listFileNames(zipDir);
+        if(CollUtil.isEmpty(fileList)){
+            throw new RuntimeException("压缩包不存在");
+        }
 
-            ScenePlus scenePlus = scenePlusService.getByNum(num);
-            ScenePlusExt scenePlusExt = scenePlusExtService.getByPlusId(scenePlus.getId());
-            String title = scenePlus.getTitle();
-            if("laser".equals(zipType)){
-                Scene scene = sceneService.getBySceneCode(scenePlus.getNum());
-                title = scene.getTitle();
-            }
+        int index = 1;
+        for (String file : fileList) {
             Map<String, Object> params = new HashMap<>();
             params.put("id", id);
-            params.put("action", "save");
-            params.put("fileName", num.concat(".zip"));
+            params.put("action", "upload");
+            params.put("fileName", file);
             params.put("num", num);
             params.put("title", title);
             params.put("zipType", zipType);
-            params.put("downloadUrl", downloadUrl);
-            params.put("version", push.getVersion());
-            params.put("calcTime", DateExtUtil.format(scenePlusExt.getAlgorithmTime(), DateExtUtil.dateStyle8));
-            String post = HttpUtil.post(push.getDestUrl(), params, 60 * 60 * 1000);
-            log.info("场景推送成功,接收端返回结果:{}", post);
-            push.setPushStatus(CommonSuccessStatus.SUCCESS.code());
-        }catch (Exception e){
-            log.error("场景推送失败,num:{}", num, e);
-            push.setPushStatus(CommonSuccessStatus.FAIL.code());
+            params.put("file", FileUtil.file(zipDir.concat(file)));
+            log.info("开发发送第{}个压缩包", index);
+            String post = HttpUtil.post(scenePushBean.getDestUrl(), params, 60 * 60 * 1000);
+            log.info("第{}个场景推送成功,接收端返回结果:{}", index, post);
+            ++index;
         }
 
-        this.saveOrUpdate(push);
+        if("laser".equals(zipType)){
+            Scene scene = sceneService.getBySceneCode(scenePlus.getNum());
+            title = scene.getTitle();
+        }
+        Map<String, Object> params = new HashMap<>();
+        params.put("id", id);
+        params.put("action", "save");
+        params.put("fileName", num.concat(".zip"));
+        params.put("num", num);
+        params.put("title", title);
+        params.put("zipType", zipType);
+        params.put("version", scenePushBean.getVersion());
+        params.put("calcTime", DateExtUtil.format(scenePlusExt.getAlgorithmTime(), DateExtUtil.dateStyle8));
+        String post = HttpUtil.post(scenePushBean.getDestUrl(), params, 60 * 60 * 1000);
+        log.info("场景推送成功,接收端返回结果:{}", post);
     }
 
     public static void main(String[] args) throws Exception {

+ 146 - 0
src/main/java/com/fdkankan/external/service/impl/XinxizhongxinServiceImpl.java

@@ -0,0 +1,146 @@
+package com.fdkankan.external.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.EasyExcel;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fdkankan.common.constant.CommonOperStatus;
+import com.fdkankan.common.constant.CommonStatus;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.external.ScenePushBean;
+import com.fdkankan.external.entity.Department;
+import com.fdkankan.external.entity.Scene;
+import com.fdkankan.external.entity.ScenePlus;
+import com.fdkankan.external.entity.ZgxxzxPushLog;
+import com.fdkankan.external.request.TaskPageRequest;
+import com.fdkankan.external.response.PageInfo;
+import com.fdkankan.external.service.*;
+import com.mybatisflex.core.paginate.Page;
+import com.mybatisflex.core.query.QueryWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class XinxizhongxinServiceImpl implements XinxizhongxinService {
+
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private ISceneService sceneService;
+    @Autowired
+    private IZgxxzxPushLogService zgxxzxPushLogService;
+    @Autowired
+    private ISceneOfflinePackagePushService sceneOfflinePackagePushService;
+    @Autowired
+    private IDepartmentService departmentService;
+
+
+    @Override
+    public void importExcel(MultipartFile file) throws IOException {
+
+        String uuid = UUID.randomUUID().toString();
+        String s = FileUtil.extName(file.getOriginalFilename());
+        File tempFile = FileUtil.createTempFile(uuid, "." + s, new File("/home/backend/4dkankan_v4/external/tmp"), true);
+        FileUtil.mkParentDirs(tempFile);
+        file.transferTo(tempFile);
+
+        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish
+        List<ZgxxzxPushLog> list = EasyExcel.read(tempFile).head(ZgxxzxPushLog.class).sheet().doReadSync();
+        if(CollUtil.isEmpty(list)){
+            throw new BusinessException(ErrorCode.SYSTEM_ERROR.code(), "excel数据有误");
+        }
+        List<String> numList = list.stream().map(v -> v.getNum()).collect(Collectors.toList());
+        List<Scene> sceneList = sceneService.list(QueryWrapper.create().in(Scene::getSceneCode, numList).eq(Scene::getStatus, 2));
+        Map<String, Scene> dbNumMap = sceneList.stream().collect(Collectors.toMap(v->v.getSceneCode(), v->v));
+        Set<String> errorNumList = numList.stream().filter(num -> !dbNumMap.keySet().contains(num)).collect(Collectors.toSet());
+        if(CollUtil.isNotEmpty(errorNumList)){
+            StringBuffer sb = new StringBuffer("以下场景不存在或错误:");
+            errorNumList.stream().forEach(v->sb.append(v).append("、"));
+            throw new BusinessException(ErrorCode.SYSTEM_ERROR.code(), sb.toString());
+        }
+
+        list.stream().forEach(v->{
+            Scene scene = dbNumMap.get(v.getNum());
+            v.setTitle(scene.getTitle());
+            v.setStatus(CommonOperStatus.WAITING.code());
+        });
+        zgxxzxPushLogService.saveBatch(list);
+    }
+
+    @Override
+    public PageInfo<ZgxxzxPushLog> taskList(TaskPageRequest request) {
+        QueryWrapper queryWrapper = QueryWrapper.create().orderBy(ZgxxzxPushLog::getId, false);
+        if(StrUtil.isNotEmpty(request.getNum())){
+            queryWrapper.like(ZgxxzxPushLog::getNum, request.getNum());
+        }
+        if(StrUtil.isNotEmpty(request.getTitle())){
+            queryWrapper.like(ZgxxzxPushLog::getTitle, request.getTitle());
+        }
+        if(request.getStatus() == 0){
+            queryWrapper.in(ZgxxzxPushLog::getStatus, 0,2);
+        }
+        if(request.getStatus() == 1){
+            queryWrapper.in(ZgxxzxPushLog::getStatus, -1,1);
+        }
+        Page<ZgxxzxPushLog> page = zgxxzxPushLogService.page(new Page<>(request.getPageNum(), request.getPageSize()), queryWrapper);
+        return PageInfo.PageInfo(page);
+    }
+
+    @Override
+    public void pushScene() {
+        List<ZgxxzxPushLog> list = zgxxzxPushLogService.list(
+                QueryWrapper.create().eq(ZgxxzxPushLog::getStatus, CommonOperStatus.WAITING.code())
+                        .orderBy(ZgxxzxPushLog::getId,true));
+        if(CollUtil.isEmpty(list)){
+            return;
+        }
+        Department zgwwxxzx = departmentService.getByCode("zgwwxxzx");
+        if(zgwwxxzx == null){
+            return;
+        }
+        for (ZgxxzxPushLog zgxxzxPushLog : list) {
+            ScenePushBean pushBean = ScenePushBean.builder()
+                    .taskId(UUID.fastUUID().toString())
+                    .num(zgxxzxPushLog.getNum()).zipType("laser")
+                    .version(Calendar.getInstance().getTimeInMillis())
+                    .destUrl(zgwwxxzx.getDestUrl()).build();
+            zgxxzxPushLog.setStatus(2);
+            try {
+                zgxxzxPushLogService.updateById(zgxxzxPushLog);
+                sceneOfflinePackagePushService.scenePushHandler(pushBean);
+            }catch (Exception e){
+                log.error("场景推送失败,num:{}", zgxxzxPushLog.getNum(), e);
+                zgxxzxPushLog.setStatus(CommonOperStatus.FAILD.code());
+                zgxxzxPushLogService.updateById(zgxxzxPushLog);
+            }
+        }
+    }
+
+    @Override
+    public void syncPushResult() {
+        List<ZgxxzxPushLog> list = zgxxzxPushLogService.list(
+                QueryWrapper.create().eq(ZgxxzxPushLog::getStatus, 2)
+                        .orderBy(ZgxxzxPushLog::getId,true));
+        if(CollUtil.isEmpty(list)){
+            return;
+        }
+        for (ZgxxzxPushLog zgxxzxPushLog : list) {
+
+        }
+
+    }
+}

+ 18 - 0
src/main/java/com/fdkankan/external/service/impl/ZgxxzxPushLogServiceImpl.java

@@ -0,0 +1,18 @@
+package com.fdkankan.external.service.impl;
+
+import com.mybatisflex.spring.service.impl.ServiceImpl;
+import com.fdkankan.external.entity.ZgxxzxPushLog;
+import com.fdkankan.external.mapper.ZgxxzxPushLogMapper;
+import com.fdkankan.external.service.IZgxxzxPushLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ *  服务层实现。
+ *
+ * @author dsx
+ * @since 2025-11-07
+ */
+@Service
+public class ZgxxzxPushLogServiceImpl extends ServiceImpl<ZgxxzxPushLogMapper, ZgxxzxPushLog> implements IZgxxzxPushLogService {
+
+}

+ 19 - 113
src/main/resources/bootstrap-dev.yml

@@ -1,116 +1,22 @@
-server:
-  port: 10002
 spring:
   application:
     name: 4dkankan-center-external
-  redis:
-    host: 120.24.144.164
-    port: 6379
-    timeout: 6000ms
-    password: bgh0cae240
-    jedis:
-      pool:
-        max-active: 10  #连接池最大连接数(使用负值表示没有限制)
-        max-idle: 10 # 连接池中的最大空闲连接
-        min-idle: 5 # 连接池中的最小空闲连接
-        max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
-    lettuce:
-      shutdown-timeout: 0ms
-  rabbitmq:
-    host: 120.24.144.164
-    port: 5672
-    username: admin
-    password: adminv41234
-    virtual-host: 4dkankan
-    connection-timeout: 0
-    listener:
-      simple:
-        prefetch: 5
-        max-concurrency: 10
-        acknowledge-mode: manual #开启消费者手动确认
-    #开启消息投递确认机制
-    publisher-confirm-type: correlated
-account:
-  username: super-admin
-  password: Aa123456
-host:
-  4dkk:
-    manage: https://v4-uat.4dkankan.com
-    scene: https://test.4dkankan.com
-  laser: https://uat-laser.4dkankan.com
-api:
-  4dkk:
-    manage:
-      login: /service/manage/login
-      checkDownLoad: /service/manage/scene/checkDownLoad?num=%s
-      downScene: /service/manage/scene/downScene?num=%s
-      downloadProcess: /service/manage/scene/downloadProcess?num=%s
-    scene:
-      getInfo: /service/scene/getInfo?num=%s
-  laser:
-    downOfflineScene: /laser/4dage/downOfflineScene
-
-forest:
-  ## 日志总开关,打开/关闭Forest请求/响应日志(默认为 true)
-  log-enabled: true
-  ## 打开/关闭Forest请求日志(默认为 true)
-  log-request: true
-  ## 打开/关闭Forest响应状态日志(默认为 true)
-  log-response-status: true
-  ## 打开/关闭Forest响应内容日志(默认为 false)
-  log-response-content: true
-  ## 请求超时时间,单位为毫秒, 默认值为3000
-  timeout: 10000
-  ## 连接超时时间,单位为毫秒, 默认值为2000
-  connect-timeout: 10000
-
-logging:
-  path: /home/backend/4dkankan_v4
-
-mybatis-flex:
-  datasource:
-    primary:
-      url: jdbc:mysql://120.24.144.164:3306/4dkankan_center_external
-      username: root
-      password: 4Dage@4Dage#@168
-    www:
-      url: jdbc:mysql://120.24.144.164:3306/4dkankan_v4
-      username: root
-      password: 4Dage@4Dage#@168
-    laser:
-      url: jdbc:mysql://120.25.146.52:13306/fdkk_laser
-      username: root
-      password: JK123456%JIK
-oss:
-  host:
-    laser:
-      old: https://laser-oss.4dkankan.com
-      new: https://zgwwzzzx-laser-download.4dage.com
-    4dkk:
-      old: https://4dkk.4dage.com
-      new: https://zgwwzzzx-download.4dage.com
-fyun:
-  type: oss
-  key: LTAI5tJwboCj3r4vUNkSmbyX
-  secret: meDy7VYAWbg8kZCKsoUZcIYQxigWOy
-  bucket: 4dkankan
-  coldBucket: 4dkk-bak  ##冷归档bucket
-  endPoint: http://oss-cn-shenzhen.aliyuncs.com
-  host: https://4dkk.4dage.com/
-
-file:
-  offlineZip:
-    dir: /mnt/external/temp/
-
-scrb:
-  obs:
-    use: true
-    bucket: djqk-vr
-    endPoint: obsv3.scrb-cd-1.sichuandaily.com.cn
-    ak: AFMVGM5CPSHHQ7UPG3DO
-    sk: IUYocj8qgixoDxhj3JIVKXtyBV3lGDJBDFgRhO21
-    host: http://djqk-vr.obsv3.scrb-cd-1.sichuandaily.com.cn/
-
-
-
-
+  cloud:
+    nacos:
+      server-addr: 172.18.156.39:8848
+      config:
+        file-extension: yaml
+        namespace: 4dkankan-v4-test
+        extension-configs:
+          - data-id: 4dkankan-center-external.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+        shared-configs:
+          - data-id: common-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+          - data-id: forest-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+      discovery:
+        namespace: 4dkankan-v4-test

+ 7 - 0
src/main/resources/bootstrap-prod.yml

@@ -11,5 +11,12 @@ spring:
           - data-id: 4dkankan-center-external.yaml
             group: DEFAULT_GROUP
             refresh: true
+        shared-configs:
+          - data-id: common-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+          - data-id: forest-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
       discovery:
         namespace: 4dkankan-v4-prod

+ 7 - 0
src/main/resources/bootstrap-test.yml

@@ -11,5 +11,12 @@ spring:
           - data-id: 4dkankan-center-external.yaml
             group: DEFAULT_GROUP
             refresh: true
+        shared-configs:
+          - data-id: common-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+          - data-id: forest-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
       discovery:
         namespace: 4dkankan-v4-test