TRX 1 år sedan
förälder
incheckning
2f39bdd16d

+ 11 - 0
src/main/java/com/zswl/dataservice/controller/TestController.java

@@ -2,6 +2,7 @@ package com.zswl.dataservice.controller;
 
 import com.zswl.dataservice.model.mqtt.SendMessageModel;
 import com.zswl.dataservice.service.artemis.ArtemisService;
+import com.zswl.dataservice.service.base.ScanExecuteService;
 import com.zswl.dataservice.service.user.impl.UserServiceImpl;
 import com.zswl.dataservice.utils.result.ResultContent;
 import io.swagger.v3.oas.annotations.Operation;
@@ -25,6 +26,9 @@ public class TestController {
     @Autowired
     ArtemisService artemisService;
 
+    @Autowired
+    ScanExecuteService scanExecuteService;
+
     @Operation(summary = "发送指令")
     @RequestMapping(value = "free/sendMessage", method = {RequestMethod.POST})
     public ResultContent sendMessage(@RequestBody SendMessageModel param) {
@@ -37,5 +41,12 @@ public class TestController {
         return ResultContent.buildSuccess(System.currentTimeMillis());
     }
 
+    @Operation(summary = "scanSystemExecuteMethod")
+    @RequestMapping(value = "free/scanSystemExecuteMethod", method = {RequestMethod.GET})
+    public ResultContent scanSystemExecuteMethod() {
+        scanExecuteService.scanSystemExecuteMethod();
+        return ResultContent.buildSuccess();
+    }
+
 }
 

+ 15 - 0
src/main/java/com/zswl/dataservice/dao/other/ExecuteMethodInfoDao.java

@@ -0,0 +1,15 @@
+package com.zswl.dataservice.dao.other;
+
+import com.zswl.dataservice.dao.MongoDao;
+import com.zswl.dataservice.domain.other.ExecuteMethodInfo;
+import com.zswl.dataservice.domain.user.AppInfo;
+
+/**
+ * @author TRX
+ * @date 2024/3/21
+ */
+public interface ExecuteMethodInfoDao extends MongoDao<ExecuteMethodInfo> {
+
+    ExecuteMethodInfo findTopByEvent(String eventName);
+
+}

+ 28 - 0
src/main/java/com/zswl/dataservice/domain/ExecuteAnnotationService.java

@@ -0,0 +1,28 @@
+package com.zswl.dataservice.domain;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ExecuteAnnotationService {
+
+    /**
+     *
+     * @return
+     */
+    String value() default "";
+
+
+    /**
+     *
+     * @return
+     */
+    String remark() default "";
+
+    /**
+     *
+     * @return
+     */
+    Class<?> serviceName() default Void.class;
+}

+ 26 - 0
src/main/java/com/zswl/dataservice/domain/ExecuteAnnotationServiceMethod.java

@@ -0,0 +1,26 @@
+package com.zswl.dataservice.domain;
+
+import java.lang.annotation.*;
+
+/**
+ * mqtt执行方法注解
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ExecuteAnnotationServiceMethod {
+
+    /**
+     * 方法扫描
+     *
+     * @return
+     */
+    String value() default "";
+
+    /**
+     * 方法备注
+     * @return
+     */
+    String remark() default "";
+
+}

+ 6 - 0
src/main/java/com/zswl/dataservice/domain/mqtt/OperationMessage.java

