diff --git a/pom.xml b/pom.xml index d71d0e9..c880708 100644 --- a/pom.xml +++ b/pom.xml @@ -102,6 +102,9 @@ 17 17 + + -parameters + org.mapstruct diff --git a/src/main/java/com/metis/MetisApplication.java b/src/main/java/com/metis/MetisApplication.java index b083632..b9dc604 100644 --- a/src/main/java/com/metis/MetisApplication.java +++ b/src/main/java/com/metis/MetisApplication.java @@ -2,9 +2,8 @@ package com.metis; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) +@SpringBootApplication public class MetisApplication { public static void main(String[] args) { diff --git a/src/main/java/com/metis/controller/ProcessDefinitionController.java b/src/main/java/com/metis/controller/ProcessDefinitionController.java new file mode 100644 index 0000000..58ebbf5 --- /dev/null +++ b/src/main/java/com/metis/controller/ProcessDefinitionController.java @@ -0,0 +1,43 @@ +package com.metis.controller; + +import com.metis.domain.bo.ProcessBo; +import com.metis.facade.ProcessDefinitionFacade; +import com.metis.flow.domain.entity.App; +import com.metis.result.Result; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/process/definition") +public class ProcessDefinitionController { + + private final ProcessDefinitionFacade processDefinitionFacade; + + + @PostMapping("/create") + public Result create(@RequestBody ProcessBo processBo) { + processDefinitionFacade.create(processBo); + return Result.ok(); + } + + @PutMapping("/update") + public Result update(@RequestBody ProcessBo processBo) { + processDefinitionFacade.update(processBo); + return Result.ok(); + } + + + @GetMapping("/{deploymentId}") + public Result getByDeploymentId(@PathVariable Long deploymentId) { + App app = processDefinitionFacade.getByDeploymentId(deploymentId); + return Result.ok(app); + } + + @DeleteMapping("/{appId}") + public Result delete(@PathVariable Long appId) { + processDefinitionFacade.delete(appId); + return Result.ok(); + } + +} diff --git a/src/main/java/com/metis/domain/BaseEntity.java b/src/main/java/com/metis/domain/BaseEntity.java deleted file mode 100644 index de02d39..0000000 --- a/src/main/java/com/metis/domain/BaseEntity.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.metis.domain; - -import com.fasterxml.jackson.annotation.JsonFormat; -import lombok.Data; - -import java.io.Serializable; -import java.time.LocalDateTime; - -/** - * @author Clay - * @date 2022/10/30 - */ -@Data -public class BaseEntity implements Serializable { - - /** - * 创建者 - */ -// private Object createBy; - - /** - * 创建时间 - */ - @JsonFormat(locale = "zh",timezone = "GMT+8",pattern = "yyyy-MM-dd") - private LocalDateTime createTime; - - /** - * 更新者 - */ -// private Object updateBy; - - /** - * 更新时间 - */ - @JsonFormat(locale = "zh",timezone = "GMT+8",pattern = "yyyy-MM-dd") - private LocalDateTime updateTime; - - - /** - * 逻辑删除字段 - */ - private Boolean isDeleted; - - -} diff --git a/src/main/java/com/metis/domain/SimpleBaseEntity.java b/src/main/java/com/metis/domain/SimpleBaseEntity.java new file mode 100644 index 0000000..c4a4c07 --- /dev/null +++ b/src/main/java/com/metis/domain/SimpleBaseEntity.java @@ -0,0 +1,43 @@ +package com.metis.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author Clay + * @date 2022/10/30 + */ +@Data +public class SimpleBaseEntity implements Serializable { + + /** + * 创建时间 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + + /** + * 更新时间 + */ + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @TableField(fill = FieldFill.INSERT) + private LocalDateTime updateTime; + + + /** + * 逻辑删除字段 + */ + @TableLogic(value = "0", delval = "1") + @TableField(fill = FieldFill.INSERT) + private Integer isDeleted; + + +} diff --git a/src/main/java/com/metis/domain/bo/ProcessBo.java b/src/main/java/com/metis/domain/bo/ProcessBo.java new file mode 100644 index 0000000..7e65629 --- /dev/null +++ b/src/main/java/com/metis/domain/bo/ProcessBo.java @@ -0,0 +1,20 @@ +package com.metis.domain.bo; + +import com.metis.enums.YesOrNoEnum; +import com.metis.flow.domain.entity.Graph; +import lombok.Data; + +@Data +public class ProcessBo { + + private Long appId; + + private String name; + + private String description; + + private Graph graph; + + private YesOrNoEnum defaultUse; + +} diff --git a/src/main/java/com/metis/enums/YesOrNoEnum.java b/src/main/java/com/metis/enums/YesOrNoEnum.java new file mode 100644 index 0000000..1dc6859 --- /dev/null +++ b/src/main/java/com/metis/enums/YesOrNoEnum.java @@ -0,0 +1,52 @@ +package com.metis.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Optional; + +/** + * 基础状态枚举 + * + * @author ZhangQiang + * @date 2024/10/22 + */ +@Getter +@AllArgsConstructor +public enum YesOrNoEnum implements BaseEnum { + + /** + * 基础状态枚举 + */ + YES(1, "是"), + NO(0, "否"), + ; + + @JsonValue + private final Integer code; + private final String name; + + /** + * 根据 code 转换枚举 + * + * @param code 编码 + * @return 枚举 + */ + public static Optional of(Integer code) { + return Optional.ofNullable(BaseEnum.parseByCode(YesOrNoEnum.class, code)); + } + + /** + * 枚举序列化器(前端传code时自动转换为对应枚举) + * + * @param code 编码 + * @return 枚举 + */ + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static YesOrNoEnum get(Integer code) { + return BaseEnum.parseByCode(YesOrNoEnum.class, code); + } + +} diff --git a/src/main/java/com/metis/facade/ProcessDefinitionFacade.java b/src/main/java/com/metis/facade/ProcessDefinitionFacade.java new file mode 100644 index 0000000..89b3f7a --- /dev/null +++ b/src/main/java/com/metis/facade/ProcessDefinitionFacade.java @@ -0,0 +1,49 @@ +package com.metis.facade; + +import com.metis.domain.bo.ProcessBo; +import com.metis.flow.domain.entity.App; +import com.metis.flow.domain.entity.CreateApp; +import com.metis.flow.domain.entity.UpdateApp; +import com.metis.flow.engine.AppEngineService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class ProcessDefinitionFacade { + + private final AppEngineService appEngineService; + + /** + * 创建 + * + * @param processBo 过程业务对象 + */ + public void create(ProcessBo processBo) { + CreateApp createApp = CreateApp.builder() + .name(processBo.getName()) + .graph(processBo.getGraph()) + .build(); + App app = appEngineService.create(createApp); + } + + public App getByDeploymentId(Long deploymentId) { + return appEngineService.getByDeploymentId(deploymentId); + } + + public void update(ProcessBo processBo) { + appEngineService.update(UpdateApp.builder() + .defaultUse(processBo.getDefaultUse()) + .appId(processBo.getAppId()) + .name(processBo.getName()) + .graph(processBo.getGraph()) + .build()); + + } + + public void delete(Long appId) { + appEngineService.delete(appId); + } +} diff --git a/src/main/java/com/metis/flow/config/FlowMybatisPlusConfiguration.java b/src/main/java/com/metis/flow/config/FlowMybatisPlusConfiguration.java new file mode 100644 index 0000000..77d35d6 --- /dev/null +++ b/src/main/java/com/metis/flow/config/FlowMybatisPlusConfiguration.java @@ -0,0 +1,9 @@ +package com.metis.flow.config; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScan(basePackages = {"com.metis.flow.mapper"}) +public class FlowMybatisPlusConfiguration { +} diff --git a/src/main/java/com/metis/flow/constant/BaseConstant.java b/src/main/java/com/metis/flow/constant/BaseConstant.java new file mode 100644 index 0000000..7e0011a --- /dev/null +++ b/src/main/java/com/metis/flow/constant/BaseConstant.java @@ -0,0 +1,6 @@ +package com.metis.flow.constant; + +public interface BaseConstant { + + Integer DEFAULT_VERSION = 0; +} diff --git a/src/main/java/com/metis/flow/convert/BaseAppConvert.java b/src/main/java/com/metis/flow/convert/BaseAppConvert.java new file mode 100644 index 0000000..1caf0cf --- /dev/null +++ b/src/main/java/com/metis/flow/convert/BaseAppConvert.java @@ -0,0 +1,73 @@ +package com.metis.flow.convert; + +import com.metis.flow.domain.entity.*; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface BaseAppConvert { + + BaseAppConvert INSTANCE = Mappers.getMapper(BaseAppConvert.class); + + + /** + * 到应用程序 + * + * @param buildApp 基础应用 + * @return {@link App } + */ + App toApp(BuildApp buildApp); + + /** + * 到应用程序 + * + * @param baseApp 基础应用 + * @return {@link App } + */ + @Mappings({ + @Mapping(target = "graph", expression = "java(com.alibaba.fastjson2.JSON.parseObject(baseApp.getGraphJson(), com.metis.flow.domain.entity.Graph.class))"), + @Mapping(target = "deploymentId", source = "id") + }) + App toApp(BaseApp baseApp); + + /** + * 到基础应用程序 + * + * @param buildApp 构建应用程序 + * @return {@link BaseApp } + */ + @Mappings({ + @Mapping(target = "graphJson", expression = "java(com.alibaba.fastjson2.JSON.toJSONString(buildApp.getGraph()))") + }) + BaseApp toBaseApp(BuildApp buildApp); + + + /** + * 应用 + * + * @param baseApps 基础应用 + * @return {@link List }<{@link App }> + */ + List toApps(List baseApps); + + /** + * 来构建应用程序 + * + * @param createApp 创建应用程序 + * @return {@link BuildApp } + */ + BuildApp toBuildApp(CreateApp createApp); + + /** + * 来构建应用程序 + * + * @param updateApp 更新应用程序 + * @return {@link BuildApp } + */ + BuildApp toBuildApp(UpdateApp updateApp); + +} diff --git a/src/main/java/com/metis/flow/domain/AppQuery.java b/src/main/java/com/metis/flow/domain/AppQuery.java new file mode 100644 index 0000000..814715e --- /dev/null +++ b/src/main/java/com/metis/flow/domain/AppQuery.java @@ -0,0 +1,16 @@ +package com.metis.flow.domain; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class AppQuery { + + private Long appId; + + private String name; + + private String description; + +} diff --git a/src/main/java/com/metis/flow/domain/entity/App.java b/src/main/java/com/metis/flow/domain/entity/App.java new file mode 100644 index 0000000..1d1d37c --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/App.java @@ -0,0 +1,52 @@ +package com.metis.flow.domain.entity; + + +import com.metis.enums.YesOrNoEnum; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class App { + + /** + * 主键 + */ + private Long id; + + /** + * 部署id + */ + private Long deploymentId; + + /** + * 名称 + */ + private String name; + + /** + * 描述 + */ + private String description; + + /** + * 图 + */ + private Graph graph; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 版本 + */ + private Integer version; + + /** + * 默认使用 + */ + private YesOrNoEnum defaultUse; + +} diff --git a/src/main/java/com/metis/flow/domain/entity/BaseApp.java b/src/main/java/com/metis/flow/domain/entity/BaseApp.java new file mode 100644 index 0000000..48e9521 --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/BaseApp.java @@ -0,0 +1,69 @@ +package com.metis.flow.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.metis.domain.SimpleBaseEntity; +import com.metis.enums.YesOrNoEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 基础应用 + * + * @author clay + * @date 2025/04/05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName(value = "base_app") +public class BaseApp extends SimpleBaseEntity { + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 应用程序id + */ + @TableField(value = "app_id") + private Long appId; + + /** + * app名称 + */ + @TableField(value = "name") + private String name; + + /** + * 描述 + */ + @TableField(value = "description") + private String description; + + /** + * 图json数据 + */ + @TableField(value = "graph_json") + private String graphJson; + + /** + * 版本号 + */ + @TableField(value = "version") + private Integer version; + + /** + * 创建人id + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 默认使用 + */ + private YesOrNoEnum defaultUse; + + +} \ No newline at end of file diff --git a/src/main/java/com/metis/flow/domain/entity/BuildApp.java b/src/main/java/com/metis/flow/domain/entity/BuildApp.java new file mode 100644 index 0000000..0df70b2 --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/BuildApp.java @@ -0,0 +1,33 @@ +package com.metis.flow.domain.entity; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public final class BuildApp { + + private Long appId; + /** + * 用户id + */ + private Long userId; + + /** + * 名字 + */ + @NotBlank(message = "流程名称不能为空") + private String name; + + @NotNull(message = "流程模型不能为空") + @Valid + private Graph graph; + + /** + * 描述 + */ + private String description; +} diff --git a/src/main/java/com/metis/flow/domain/entity/CreateApp.java b/src/main/java/com/metis/flow/domain/entity/CreateApp.java new file mode 100644 index 0000000..54bac7f --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/CreateApp.java @@ -0,0 +1,31 @@ +package com.metis.flow.domain.entity; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class CreateApp { + /** + * 用户id + */ + private Long userId; + + /** + * 名字 + */ + @NotBlank(message = "流程名称不能为空") + private String name; + + @NotNull(message = "流程模型不能为空") + @Valid + private Graph graph; + + /** + * 描述 + */ + private String description; +} diff --git a/src/main/java/com/metis/flow/domain/entity/Graph.java b/src/main/java/com/metis/flow/domain/entity/Graph.java new file mode 100644 index 0000000..3915236 --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/Graph.java @@ -0,0 +1,29 @@ +package com.metis.flow.domain.entity; + +import com.metis.flow.domain.entity.base.Edge; +import com.metis.flow.domain.entity.base.Node; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.List; + +@Data +public class Graph { + + /** + * 边缘 + */ + @Valid + @NotNull(message = "连线不能为空") + private List edges; + + /** + * 节点 + */ + @Valid + @NotNull(message = "节点不能为空") + @Size(min = 1, message = "节点不能为空") + private List nodes; +} diff --git a/src/main/java/com/metis/flow/domain/entity/UpdateApp.java b/src/main/java/com/metis/flow/domain/entity/UpdateApp.java new file mode 100644 index 0000000..8391e9b --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/UpdateApp.java @@ -0,0 +1,35 @@ +package com.metis.flow.domain.entity; + +import com.metis.enums.YesOrNoEnum; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class UpdateApp { + + /** + * id + */ + private Long appId; + + /** + * 名字 + */ + @NotBlank(message = "流程名称不能为空") + private String name; + + @NotNull(message = "流程模型不能为空") + @Valid + private Graph graph; + + /** + * 描述 + */ + private String description; + + private YesOrNoEnum defaultUse; +} diff --git a/src/main/java/com/metis/flow/domain/entity/base/Edge.java b/src/main/java/com/metis/flow/domain/entity/base/Edge.java new file mode 100644 index 0000000..ce657d1 --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/base/Edge.java @@ -0,0 +1,67 @@ +package com.metis.flow.domain.entity.base; + +import com.metis.flow.enums.EdgeType; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class Edge { + + /** + * 唯一标识符 + */ + @NotBlank(message = "唯一标识符不能为空") + private String id; + + /** + * 标签 + */ + private String label; + + /** + * 节点类型 + */ + @NotNull(message = "线类型不能为空") + private EdgeType type; + + /** + * 源节点ID,对应节点id + */ + @NotBlank(message = "源节点ID不能为空") + private String source; + + /** + * 目标节点ID,对应节点id + */ + @NotBlank(message = "目标节点ID不能为空") + private String target; + /** + * 源句柄id + */ + @NotBlank(message = "源句柄ID不能为空") + private String sourceHandle; + + /** + * 目标句柄id + */ + @NotBlank(message = "目标句柄ID不能为空") + private String targetHandle; + + /** + * 边是否动画true/false + */ + private Boolean animated; + + /** + * 开始标志 + */ + private String markerStart; + + /** + * 结束标记 + */ + private String markerEnd; + + +} diff --git a/src/main/java/com/metis/flow/domain/entity/base/Handle.java b/src/main/java/com/metis/flow/domain/entity/base/Handle.java new file mode 100644 index 0000000..f49dda3 --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/base/Handle.java @@ -0,0 +1,37 @@ +package com.metis.flow.domain.entity.base; + +import com.metis.flow.enums.PositionType; +import com.metis.flow.enums.HandleType; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 句柄对象 + */ +@Data +public class Handle { + /** + * 句柄id + */ + @NotBlank(message = "句柄id不能为空") + private String id; + + /** + * 句柄类型 + */ + @NotNull(message = "句柄类型不能为空") + private HandleType type; + + /** + * 句柄位置 + */ + @NotNull(message = "句柄位置不能为空") + private PositionType position; + + /** + * 是否可以连接 + */ + @NotNull(message = "是否可以连接不能为空") + private Boolean connectable; +} diff --git a/src/main/java/com/metis/flow/domain/entity/base/Node.java b/src/main/java/com/metis/flow/domain/entity/base/Node.java new file mode 100644 index 0000000..b753588 --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/base/Node.java @@ -0,0 +1,51 @@ +package com.metis.flow.domain.entity.base; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.metis.flow.enums.NodeType; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.Map; + +@Data +public class Node { + + /** + * id + */ + @NotBlank(message = "节点id不能为空") + private String id; + + /** + * 类型 + */ + @NotNull(message = "节点类型不能为空") + private NodeType type; + + /** + * 位置 + */ + @Valid + @NotNull(message = "节点位置不能为空") + private Position position; + + /** + * 业务数据 + */ + @Valid + @NotNull(message = "节点业务数据不能为空") + private NodeData data; + + + @JsonIgnore + public Map getHandleMap() { + if (data == null || data.getHandles() == null) { + return Map.of(); + } + return data.getHandles().stream().collect(java.util.stream.Collectors.toMap(Handle::getId, handle -> handle)); + } + + +} diff --git a/src/main/java/com/metis/flow/domain/entity/base/NodeData.java b/src/main/java/com/metis/flow/domain/entity/base/NodeData.java new file mode 100644 index 0000000..5592325 --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/base/NodeData.java @@ -0,0 +1,43 @@ +package com.metis.flow.domain.entity.base; + +import com.metis.flow.enums.PositionType; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.List; + +@Data +public class NodeData { + + /** + * 标签 + */ + private String label; + + /** + * 图标 + */ + private String icon; + + /** + * 工具栏位置 + */ + private PositionType toolbarPosition; + + /** + * 配置 + */ + private T config; + + /** + * 句柄列表 + */ + @Valid + @NotNull(message = "句柄列表不能为空") + @Size(min = 1, message = "句柄列表不能为空") + private List handles; + + +} diff --git a/src/main/java/com/metis/flow/domain/entity/base/Position.java b/src/main/java/com/metis/flow/domain/entity/base/Position.java new file mode 100644 index 0000000..291cf55 --- /dev/null +++ b/src/main/java/com/metis/flow/domain/entity/base/Position.java @@ -0,0 +1,20 @@ +package com.metis.flow.domain.entity.base; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class Position { + /** + * x坐标 + */ + @NotNull(message = "x坐标不能为空") + private Double x; + + /** + * y坐标 + */ + @NotNull(message = "y坐标不能为空") + private Double y; + +} diff --git a/src/main/java/com/metis/flow/domain/package-info.java b/src/main/java/com/metis/flow/domain/package-info.java new file mode 100644 index 0000000..4b40eac --- /dev/null +++ b/src/main/java/com/metis/flow/domain/package-info.java @@ -0,0 +1 @@ +package com.metis.flow.domain; \ No newline at end of file diff --git a/src/main/java/com/metis/flow/engine/AppEngineService.java b/src/main/java/com/metis/flow/engine/AppEngineService.java new file mode 100644 index 0000000..dfc4c27 --- /dev/null +++ b/src/main/java/com/metis/flow/engine/AppEngineService.java @@ -0,0 +1,79 @@ +package com.metis.flow.engine; + +import com.metis.flow.domain.AppQuery; +import com.metis.flow.domain.entity.App; +import com.metis.flow.domain.entity.CreateApp; +import com.metis.flow.domain.entity.UpdateApp; + +import java.util.List; + +public interface AppEngineService { + + /** + * 列表页面 + * + * @param query 查询 + * @return {@link List }<{@link App }> + */ + List listPage(AppQuery query); + + /** + * 列表 + * + * @param query 查询 + * @return {@link List }<{@link App }> + */ + List list(AppQuery query); + + + /** + * 按身份证领取 + * + * @param appId id + * @return {@link App } + */ + App getByAppId(Long appId, Integer version); + + /** + * 通过部署id获取 + * + * @param deploymentId 部署id + * @return {@link App } + */ + App getByDeploymentId(Long deploymentId); + + /** + * 按id列表 + * + * @param appIds id + * @return {@link List }<{@link App }> + */ + List listByAppIds(List appIds); + + + /** + * 创建 + * + * @param createApp 应用程序 + * @return {@link App } + */ + App create(CreateApp createApp); + + + /** + * 更新 + * + * @param updateApp 应用程序 + * @return {@link App } + */ + App update(UpdateApp updateApp); + + /** + * 删除 + * + * @param appId id + */ + void delete(Long appId); + + +} diff --git a/src/main/java/com/metis/flow/engine/impl/AppEngineServiceImpl.java b/src/main/java/com/metis/flow/engine/impl/AppEngineServiceImpl.java new file mode 100644 index 0000000..66d6af5 --- /dev/null +++ b/src/main/java/com/metis/flow/engine/impl/AppEngineServiceImpl.java @@ -0,0 +1,148 @@ +package com.metis.flow.engine.impl; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import com.metis.enums.YesOrNoEnum; +import com.metis.flow.constant.BaseConstant; +import com.metis.flow.convert.BaseAppConvert; +import com.metis.flow.domain.AppQuery; +import com.metis.flow.domain.entity.*; +import com.metis.flow.engine.AppEngineService; +import com.metis.flow.service.BaseAppService; +import com.metis.flow.validator.ValidatorService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Slf4j +@Service +@RequiredArgsConstructor +public class AppEngineServiceImpl implements AppEngineService { + + private final BaseAppService baseAppService; + private final ValidatorService validatorService; + + + @Override + public List listPage(AppQuery query) { + List list = baseAppService.listPage(query); + return BaseAppConvert.INSTANCE.toApps(list); + } + + @Override + public List list(AppQuery query) { + List list = baseAppService.listQuery(query); + return BaseAppConvert.INSTANCE.toApps(list); + } + + @Override + public App getByAppId(Long appId, Integer version) { + BaseApp baseApp = baseAppService.getByAppIdAndVersion(appId, version); + return BaseAppConvert.INSTANCE.toApp(baseApp); + } + + @Override + public App getByDeploymentId(Long deploymentId) { + BaseApp baseApp = baseAppService.getById(deploymentId); + return BaseAppConvert.INSTANCE.toApp(baseApp); + } + + @Override + public List listByAppIds(List appIds) { + List baseApps = baseAppService.listByAppIds(appIds); + return BaseAppConvert.INSTANCE.toApps(baseApps); + } + + @Override + public App create(CreateApp createApp) { + BuildApp buildApp = BaseAppConvert.INSTANCE.toBuildApp(createApp); + // 校验 + validatorService.validate(buildApp); + // 构建保存对象 + BaseApp baseApp = creatBaseApp(buildApp); + // 保存 + boolean save = baseAppService.save(baseApp); + Assert.isTrue(save, "保存失败"); + return creatApp(baseApp, buildApp); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public synchronized App update(UpdateApp updateApp) { + BaseApp entity = baseAppService.getByAppId(updateApp.getAppId()); + Assert.isTrue(ObjectUtil.isNotNull(entity), "app不存在"); + BuildApp buildApp = BaseAppConvert.INSTANCE.toBuildApp(updateApp); + // 校验 + validatorService.validate(buildApp); + // 构建保存对象 + BaseApp baseApp = updateBaseApp(buildApp); + if (ObjectUtil.isNotNull(updateApp.getDefaultUse()) && YesOrNoEnum.YES.equals(updateApp.getDefaultUse())) { + baseApp.setDefaultUse(YesOrNoEnum.YES); + baseAppService.updateDefaultUseByAppId(updateApp.getAppId(), YesOrNoEnum.NO); + } else { + baseApp.setDefaultUse(YesOrNoEnum.NO); + } + baseApp.setVersion(entity.getVersion() + 1); + // 保存 + boolean save = baseAppService.save(baseApp); + Assert.isTrue(save, "更新失败"); + return creatApp(baseApp, buildApp); + } + + @Override + public void delete(Long appId) { + baseAppService.removeByAppId(appId); + } + + + /** + * 创建应用程序 + * + * @param baseApp 基础应用 + * @param buildApp 构建应用程序 + * @return {@link App } + */ + private App creatApp(BaseApp baseApp, BuildApp buildApp) { + App app = BaseAppConvert.INSTANCE.toApp(buildApp); + app.setId(baseApp.getId()); + app.setDeploymentId(baseApp.getId()); + app.setDefaultUse(baseApp.getDefaultUse()); + return app; + } + + + /** + * 创建应用程序 + * + * @param buildApp 应用程序 + * @return {@link BaseApp } + */ + private BaseApp creatBaseApp(BuildApp buildApp) { + BaseApp baseApp = BaseAppConvert.INSTANCE.toBaseApp(buildApp); + long id = IdUtil.getSnowflakeNextId(); + baseApp.setAppId(id); + baseApp.setId(id); + baseApp.setVersion(BaseConstant.DEFAULT_VERSION); + baseApp.setDefaultUse(YesOrNoEnum.YES); + return baseApp; + } + + + /** + * 更新基础应用程序 + * + * @param buildApp 构建应用程序 + * @return {@link BaseApp } + */ + private BaseApp updateBaseApp(BuildApp buildApp) { + BaseApp baseApp = BaseAppConvert.INSTANCE.toBaseApp(buildApp); + long id = IdUtil.getSnowflakeNextId(); + baseApp.setId(id); + return baseApp; + } + +} diff --git a/src/main/java/com/metis/flow/enums/EdgeType.java b/src/main/java/com/metis/flow/enums/EdgeType.java new file mode 100644 index 0000000..4113c13 --- /dev/null +++ b/src/main/java/com/metis/flow/enums/EdgeType.java @@ -0,0 +1,41 @@ +package com.metis.flow.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum EdgeType { + + DEFAULT(1, "default", "默认线"), + + ; + + + private final Integer code; + + @JsonValue + private final String value; + + private final String name; + + + /** + * 枚举序列化器(前端传code时自动转换为对应枚举) + * + * @param value 值 + * @return 枚举 + */ + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static EdgeType get(String value) { + return Arrays.stream(EdgeType.class.getEnumConstants()) + .filter(e -> e.getValue().equals(value)) + .findFirst() + .orElse(null); + } + +} diff --git a/src/main/java/com/metis/flow/enums/HandleType.java b/src/main/java/com/metis/flow/enums/HandleType.java new file mode 100644 index 0000000..37dc51e --- /dev/null +++ b/src/main/java/com/metis/flow/enums/HandleType.java @@ -0,0 +1,41 @@ +package com.metis.flow.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum HandleType { + SOURCE(1, "source", "源节点"), + TARGET(2, "target", "目标节点"), + ; + + + private final Integer code; + + @JsonValue + private final String value; + + private final String name; + + + /** + * 枚举序列化器(前端传code时自动转换为对应枚举) + * + * @param value 值 + * @return 枚举 + */ + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static HandleType get(String value) { + return Arrays.stream(HandleType.class.getEnumConstants()) + .filter(e -> e.getValue().equals(value)) + .findFirst() + .orElse(null); + } + + +} diff --git a/src/main/java/com/metis/flow/enums/NodeType.java b/src/main/java/com/metis/flow/enums/NodeType.java new file mode 100644 index 0000000..ed3195c --- /dev/null +++ b/src/main/java/com/metis/flow/enums/NodeType.java @@ -0,0 +1,43 @@ +package com.metis.flow.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum NodeType { + + START(1, "start", "开始"), + END(2, "end", "结束"), + + ; + + + private final Integer code; + + @JsonValue + private final String value; + + private final String name; + + + /** + * 枚举序列化器(前端传code时自动转换为对应枚举) + * + * @param value 值 + * @return 枚举 + */ + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static NodeType get(String value) { + return Arrays.stream(NodeType.class.getEnumConstants()) + .filter(e -> e.getValue().equals(value)) + .findFirst() + .orElse(null); + } + + +} diff --git a/src/main/java/com/metis/flow/enums/PositionType.java b/src/main/java/com/metis/flow/enums/PositionType.java new file mode 100644 index 0000000..98eb1d0 --- /dev/null +++ b/src/main/java/com/metis/flow/enums/PositionType.java @@ -0,0 +1,49 @@ +package com.metis.flow.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 句柄位置类型 + * + * @author clay + * @date 2025/04/05 + */ +@Getter +@AllArgsConstructor +public enum PositionType { + + LEFT(1, "left", "左"), + RIGHT(2, "right", "右"), + TOP(3, "top", "上"), + BOTTOM(4, "bottom", "下"); + + + private final Integer code; + + @JsonValue + private final String value; + + private final String name; + + + /** + * 枚举序列化器(前端传code时自动转换为对应枚举) + * + * @param value 值 + * @return 枚举 + */ + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static PositionType get(String value) { + return Arrays.stream(PositionType.class.getEnumConstants()) + .filter(e -> e.getValue().equals(value)) + .findFirst() + .orElse(null); + } + + +} diff --git a/src/main/java/com/metis/flow/mapper/BaseAppMapper.java b/src/main/java/com/metis/flow/mapper/BaseAppMapper.java new file mode 100644 index 0000000..cb09b20 --- /dev/null +++ b/src/main/java/com/metis/flow/mapper/BaseAppMapper.java @@ -0,0 +1,20 @@ +package com.metis.flow.mapper; + +import com.metis.flow.domain.entity.BaseApp; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 基础应用映射器 + * + * @author 18209 + * @date 2025/04/05 + */ +@Mapper +public interface BaseAppMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/metis/flow/package-info.java b/src/main/java/com/metis/flow/package-info.java new file mode 100644 index 0000000..cea1222 --- /dev/null +++ b/src/main/java/com/metis/flow/package-info.java @@ -0,0 +1 @@ +package com.metis.flow; \ No newline at end of file diff --git a/src/main/java/com/metis/flow/service/BaseAppService.java b/src/main/java/com/metis/flow/service/BaseAppService.java new file mode 100644 index 0000000..0357d25 --- /dev/null +++ b/src/main/java/com/metis/flow/service/BaseAppService.java @@ -0,0 +1,77 @@ +package com.metis.flow.service; + +import com.metis.enums.YesOrNoEnum; +import com.metis.flow.domain.AppQuery; +import com.metis.flow.domain.entity.BaseApp; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** + * 基础应用服务 + * + * @author 18209 + * @date 2025/04/05 + */ +public interface BaseAppService extends IService { + + + /** + * 通过应用id获取 + * + * @param appId 应用程序id + * @return {@link BaseApp } + */ + BaseApp getByAppId(Long appId); + + + /** + * 通过id和版本获取 + * + * @param appId id + * @param version 版本 + * @return {@link BaseApp } + */ + BaseApp getByAppIdAndVersion(Long appId, Integer version); + + /** + * 列表页面 + * + * @param query 查询 + * @return {@link List }<{@link BaseApp }> + */ + List listPage(AppQuery query); + + /** + * 列表查询 + * + * @param query 查询 + * @return {@link List }<{@link BaseApp }> + */ + List listQuery(AppQuery query); + + /** + * 应用id列表 + * + * @param appIds 应用程序id + * @return {@link List }<{@link BaseApp }> + */ + List listByAppIds(List appIds); + + /** + * 按应用id删除 + * + * @param appId 应用程序id + * @return int + */ + int removeByAppId(Long appId); + + /** + * 更新默认使用 + * + * @param appId 应用程序id + * @param yesOrNoEnum 是或否enum + * @return int + */ + boolean updateDefaultUseByAppId(Long appId, YesOrNoEnum yesOrNoEnum); +} diff --git a/src/main/java/com/metis/flow/service/impl/BaseAppServiceImpl.java b/src/main/java/com/metis/flow/service/impl/BaseAppServiceImpl.java new file mode 100644 index 0000000..a568544 --- /dev/null +++ b/src/main/java/com/metis/flow/service/impl/BaseAppServiceImpl.java @@ -0,0 +1,109 @@ +package com.metis.flow.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.metis.enums.YesOrNoEnum; +import com.metis.flow.domain.AppQuery; +import com.metis.flow.domain.entity.BaseApp; +import com.metis.flow.mapper.BaseAppMapper; +import com.metis.flow.service.BaseAppService; +import com.metis.utils.PageConditionUtil; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 基础应用服务impl + * + * @author 18209 + * @date 2025/04/05 + */ +@Service +public class BaseAppServiceImpl extends ServiceImpl + implements BaseAppService { + + @Override + public BaseApp getByAppId(Long appId) { + return this.lambdaQuery() + .eq(BaseApp::getAppId, appId) + .orderByDesc(BaseApp::getVersion) + .last("limit 1") + .one(); + } + + + @Override + public BaseApp getByAppIdAndVersion(Long appId, Integer version) { + return this.lambdaQuery() + .eq(BaseApp::getId, appId) + .eq(BaseApp::getVersion, version) + .last("limit 1") + .one(); + } + + @Override + public List listPage(AppQuery query) { + IPage page = PageConditionUtil.getPage(); + LambdaQueryWrapper wrapper = buildQuery(query); + return baseMapper.selectList(page, wrapper); + } + + + @Override + public List listQuery(AppQuery query) { + LambdaQueryWrapper wrapper = buildQuery(query); + return baseMapper.selectList(wrapper); + } + + @Override + public List listByAppIds(List appIds) { + return this.lambdaQuery() + .in(BaseApp::getAppId, appIds) + .eq(BaseApp::getDefaultUse, YesOrNoEnum.YES) + .list(); + } + + + @Override + public int removeByAppId(Long appId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(BaseApp::getAppId, appId); + return baseMapper.delete(wrapper); + } + + @Override + public boolean updateDefaultUseByAppId(Long appId, YesOrNoEnum yesOrNoEnum) { + return this.lambdaUpdate() + .eq(BaseApp::getAppId, appId) + .set(BaseApp::getDefaultUse, yesOrNoEnum) + .update(); + } + + /** + * 构建查询 + * + * @param query 查询 + * @return {@link LambdaQueryWrapper }<{@link BaseApp }> + */ + public LambdaQueryWrapper buildQuery(AppQuery query) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.select(BaseApp::getId, BaseApp::getAppId, BaseApp::getName, + BaseApp::getDescription, BaseApp::getVersion, BaseApp::getIsDeleted, + BaseApp::getCreateTime, BaseApp::getUpdateTime) + .like(StrUtil.isNotBlank(query.getName()), BaseApp::getName, query.getName()) + .like(StrUtil.isNotBlank(query.getDescription()), BaseApp::getDescription, query.getDescription()); + if (ObjectUtil.isNotNull(query.getAppId())) { + wrapper.eq(BaseApp::getAppId, query.getAppId()); + } else { + wrapper.eq(BaseApp::getDefaultUse, YesOrNoEnum.YES); + } + return wrapper; + } +} + + + + diff --git a/src/main/java/com/metis/flow/validator/EdgeValidator.java b/src/main/java/com/metis/flow/validator/EdgeValidator.java new file mode 100644 index 0000000..a02d1e2 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/EdgeValidator.java @@ -0,0 +1,24 @@ +package com.metis.flow.validator; + +import com.metis.flow.domain.entity.base.Edge; +import com.metis.flow.enums.EdgeType; + +public interface EdgeValidator { + + + /** + * 线验证 + * + * @param edge 线 + * @return {@link ValidatorResult } + */ + ValidatorResult validate(Edge edge); + + + /** + * 得到类型 + * + * @return {@link EdgeType } + */ + EdgeType getType(); +} diff --git a/src/main/java/com/metis/flow/validator/NodeValidator.java b/src/main/java/com/metis/flow/validator/NodeValidator.java new file mode 100644 index 0000000..1e4bb92 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/NodeValidator.java @@ -0,0 +1,25 @@ +package com.metis.flow.validator; + +import com.metis.flow.domain.entity.base.Node; +import com.metis.flow.enums.NodeType; + +public interface NodeValidator { + + + /** + * 节点验证 + * + * @param node 节点 + * @return {@link ValidatorResult } + */ + ValidatorResult validate(Node node); + + + /** + * 得到类型 + * + * @return {@link NodeType } + */ + NodeType getType(); + +} diff --git a/src/main/java/com/metis/flow/validator/ValidatorInitialize.java b/src/main/java/com/metis/flow/validator/ValidatorInitialize.java new file mode 100644 index 0000000..7201eb7 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/ValidatorInitialize.java @@ -0,0 +1,34 @@ +package com.metis.flow.validator; + + +import com.metis.flow.validator.factory.EdgeValidatorFactory; +import com.metis.flow.validator.factory.NodeValidatorFactory; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +public class ValidatorInitialize implements ApplicationContextAware { + + + @Override + public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException { + Map edgeMap = applicationContext.getBeansOfType(EdgeValidator.class); + + edgeMap.forEach((k, v) -> { + EdgeValidatorFactory.register(v); + }); + + + Map nodeMap = applicationContext.getBeansOfType(NodeValidator.class); + nodeMap.forEach((k, v) -> { + NodeValidatorFactory.register(v); + }); + } + + +} diff --git a/src/main/java/com/metis/flow/validator/ValidatorResult.java b/src/main/java/com/metis/flow/validator/ValidatorResult.java new file mode 100644 index 0000000..8666b6e --- /dev/null +++ b/src/main/java/com/metis/flow/validator/ValidatorResult.java @@ -0,0 +1,25 @@ +package com.metis.flow.validator; + +import lombok.Data; + +@Data +public final class ValidatorResult { + + private final Boolean valid; + + private final String message; + + private ValidatorResult(Boolean valid, String message) { + this.valid = valid; + this.message = message; + } + + public static ValidatorResult valid() { + return new ValidatorResult(true, ""); + } + + public static ValidatorResult invalid(String message) { + return new ValidatorResult(false, message); + } + +} diff --git a/src/main/java/com/metis/flow/validator/ValidatorService.java b/src/main/java/com/metis/flow/validator/ValidatorService.java new file mode 100644 index 0000000..36350f3 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/ValidatorService.java @@ -0,0 +1,16 @@ +package com.metis.flow.validator; + +import com.metis.flow.domain.entity.BuildApp; + +public interface ValidatorService { + + + /** + * 验证 + * + * @param graph 流程信息 + */ + void validate(BuildApp graph); + + +} diff --git a/src/main/java/com/metis/flow/validator/factory/EdgeValidatorFactory.java b/src/main/java/com/metis/flow/validator/factory/EdgeValidatorFactory.java new file mode 100644 index 0000000..1324401 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/factory/EdgeValidatorFactory.java @@ -0,0 +1,42 @@ +package com.metis.flow.validator.factory; + +import com.metis.flow.enums.EdgeType; +import com.metis.flow.validator.EdgeValidator; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class EdgeValidatorFactory implements ApplicationContextAware { + + private static final Map MAP = new ConcurrentHashMap<>(8); + + /** + * 注册 + * + * @param validator 验证器 + */ + public static void register(EdgeValidator validator) { + MAP.put(validator.getType(), validator); + } + + /** + * 得到 + * + * @param type 类型 + * @return {@link EdgeValidator } + */ + public static EdgeValidator get(EdgeType type) { + return MAP.get(type); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Map validatorMap = applicationContext.getBeansOfType(EdgeValidator.class); + validatorMap.forEach((k, v) -> { + register(v); + }); + } +} diff --git a/src/main/java/com/metis/flow/validator/factory/NodeValidatorFactory.java b/src/main/java/com/metis/flow/validator/factory/NodeValidatorFactory.java new file mode 100644 index 0000000..67a07f2 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/factory/NodeValidatorFactory.java @@ -0,0 +1,34 @@ +package com.metis.flow.validator.factory; + +import com.metis.flow.enums.NodeType; +import com.metis.flow.validator.NodeValidator; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +public class NodeValidatorFactory { + + private static final Map> MAP = new ConcurrentHashMap<>(8); + + /** + * 注册 + * + * @param validator 验证器 + */ + public static void register(NodeValidator validator) { + MAP.put(validator.getType(), validator); + } + + /** + * 得到 + * + * @param type 类型 + * @return {@link NodeValidator }<{@link T }> + */ + public static NodeValidator get(NodeType type) { + return (NodeValidator) MAP.get(type); + } + + +} diff --git a/src/main/java/com/metis/flow/validator/impl/ValidatorServiceImpl.java b/src/main/java/com/metis/flow/validator/impl/ValidatorServiceImpl.java new file mode 100644 index 0000000..3d5395b --- /dev/null +++ b/src/main/java/com/metis/flow/validator/impl/ValidatorServiceImpl.java @@ -0,0 +1,111 @@ +package com.metis.flow.validator.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjectUtil; +import com.metis.flow.domain.entity.BuildApp; +import com.metis.flow.domain.entity.Graph; +import com.metis.flow.domain.entity.base.Edge; +import com.metis.flow.domain.entity.base.Node; +import com.metis.flow.enums.EdgeType; +import com.metis.flow.enums.NodeType; +import com.metis.flow.validator.EdgeValidator; +import com.metis.flow.validator.NodeValidator; +import com.metis.flow.validator.ValidatorResult; +import com.metis.flow.validator.ValidatorService; +import com.metis.flow.validator.factory.EdgeValidatorFactory; +import com.metis.flow.validator.factory.NodeValidatorFactory; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validator; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@Slf4j +@Service +@RequiredArgsConstructor +public class ValidatorServiceImpl implements ValidatorService { + + private final Validator globalValidator; + + @Override + public void validate(BuildApp graph) { + // validation 编程式校验 + Set> validates = globalValidator.validate(graph); + if (CollUtil.isNotEmpty(validates)) { + List errorMessage = validates.stream() + .map(ConstraintViolation::getMessage).toList(); + throw new RuntimeException(String.join(",", errorMessage)); + } + + Graph model = graph.getGraph(); + // 节点参数校验 + validateNode(model.getNodes()); + // 线参数校验 + validateEdge(model.getEdges()); + // 关系验证 + validateRelation(model.getNodes(), model.getEdges()); + } + + + /** + * 验证节点 + * + * @param nodes 节点 + */ + private void validateNode(List nodes) { + List errorMessage = new ArrayList<>(); + for (Node node : nodes) { + NodeType type = node.getType(); + NodeValidator validator = NodeValidatorFactory.get(type); + // 节点校验器 + Assert.isTrue(ObjectUtil.isNotNull(validator), "无:{}类型的节点校验器", type.getName()); + ValidatorResult result = validator.validate(node); + // 返回值检查 + Assert.isTrue(ObjectUtil.isNotNull(result), "类型:{} 的校验器无返回值", validator.getType().getName()); + if (!result.getValid()) { + errorMessage.add(result.getMessage()); + } + } + Assert.isTrue(CollUtil.isEmpty(errorMessage), String.join(",", errorMessage)); + } + + + /** + * 验证边缘 + * + * @param edges + */ + private void validateEdge(List edges) { + List errorMessage = new ArrayList<>(); + for (Edge edge : edges) { + EdgeType type = edge.getType(); + EdgeValidator validator = EdgeValidatorFactory.get(type); + // 节点校验器 + Assert.isTrue(ObjectUtil.isNotNull(validator), "无:{}类型的边校验器", type.getName()); + ValidatorResult result = validator.validate(edge); + // 返回值检查 + Assert.isTrue(ObjectUtil.isNotNull(result), "类型:{} 的校验器无返回值", validator.getType().getName()); + if (!result.getValid()) { + errorMessage.add(result.getMessage()); + } + } + Assert.isTrue(CollUtil.isEmpty(errorMessage), String.join(",", errorMessage)); + } + + + /** + * 验证关系 + * + * @param nodes 节点 + * @param edges 边缘 + */ + private void validateRelation(List nodes, List edges) { + + } + +} diff --git a/src/main/java/com/metis/flow/validator/impl/edge/DefaultEdgeValidator.java b/src/main/java/com/metis/flow/validator/impl/edge/DefaultEdgeValidator.java new file mode 100644 index 0000000..3012647 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/impl/edge/DefaultEdgeValidator.java @@ -0,0 +1,22 @@ +package com.metis.flow.validator.impl.edge; + +import com.metis.flow.domain.entity.base.Edge; +import com.metis.flow.enums.EdgeType; +import com.metis.flow.validator.EdgeValidator; +import com.metis.flow.validator.ValidatorResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class DefaultEdgeValidator implements EdgeValidator { + @Override + public ValidatorResult validate(Edge edge) { + return ValidatorResult.valid(); + } + + @Override + public EdgeType getType() { + return EdgeType.DEFAULT; + } +} diff --git a/src/main/java/com/metis/flow/validator/impl/node/EndNodeValidator.java b/src/main/java/com/metis/flow/validator/impl/node/EndNodeValidator.java new file mode 100644 index 0000000..1a3b501 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/impl/node/EndNodeValidator.java @@ -0,0 +1,23 @@ +package com.metis.flow.validator.impl.node; + +import com.metis.flow.domain.entity.base.Node; +import com.metis.flow.enums.NodeType; +import com.metis.flow.validator.NodeValidator; +import com.metis.flow.validator.ValidatorResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class EndNodeValidator implements NodeValidator { + + @Override + public ValidatorResult validate(Node node) { + return ValidatorResult.valid(); + } + + @Override + public NodeType getType() { + return NodeType.END; + } +} diff --git a/src/main/java/com/metis/flow/validator/impl/node/StartNodeValidator.java b/src/main/java/com/metis/flow/validator/impl/node/StartNodeValidator.java new file mode 100644 index 0000000..f5dba81 --- /dev/null +++ b/src/main/java/com/metis/flow/validator/impl/node/StartNodeValidator.java @@ -0,0 +1,24 @@ +package com.metis.flow.validator.impl.node; + +import com.metis.flow.domain.entity.base.Node; +import com.metis.flow.enums.NodeType; +import com.metis.flow.validator.NodeValidator; +import com.metis.flow.validator.ValidatorResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +public class StartNodeValidator implements NodeValidator { + + @Override + public ValidatorResult validate(Node node) { + return ValidatorResult.valid(); + } + + @Override + public NodeType getType() { + return NodeType.START; + } + +} diff --git a/src/main/java/com/metis/mybatis/MybatisPlusConfiguration.java b/src/main/java/com/metis/mybatis/MybatisPlusConfiguration.java index 7530f83..c71e6b6 100644 --- a/src/main/java/com/metis/mybatis/MybatisPlusConfiguration.java +++ b/src/main/java/com/metis/mybatis/MybatisPlusConfiguration.java @@ -1,9 +1,6 @@ package com.metis.mybatis; -import cn.hutool.core.net.NetUtil; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; -import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; -import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; import com.baomidou.mybatisplus.core.injector.ISqlInjector; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; @@ -37,7 +34,7 @@ public class MybatisPlusConfiguration { paginationInnerInterceptor.setOverflow(false); interceptor.addInnerInterceptor(paginationInnerInterceptor); // 乐观锁插件 - interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor()); + interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 添加防止全表更新与删除插件 interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor()); return interceptor; @@ -51,13 +48,6 @@ public class MybatisPlusConfiguration { return new BaseEntityMetaObjectHandler(); } - /** - * 乐观锁插件 - */ - public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { - return new OptimisticLockerInnerInterceptor(); - } - /** * 自定义SQL注入器 * @@ -69,14 +59,6 @@ public class MybatisPlusConfiguration { } - /** - * 使用网卡信息绑定雪花生成器,实现集群生成id不重复 - */ - @Bean - public IdentifierGenerator idGenerator() { - return new DefaultIdentifierGenerator(NetUtil.getLocalhost()); - } - } diff --git a/src/main/java/com/metis/sseclient/check/SseCheck.java b/src/main/java/com/metis/sseclient/check/SseCheck.java index 4d45e89..6f1c495 100644 --- a/src/main/java/com/metis/sseclient/check/SseCheck.java +++ b/src/main/java/com/metis/sseclient/check/SseCheck.java @@ -35,7 +35,7 @@ public class SseCheck { private final OkHttpClient client; private EventSource eventSource; private final String clientVersion = "1.0"; - private final String clientName = "metis"; + private final String clientName = "langchain4j"; private final String protocolVersion = "2024-11-05"; @@ -99,9 +99,10 @@ public class SseCheck { return; } final Request finalInitializationNotification = initializationNotification; - execute(httpRequest, operationId) + CompletableFuture future = execute(httpRequest, operationId) .thenCompose(originalResponse -> execute(finalInitializationNotification, null) .thenCompose(nullNode -> CompletableFuture.completedFuture(originalResponse))); + JsonNode jsonNode = future.get(); // log.debug("MCP server capabilities: {}", capabilities.get("result")); } catch (Exception e) { throw new RuntimeException(e); @@ -152,6 +153,13 @@ public class SseCheck { private CompletableFuture execute(Request request, Long id) { CompletableFuture future = new CompletableFuture<>(); + try { + Response execute = client.newCall(request).execute(); + + System.out.println(execute); + } catch (IOException e) { + throw new RuntimeException(e); + } client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 7b52eda..4dd0d19 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -1,10 +1,10 @@ # Spring配置 spring: datasource: + driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://frp.feashow.cn:39306/metis?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: yyz@2024 - driver-class-name: com.mysql.cj.jdbc.Driver data: redis: host: frp.feashow.cn diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index a469978..4f78bf9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,4 +4,28 @@ server: spring: application: - name: metis \ No newline at end of file + name: metis + profiles: + active: dev + +# MyBatis Plus 配置 +mybatis-plus: + global-config: + # 关闭MP3.0自带的banner + banner: false + db-config: + #主键类型 0:"数据库ID自增", 1:"不操作", 2:"用户输入ID",3:"数字型snowflake", 4:"全局唯一ID UUID", 5:"字符串型snowflake"; + id-type: 3 + #字段策略 + insert-strategy: not_null + update-strategy: not_null + select-strategy: not_null + #驼峰下划线转换 + table-underline: true + logic-delete-field: is_deleted # 全局逻辑删除字段名 + logic-delete-value: 1 # 逻辑已删除值 + logic-not-delete-value: 0 # 逻辑未删除值 + configuration: + map-underscore-to-camel-case: true + cache-enabled: false + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl \ No newline at end of file diff --git a/src/test/java/SSeTest.java b/src/test/java/SSeTest.java index 1a34d62..63f3d19 100644 --- a/src/test/java/SSeTest.java +++ b/src/test/java/SSeTest.java @@ -1,6 +1,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.metis.sseclient.check.SseCheck; import dev.langchain4j.agent.tool.ToolSpecification; +import dev.langchain4j.mcp.client.DefaultMcpClient; +import dev.langchain4j.mcp.client.transport.McpTransport; +import dev.langchain4j.mcp.client.transport.http.HttpMcpTransport; import lombok.extern.slf4j.Slf4j; import java.util.List; @@ -9,6 +12,14 @@ import java.util.List; @Slf4j public class SSeTest { public static void main(String[] args) throws JsonProcessingException { + McpTransport transport = new HttpMcpTransport.Builder() + .sseUrl("http://localhost:8081/sse") + .build(); + new DefaultMcpClient.Builder() + .transport(transport) + .build() + .listTools(); + SseCheck sseCheck = new SseCheck("http://localhost:8081/sse"); List listTools = sseCheck.listTools(); System.out.println(listTools);