diff --git a/src/main/java/com/iflytop/gd/app/common/annotation/CommandMapping.java b/src/main/java/com/iflytop/gd/app/common/annotation/CommandMapping.java new file mode 100644 index 0000000..5432a10 --- /dev/null +++ b/src/main/java/com/iflytop/gd/app/common/annotation/CommandMapping.java @@ -0,0 +1,12 @@ +package com.iflytop.gd.app.common.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface CommandMapping { + String value(); +} \ No newline at end of file diff --git a/src/main/java/com/iflytop/gd/app/controller/CmdController.java b/src/main/java/com/iflytop/gd/app/controller/CmdController.java new file mode 100644 index 0000000..5a3184b --- /dev/null +++ b/src/main/java/com/iflytop/gd/app/controller/CmdController.java @@ -0,0 +1,55 @@ +package com.iflytop.gd.app.controller; + +import com.iflytop.gd.app.core.cmd.CommandHandler; +import com.iflytop.gd.app.core.cmd.CommandHandlerRegistry; +import com.iflytop.gd.app.model.dto.CmdDTO; +import com.iflytop.gd.system.common.result.Result; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.CompletableFuture; + +@Tag(name = "前端业务指令") +@RestController +@RequestMapping("/api/cmd") +@RequiredArgsConstructor +@Slf4j +public class CmdController { + private final CommandHandlerRegistry registry; + + @Operation(summary = "前端统一调用一个接口") + @PostMapping + public Result controlMethod(@RequestBody CmdDTO cmdDTO) { + String cmdId = cmdDTO.getCmdId(); + String cmdCode = cmdDTO.getCmdCode(); + try { + CommandHandler commandHandler = registry.getHandler(cmdCode); + if (commandHandler == null) { + log.error("未找到对应的业务指令"); + return Result.failed(); + } + log.info("业务指令开始执行"); + CompletableFuture future = commandHandler.handle(cmdDTO); + future.whenComplete((v, ex) -> { + if (ex != null) { + log.error("执行业务指令发生异常: {}", cmdDTO, ex); + } else { + log.info("业务指令执行成功"); + } + log.info("业务指令执行结束"); + }); + } catch (Exception e) { + log.error("执行业务指令发生异常: {}", cmdDTO, e); + return Result.failed(e.getMessage()); + } + return Result.success(); + } + + +} diff --git a/src/main/java/com/iflytop/gd/app/core/cmd/CommandHandler.java b/src/main/java/com/iflytop/gd/app/core/cmd/CommandHandler.java new file mode 100644 index 0000000..cadee50 --- /dev/null +++ b/src/main/java/com/iflytop/gd/app/core/cmd/CommandHandler.java @@ -0,0 +1,9 @@ +package com.iflytop.gd.app.core.cmd; + +import com.iflytop.gd.app.model.dto.CmdDTO; + +import java.util.concurrent.CompletableFuture; + +public interface CommandHandler { + CompletableFuture handle(CmdDTO cmdDTO); +} \ No newline at end of file diff --git a/src/main/java/com/iflytop/gd/app/core/cmd/CommandHandlerRegistry.java b/src/main/java/com/iflytop/gd/app/core/cmd/CommandHandlerRegistry.java new file mode 100644 index 0000000..767e2e6 --- /dev/null +++ b/src/main/java/com/iflytop/gd/app/core/cmd/CommandHandlerRegistry.java @@ -0,0 +1,42 @@ +package com.iflytop.gd.app.core.cmd; + +import com.iflytop.gd.app.common.annotation.CommandMapping; +import io.micrometer.common.lang.NonNull; +import jakarta.annotation.PostConstruct; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class CommandHandlerRegistry implements ApplicationContextAware { + + private final Map handlerMap = new HashMap<>(); + private ApplicationContext applicationContext; + + @Override + public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @PostConstruct + public void init() { + Map beans = applicationContext.getBeansWithAnnotation(CommandMapping.class); + for (Object bean : beans.values()) { + // 获取实际目标类,而不是代理类 + Class targetClass = AopUtils.getTargetClass(bean); + CommandMapping mapping = targetClass.getAnnotation(CommandMapping.class); + if (mapping != null && bean instanceof CommandHandler) { + handlerMap.put(mapping.value(), (CommandHandler) bean); + } + } + } + + public CommandHandler getHandler(String command) { + return handlerMap.get(command); + } +} \ No newline at end of file diff --git a/src/main/java/com/iflytop/gd/app/model/dto/CmdDTO.java b/src/main/java/com/iflytop/gd/app/model/dto/CmdDTO.java new file mode 100644 index 0000000..bdbe334 --- /dev/null +++ b/src/main/java/com/iflytop/gd/app/model/dto/CmdDTO.java @@ -0,0 +1,55 @@ +package com.iflytop.gd.app.model.dto; + +import cn.hutool.json.JSONUtil; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.util.Map; +import java.util.Optional; + +@Schema(description = "指令") +@Data +public class CmdDTO { + + @NotBlank() + @Schema(description = "指令id,前端生成唯一ID") + private String cmdId; + + @NotBlank() + @Schema(description = "指令") + private String cmdCode; + + @Schema(description = "参数") + private Map params; + + public Double getDoubleParam(String key) { + return Optional.ofNullable(params.get(key)) + .map(Object::toString) + .map(Double::parseDouble) + .orElse(null); + } + + public String getStringParam(String key) { + return (String) params.get(key); + } + + public Integer getIntegerParam(String key) { + return Optional.ofNullable(params.get(key)) + .map(Object::toString) + .map(Integer::parseInt) + .orElse(null); + } + + public Boolean getBooleanParam(String key) { + return Optional.ofNullable(params.get(key)) + .map(Object::toString) + .map(Boolean::parseBoolean) + .orElse(null); + } + + @Override + public String toString() { + return JSONUtil.toJsonStr(this); + } +}