@@ -96,6 +96,12 @@ public class OperationMessage extends SuperEntity {
     @Schema(description = "处理结果")
     private String handleMsg;
 
+    @Schema(description = "业务处理的bean")
+    private String beanName;
+
+    @Schema(description = "业务处理的方法")
+    private String methodName;
+
     //--------------------返回数据 start ------------------
     @Schema(description = "是否响应成功")
     private Boolean isResult = Boolean.FALSE;

+ 28 - 0
src/main/java/com/zswl/dataservice/domain/other/ExecuteMethodInfo.java

@@ -0,0 +1,28 @@
+package com.zswl.dataservice.domain.other;
+
+import com.zswl.dataservice.domain.base.SuperEntity;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * @author TRX
+ * @date 2024/6/27
+ */
+@Data
+@Document
+@NoArgsConstructor
+@AllArgsConstructor
+public class ExecuteMethodInfo extends SuperEntity {
+
+    @Schema(description = "对应的service bean名称")
+    private String beanName;
+
+    @Schema(description = "标记名称")
+    private String event;
+
+    @Schema(description = "bean里的方法名称")
+    private String methodName;
+}

+ 33 - 0
src/main/java/com/zswl/dataservice/init/ScanMqttEventExecuteRunner.java

@@ -0,0 +1,33 @@
+package com.zswl.dataservice.init;
+
+import com.zswl.dataservice.service.base.ScanExecuteService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 扫描记录 mqtt event 对应的执行方法
+ *
+ * @author TRX
+ * @date 2024/6/27
+ */
+@Slf4j
+@Component
+public class ScanMqttEventExecuteRunner implements ApplicationRunner {
+
+    @Autowired
+    ScanExecuteService scanExecuteService;
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        CompletableFuture.runAsync(() -> {
+            scanExecuteService.scanSystemExecuteMethod();
+        });
+    }
+
+}

+ 37 - 11
src/main/java/com/zswl/dataservice/service/artemis/OperationMessageService.java

@@ -5,10 +5,14 @@ import cn.hutool.json.JSONUtil;
 import com.google.gson.JsonObject;
 import com.zswl.dataservice.dao.mqtt.DeviceInfoDao;
 import com.zswl.dataservice.dao.mqtt.OperationMessageDao;
+import com.zswl.dataservice.dao.other.ExecuteMethodInfoDao;
 import com.zswl.dataservice.domain.mqtt.DeviceInfo;
 import com.zswl.dataservice.domain.mqtt.OperationMessage;
+import com.zswl.dataservice.domain.other.ExecuteMethodInfo;
+import com.zswl.dataservice.helper.ApplicationContextHolder;
 import com.zswl.dataservice.model.hxz.ConsumTransactionsModel;
 import com.zswl.dataservice.model.mqtt.*;
+import com.zswl.dataservice.service.base.SuperService;
 import com.zswl.dataservice.service.mqtt.DeviceInfoService;
 import com.zswl.dataservice.service.mqtt.GateWayInfoService;
 import com.zswl.dataservice.service.payment.HxzService;
@@ -21,10 +25,12 @@ import com.zswl.dataservice.utils.result.ResultContent;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
 
+import java.lang.reflect.Method;
 import java.util.Date;
 import java.util.UUID;
 
@@ -59,6 +65,12 @@ public class OperationMessageService {
     // 保存90天
     private Long ttlMill = 90 * 24L * 60 * 60 * 1000L;
 
+    @Autowired
+    private ExecuteMethodInfoDao executeMethodInfoDao;
+
+    @Autowired
+    private ApplicationContext applicationContext;
+
     /**
      * 给设备下发指令
      *
@@ -119,14 +131,17 @@ public class OperationMessageService {
     public ResultContent addOperationMessage(OperationMessage entity) {
         entity.setTime(DateUtils.paresTime(System.currentTimeMillis(), DateUtils.patternyyyySSS));
         entity.setTtl(new Date(System.currentTimeMillis() + ttlMill));
-        if(entity.getIsTimeOut()) {
+        if (entity.getIsTimeOut()) {
             entity.setHandleMsg("超时不处理");
         }
-        operationMessageDao.save(entity);
         boolean isTimeOut = entity.getIsTimeOut();
-        if(!isTimeOut) {
-            // 处理消息
+        // TODO
+        if (isTimeOut) {
+            // 未超时,处理消息
             handleOperationMessage(entity);
+        } else {
+            // 超时
+            operationMessageDao.save(entity);
         }
         return ResultContent.buildSuccess();
     }
@@ -142,21 +157,31 @@ public class OperationMessageService {
         JSONObject json = (JSONObject) entity.getData();
         if (json.containsKey("data")) {
             Object result = null;
-            String dataStr = json.getStr("data");
 
             boolean isHandleSuccess = true;
             String handleMsg = "处理成功";
             try {
-                // 判断那个业务处理
-                if (event.equals("consum")) {
-                    ConsumTransactionsModel model = JSONUtil.toBean(dataStr, ConsumTransactionsModel.class);
-                    ResultContent<Object> resultContent = hxzService.consumTransactions(model);
+                ExecuteMethodInfo executeMethodInfo = executeMethodInfoDao.findTopByEvent(event);
+                if (ObjectUtils.isNotEmpty(executeMethodInfo)) {
+                    String dataStr = json.getStr("data");
+
+                    String beanName = executeMethodInfo.getBeanName();
+                    String methodName = executeMethodInfo.getMethodName();
+                    Class c = applicationContext.getBean(beanName).getClass();
+                    SuperService t = (SuperService) applicationContext.getBean(beanName);
+                    Method method = c.getMethod(methodName, String.class);
+                    ResultContent<Object> resultContent = (ResultContent<Object>) method.invoke(t, dataStr);
                     if (resultContent.isSuccess()) {
                         result = resultContent.getContent();
-                    }else {
+                    } else {
                         isHandleSuccess = false;
                         handleMsg = resultContent.getMsg();
                     }
+                    entity.setBeanName(beanName);
+                    entity.setMethodName(methodName);
+                } else {
+                    isHandleSuccess = false;
+                    handleMsg = "消息处理方法未找到";
                 }
             } catch (Exception e) {
                 e.printStackTrace();
@@ -172,7 +197,8 @@ public class OperationMessageService {
             if (isHandleSuccess) {
                 // 处理成功,返回响应
                 responseMessage(entity);
-            }else {
+            } else {
+                // 处理失败,记录数据
                 entity.setReTime(System.currentTimeMillis());
                 entity.setReTimeStr(DateUtils.paresTime(System.currentTimeMillis(), DateUtils.patternyyyySSS));
                 operationMessageDao.save(entity);

+ 60 - 0
src/main/java/com/zswl/dataservice/service/base/ScanExecuteService.java

@@ -0,0 +1,60 @@
+package com.zswl.dataservice.service.base;
+
+import com.zswl.dataservice.dao.other.ExecuteMethodInfoDao;
+import com.zswl.dataservice.domain.ExecuteAnnotationService;
+import com.zswl.dataservice.domain.ExecuteAnnotationServiceMethod;
+import com.zswl.dataservice.domain.other.ExecuteMethodInfo;
+import com.zswl.dataservice.utils.CommonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author TRX
+ * @date 2024/6/27
+ */
+@Slf4j
+@Service
+public class ScanExecuteService {
+
+    @Autowired
+    ExecuteMethodInfoDao executeMethodInfoDao;
+
+    /**
+     * 扫码方法
+     */
+    public void scanSystemExecuteMethod() {
+        Set<Class<?>> domainClasses = ScanSupport.classInfos();
+        List<Class> standardClasses = domainClasses.stream().filter(cls -> cls.isAnnotationPresent(ExecuteAnnotationService.class)).collect(Collectors.toList());
+        executeMethodInfoDao.deleteAll();
+        List<ExecuteMethodInfo> list = new ArrayList<>();
+        if (ObjectUtils.isNotEmpty(standardClasses)) {
+            for (Class cls : standardClasses) {
+                String className = CommonUtil.toFirstCharLowerCase(cls.getSimpleName());
+                Method[] methods = cls.getMethods();
+                for (Method method : methods) {
+                    if (method.isAnnotationPresent(ExecuteAnnotationServiceMethod.class)) {
+                        String methodName = method.getName();
+                        ExecuteAnnotationServiceMethod t = method.getAnnotation(ExecuteAnnotationServiceMethod.class);
+                        ExecuteMethodInfo methodInfo = new ExecuteMethodInfo();
+                        methodInfo.setMethodName(methodName);
+                        methodInfo.setBeanName(className);
+                        methodInfo.setEvent(t.value());
+                        methodInfo.setRemark(t.remark());
+                        list.add(methodInfo);
+                    }
+                }
+            }
+        }
+        executeMethodInfoDao.saveAll(list);
+        log.info("scanSystemExecuteMethod size: {} ", list.size());
+    }
+
+}

+ 96 - 0
src/main/java/com/zswl/dataservice/service/base/ScanSupport.java

@@ -0,0 +1,96 @@
+package com.zswl.dataservice.service.base;
+
+import com.zswl.dataservice.helper.ApplicationContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternUtils;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.SystemPropertyUtils;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+
+@Slf4j
+@Component
+public class ScanSupport implements ResourceLoaderAware {
+    /**
+     * Spring容器注入
+     */
+    private ResourceLoader resourceLoader;
+
+    private ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
+    private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
+    private static final String FULLTEXT_SACN_PACKAGE_PATH = "com.zswl.dataservice";
+
+    /**
+     * set注入对象
+     */
+    @Override
+    public void setResourceLoader(ResourceLoader resourceLoader) {
+        this.resourceLoader = resourceLoader;
+    }
+
+    /**
+     * 利用spring提供的扫描包下面的类信息,再通过classfrom反射获得类信息
+     *
+     * @param scanPath
+     * @return
+     * @throws IOException
+     */
+    public Set<Class<?>> doScan(String scanPath) {
+        Set<Class<?>> classes = new HashSet<Class<?>>();
+        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+                .concat(ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(scanPath))
+                        .concat("/**/*.class"));
+        Resource[] resources = new Resource[0];
+        try {
+            resources = resolver.getResources(packageSearchPath);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        MetadataReader metadataReader = null;
+        for (Resource resource : resources) {
+            if (resource.isReadable()) {
+                try {
+                    metadataReader = metadataReaderFactory.getMetadataReader(resource);
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+                try {
+                    if (metadataReader.getClassMetadata().isConcrete()) {// 当类型不是抽象类或接口在添加到集合
+                        classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
+                    }
+                } catch (ClassNotFoundException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return classes;
+    }
+
+    /**
+     * 指定包下面的类信息
+     *
+     * @return 多个类信息
+     */
+    public static Set<Class<?>> classInfos() {
+        try {
+//            String scanPath = ApplicationContextHolder.getContext().getEnvironment()
+//                    .getProperty(FULLTEXT_SACN_PACKAGE_PATH);
+//            scanPath = FULLTEXT_SACN_PACKAGE_PATH;
+            return new ScanSupport().doScan(FULLTEXT_SACN_PACKAGE_PATH);
+        } catch (Exception e) {
+            log.error("扫描包类信息错误", e);
+        }
+        return null;
+    }
+}

+ 9 - 2
src/main/java/com/zswl/dataservice/service/payment/HxzService.java

@@ -1,6 +1,9 @@
 package com.zswl.dataservice.service.payment;
 
+import cn.hutool.json.JSONUtil;
 import com.zswl.dataservice.dao.mqtt.DeviceInfoDao;
+import com.zswl.dataservice.domain.ExecuteAnnotationService;
+import com.zswl.dataservice.domain.ExecuteAnnotationServiceMethod;
 import com.zswl.dataservice.domain.mqtt.DeviceInfo;
 import com.zswl.dataservice.httpRequest.ApiRequestService;
 import com.zswl.dataservice.httpRequest.apiConf.APIResponseModel;
@@ -29,6 +32,7 @@ import java.util.Map;
  */
 @Slf4j
 @Service
+@ExecuteAnnotationService
 public class HxzService extends SuperService {
 
     @Autowired
@@ -75,10 +79,13 @@ public class HxzService extends SuperService {
     /**
      * 刷卡扣费
      *
-     * @param params
+     * @param dataStr
      * @return
      */
-    public ResultContent<Object> consumTransactions(ConsumTransactionsModel params) {
+    @ExecuteAnnotationServiceMethod(value = "consum", remark = "云版消费机 用户刷卡综合接口")
+    public ResultContent<Object> consumTransactions(String dataStr) {
+        ConsumTransactionsModel params = JSONUtil.toBean(dataStr, ConsumTransactionsModel.class);
+
         ConsumTransactionsResult ret = null;
         //十进制转16进制
         final String cardNumber = params.getCardNo();

+ 4 - 0
src/main/java/com/zswl/dataservice/service/payment/package-info.java

@@ -0,0 +1,4 @@
+package com.zswl.dataservice.service.payment;
+/**
+ * 支付相关的Service
+ */

+ 7 - 0
src/main/java/com/zswl/dataservice/utils/CommonUtil.java

@@ -307,4 +307,11 @@ public class CommonUtil {
         }
         return mins;
     }
+
+    public static String toFirstCharLowerCase(String str) {
+        if (str == null || str.isEmpty()) {
+            return str;
+        }
+        return Character.toLowerCase(str.charAt(0)) + str.substring(1);
+    }
 }