diff --git a/README.md b/README.md index 303fdff7..35e635f6 100644 --- a/README.md +++ b/README.md @@ -149,9 +149,8 @@ youlai-boot/ │ │ │ └── util/ # 安全工具类 │ │ └── web/ # Web 层(全局异常/跨域/限流) │ ├── module/ # 业务扩展模块 -│ │ ├── config/ # 模块装配(工作流按 flowable.enabled 开关) │ │ ├── form/ # 动态表单 -│ │ └── workflow/ # 工作流(Flowable 审批流) +│ │ └── workflow/ # 工作流 │ ├── support/ # 能力服务 │ │ ├── file/ # 文件存储(RustFS/阿里云OSS/本地) │ │ ├── mail/ # 邮件服务 @@ -215,10 +214,14 @@ youlai-boot/ 2. 在 `application-{profile}.yml` 中开启: ```yaml - flowable: + workflow: enabled: true ``` + Flowable 引擎开关(process / idm / eventregistry)在同一 `application-{profile}.yml` 中以占位符跟随 `workflow.enabled`,无需单独维护。 + + 演示流程的启动自动部署由同文件 `workflow.demo.enabled` 控制(dev/youlai 默认 `true`、prod 默认 `false`,仅在模块开启后生效)。 + **多租户** 需要租户隔离与租户配置,使用独立仓库 [youlai-boot-tenant](https://gitee.com/youlaiorg/youlai-boot-tenant)。 @@ -229,8 +232,23 @@ youlai-boot/ 如需技术支持、商务合作、二次开发、项目定制或私有化部署,可联系作者微信(见下方二维码)。 -| 公众号「有来技术」 |
| 小程序「有来技术」 |
| 添加作者微信 | -| --------- | ------ | --------- | ------ | ------ | -|
|
|
|
|
| + + + + + + + + +
+ 公众号「有来技术」
+ 公众号「有来技术」 +
     + 小程序「有来技术」
+ 小程序「有来技术」 +
     + 添加作者微信
+ 添加作者微信 +

技术交流 · 问题反馈 · 商务合作

diff --git a/pom.xml b/pom.xml index 7bc8cca9..d2dde7f6 100644 --- a/pom.xml +++ b/pom.xml @@ -295,7 +295,7 @@ ${weixin-java-miniapp.version} - + org.flowable flowable-spring-boot-starter-process diff --git a/src/main/java/com/youlai/boot/YouLaiBootApplication.java b/src/main/java/com/youlai/boot/YouLaiBootApplication.java index b5f11c68..1b2761fd 100644 --- a/src/main/java/com/youlai/boot/YouLaiBootApplication.java +++ b/src/main/java/com/youlai/boot/YouLaiBootApplication.java @@ -1,34 +1,17 @@ package com.youlai.boot; import org.springframework.boot.SpringApplication; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.autoconfigure.AutoConfigurationExcludeFilter; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.context.TypeExcludeFilter; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.FilterType; +import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; /** * 应用启动类 * - *

等价于 @SpringBootApplication,但显式声明 @ComponentScan 以排除工作流包, - * 改由 {@link com.youlai.boot.module.config.WorkflowModuleConfig} 按 flowable.enabled 决定是否扫描

- * * @author Ray.Hao * @since 3.0.0 */ -@ConfigurationPropertiesScan @EnableScheduling -@SpringBootConfiguration -@EnableAutoConfiguration -@ComponentScan(basePackages = "com.youlai.boot", excludeFilters = { - // 保留 @SpringBootApplication 默认的排除器 - @ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), - @ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class), - @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com\\.youlai\\.boot\\.module\\.workflow\\..*") -}) +@SpringBootApplication public class YouLaiBootApplication { public static void main(String[] args) { diff --git a/src/main/java/com/youlai/boot/auth/password/config/CaptchaProperties.java b/src/main/java/com/youlai/boot/auth/password/config/CaptchaProperties.java index e1b10c4b..8b0f4681 100644 --- a/src/main/java/com/youlai/boot/auth/password/config/CaptchaProperties.java +++ b/src/main/java/com/youlai/boot/auth/password/config/CaptchaProperties.java @@ -2,6 +2,7 @@ package com.youlai.boot.auth.password.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; /** * 验证码配置属性 @@ -9,6 +10,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Ray.Hao * @since 2023/11/24 */ +@Component @ConfigurationProperties(prefix = "captcha") @Data public class CaptchaProperties { diff --git a/src/main/java/com/youlai/boot/auth/wxma/config/WxMaProperties.java b/src/main/java/com/youlai/boot/auth/wxma/config/WxMaProperties.java index 428c8709..94d330bb 100644 --- a/src/main/java/com/youlai/boot/auth/wxma/config/WxMaProperties.java +++ b/src/main/java/com/youlai/boot/auth/wxma/config/WxMaProperties.java @@ -2,6 +2,7 @@ package com.youlai.boot.auth.wxma.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; /** * 微信小程序配置属性 @@ -9,6 +10,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Ray.Hao */ @Data +@Component @ConfigurationProperties(prefix = "wx.miniapp") public class WxMaProperties { diff --git a/src/main/java/com/youlai/boot/codegen/property/CodegenProperties.java b/src/main/java/com/youlai/boot/codegen/property/CodegenProperties.java index ec229833..ca8bd685 100644 --- a/src/main/java/com/youlai/boot/codegen/property/CodegenProperties.java +++ b/src/main/java/com/youlai/boot/codegen/property/CodegenProperties.java @@ -4,6 +4,7 @@ import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.map.MapUtil; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; @@ -14,6 +15,7 @@ import java.util.Map; * @author Ray * @since 2.11.0 */ +@Component @ConfigurationProperties(prefix = "codegen") @Data public class CodegenProperties { diff --git a/src/main/java/com/youlai/boot/config/RedisCacheConfig.java b/src/main/java/com/youlai/boot/config/RedisCacheConfig.java index 9be08f3c..f7665976 100644 --- a/src/main/java/com/youlai/boot/config/RedisCacheConfig.java +++ b/src/main/java/com/youlai/boot/config/RedisCacheConfig.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.serializer.RedisSerializer; @EnableCaching @EnableConfigurationProperties(CacheProperties.class) @Configuration -@ConditionalOnProperty(name = "spring.cache.enabled") // xxl.job.enabled = true 才会自动装配 +@ConditionalOnProperty(name = "spring.cache.enabled") // 未配置视为关闭 public class RedisCacheConfig { /** diff --git a/src/main/java/com/youlai/boot/framework/security/config/SecurityProperties.java b/src/main/java/com/youlai/boot/framework/security/config/SecurityProperties.java index 96337564..a68ebb83 100644 --- a/src/main/java/com/youlai/boot/framework/security/config/SecurityProperties.java +++ b/src/main/java/com/youlai/boot/framework/security/config/SecurityProperties.java @@ -8,6 +8,7 @@ import jakarta.validation.constraints.Pattern; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; +import org.springframework.stereotype.Component; /** * 安全模块配置属性类 @@ -19,6 +20,7 @@ import org.springframework.validation.annotation.Validated; */ @Data @Validated +@Component @ConfigurationProperties(prefix = "security") public class SecurityProperties { diff --git a/src/main/java/com/youlai/boot/framework/web/ratelimit/RateLimitProperties.java b/src/main/java/com/youlai/boot/framework/web/ratelimit/RateLimitProperties.java index a48abc7a..822eda51 100644 --- a/src/main/java/com/youlai/boot/framework/web/ratelimit/RateLimitProperties.java +++ b/src/main/java/com/youlai/boot/framework/web/ratelimit/RateLimitProperties.java @@ -2,6 +2,7 @@ package com.youlai.boot.framework.web.ratelimit; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; import java.time.Duration; @@ -13,6 +14,7 @@ import java.time.Duration; * @since 4.3.1 */ @Data +@Component @ConfigurationProperties(prefix = "rate-limit") public class RateLimitProperties { diff --git a/src/main/java/com/youlai/boot/module/config/WorkflowEnvironmentPostProcessor.java b/src/main/java/com/youlai/boot/module/config/WorkflowEnvironmentPostProcessor.java deleted file mode 100644 index 0abaf945..00000000 --- a/src/main/java/com/youlai/boot/module/config/WorkflowEnvironmentPostProcessor.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.youlai.boot.module.config; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.springframework.boot.EnvironmentPostProcessor; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor; -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.core.Ordered; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.MapPropertySource; - -/** - * 工作流关闭时排除 Flowable 引擎自动配置 - * - * @author Ray.Hao - * @since 4.9.0 - */ -public class WorkflowEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { - - /** 工作流开关属性 */ - private static final String WORKFLOW_ENABLED = "flowable.enabled"; - - /** 自动配置排除列表属性 */ - private static final String AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude"; - - /** Flowable 引擎相关的自动配置类 */ - private static final List FLOWABLE_AUTOCONFIGURATIONS = List.of( - "org.flowable.spring.boot.ProcessEngineAutoConfiguration", - "org.flowable.spring.boot.ProcessEngineServicesAutoConfiguration" - ); - - @Override - public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - // 与 WorkflowModuleConfig 的条件一致:未配置视为关闭 - if ("true".equalsIgnoreCase(environment.getProperty(WORKFLOW_ENABLED))) { - return; - } - // 合并已有的排除项,避免覆盖用户自己的 spring.autoconfigure.exclude - List excluded = new ArrayList<>(Binder.get(environment) - .bind(AUTOCONFIGURE_EXCLUDE, Bindable.listOf(String.class)) - .orElseGet(List::of)); - for (String className : FLOWABLE_AUTOCONFIGURATIONS) { - if (!excluded.contains(className)) { - excluded.add(className); - } - } - Map properties = new HashMap<>(); - properties.put(AUTOCONFIGURE_EXCLUDE, String.join(",", excluded)); - environment.getPropertySources().addFirst(new MapPropertySource("workflowDisabled", properties)); - } - - /** - * 晚于 ConfigDataEnvironmentPostProcessor 执行,保证 profile 配置文件已加载 - */ - @Override - public int getOrder() { - return ConfigDataEnvironmentPostProcessor.ORDER + 1; - } -} diff --git a/src/main/java/com/youlai/boot/module/config/WorkflowModuleConfig.java b/src/main/java/com/youlai/boot/module/config/WorkflowModuleConfig.java deleted file mode 100644 index d28c306d..00000000 --- a/src/main/java/com/youlai/boot/module/config/WorkflowModuleConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.youlai.boot.module.config; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -/** - * 工作流模块装配 - * - *

仅当 flowable.enabled 为 true 时扫描工作流包,未配置视为关闭

- * - * @author Ray.Hao - * @since 4.9.0 - */ -@Configuration -@ConditionalOnProperty(name = "flowable.enabled", havingValue = "true") -@ComponentScan(basePackages = "com.youlai.boot.module.workflow") -public class WorkflowModuleConfig { -} diff --git a/src/main/java/com/youlai/boot/module/form/service/FormDataService.java b/src/main/java/com/youlai/boot/module/form/service/FormDataService.java index b1f40ecf..ded2e9c6 100644 --- a/src/main/java/com/youlai/boot/module/form/service/FormDataService.java +++ b/src/main/java/com/youlai/boot/module/form/service/FormDataService.java @@ -70,9 +70,6 @@ public interface FormDataService { /** * 按表单标识删除全部提交数据(演示数据重置用) * - *

跨模块窄接口:formKey 到 formId 的解析与删除条件封装在 form 模块内部, - * 调用方(workflow)不感知表单实体与查询条件

- * * @param formKey 表单唯一标识 */ void removeByFormKey(String formKey); diff --git a/src/main/java/com/youlai/boot/module/form/service/impl/FormDataServiceImpl.java b/src/main/java/com/youlai/boot/module/form/service/impl/FormDataServiceImpl.java index 40778ab4..753904df 100644 --- a/src/main/java/com/youlai/boot/module/form/service/impl/FormDataServiceImpl.java +++ b/src/main/java/com/youlai/boot/module/form/service/impl/FormDataServiceImpl.java @@ -88,7 +88,6 @@ public class FormDataServiceImpl extends ServiceImpl i @Override public boolean savePublicFormData(String formKey, Map data, String ip) { FormDefinition form = formDefinitionService.getByFormKey(formKey); - // 公开访问总闸:未开启公开或未发布的表单拿 key 也提交不了 if (!FormStatusEnum.PUBLISHED.getValue().equals(form.getStatus()) || !Integer.valueOf(1).equals(form.getIsPublic())) { throw new BusinessException("表单不存在或未开放公开访问"); @@ -218,8 +217,6 @@ public class FormDataServiceImpl extends ServiceImpl i /** * 按表单标识删除全部提交数据(演示数据重置用) * - *

formKey 到 formId 的解析与删除条件封装在本模块内部,跨模块调用方不感知表单实体与查询条件

- * * @param formKey 表单唯一标识 */ @Override diff --git a/src/main/java/com/youlai/boot/module/form/service/impl/FormDefinitionServiceImpl.java b/src/main/java/com/youlai/boot/module/form/service/impl/FormDefinitionServiceImpl.java index b31f645c..e63d56b5 100644 --- a/src/main/java/com/youlai/boot/module/form/service/impl/FormDefinitionServiceImpl.java +++ b/src/main/java/com/youlai/boot/module/form/service/impl/FormDefinitionServiceImpl.java @@ -229,7 +229,6 @@ public class FormDefinitionServiceImpl extends ServiceImpl() - .eq(Menu::getRouteName, "FormCenter") + // 目录类型保存时 routeName 被置空,按名称+类型回查 + Menu createdCatalog = menuService.getOne(new LambdaQueryWrapper() + .eq(Menu::getName, DEFAULT_CATALOG_NAME) + .eq(Menu::getType, MenuTypeEnum.CATALOG.getValue()) .last("LIMIT 1") ); + Assert.notNull(createdCatalog, "默认目录创建失败"); + return createdCatalog; } /** diff --git a/src/main/java/com/youlai/boot/module/workflow/config/ConditionalOnWorkflowEnabled.java b/src/main/java/com/youlai/boot/module/workflow/config/ConditionalOnWorkflowEnabled.java new file mode 100644 index 00000000..5c5c4557 --- /dev/null +++ b/src/main/java/com/youlai/boot/module/workflow/config/ConditionalOnWorkflowEnabled.java @@ -0,0 +1,24 @@ +package com.youlai.boot.module.workflow.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; + +/** + * 工作流启用条件 + * + *

workflow.enabled 显式为 true 时生效,未配置视为关闭

+ * + * @author Ray.Hao + * @since 4.9.0 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@ConditionalOnBooleanProperty(prefix = "workflow", name = "enabled") +public @interface ConditionalOnWorkflowEnabled { +} diff --git a/src/main/java/com/youlai/boot/module/workflow/config/WorkflowEngineConfig.java b/src/main/java/com/youlai/boot/module/workflow/config/WorkflowEngineConfig.java index 6575ac66..0ea29e1f 100644 --- a/src/main/java/com/youlai/boot/module/workflow/config/WorkflowEngineConfig.java +++ b/src/main/java/com/youlai/boot/module/workflow/config/WorkflowEngineConfig.java @@ -16,6 +16,7 @@ import java.util.List; * @author Ray.Hao * @since 4.9.0 */ +@ConditionalOnWorkflowEnabled @Configuration(proxyBeanMethods = false) public class WorkflowEngineConfig { diff --git a/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowDefinitionController.java b/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowDefinitionController.java index a44163ba..04c102c0 100644 --- a/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowDefinitionController.java +++ b/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowDefinitionController.java @@ -6,6 +6,7 @@ import com.youlai.boot.module.workflow.model.vo.ModelXmlVO; import com.youlai.boot.module.workflow.model.vo.ProcessStageVO; import com.youlai.boot.module.workflow.model.vo.StartableProcessVO; import com.youlai.boot.module.workflow.service.WorkflowDefinitionService; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -19,12 +20,13 @@ import java.util.List; /** * 流程定义控制层(发布产物:发布后供发起、审批与流程图查看) * - *

定义的发布入口在模型接口(deploy),删除随模型级联,本层不再提供独立分页与删除

+ *

定义的发布在模型接口(deploy),删除随模型级联

* * @author Ray.Hao * @since 4.9.0 */ @Tag(name = "13.工作流定义接口") +@ConditionalOnWorkflowEnabled @RestController @RequestMapping("/api/v1/workflow/definitions") @RequiredArgsConstructor diff --git a/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowInstanceController.java b/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowInstanceController.java index ddc09a38..18603437 100644 --- a/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowInstanceController.java +++ b/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowInstanceController.java @@ -13,6 +13,7 @@ import com.youlai.boot.module.workflow.model.vo.InstanceDetailVO; import com.youlai.boot.module.workflow.model.vo.InstancePageVO; import com.youlai.boot.module.workflow.model.vo.ProcessDiagramVO; import com.youlai.boot.module.workflow.service.WorkflowInstanceService; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -28,6 +29,7 @@ import org.springframework.web.bind.annotation.*; * @since 4.9.0 */ @Tag(name = "13.工作流实例接口") +@ConditionalOnWorkflowEnabled @RestController @RequestMapping("/api/v1/workflow/instances") @RequiredArgsConstructor diff --git a/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowModelController.java b/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowModelController.java index 0d1448af..0d09af76 100644 --- a/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowModelController.java +++ b/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowModelController.java @@ -14,6 +14,7 @@ import com.youlai.boot.module.workflow.model.vo.ModelVO; import com.youlai.boot.module.workflow.model.vo.ModelXmlVO; import com.youlai.boot.module.workflow.service.WorkflowDemoService; import com.youlai.boot.module.workflow.service.WorkflowModelService; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -31,6 +32,7 @@ import java.util.Arrays; * @since 4.9.0 */ @Tag(name = "13.工作流模型接口") +@ConditionalOnWorkflowEnabled @RestController @RequestMapping("/api/v1/workflow/models") @RequiredArgsConstructor diff --git a/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowTaskController.java b/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowTaskController.java index ed29fa28..68b3d893 100644 --- a/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowTaskController.java +++ b/src/main/java/com/youlai/boot/module/workflow/controller/WorkflowTaskController.java @@ -15,6 +15,7 @@ import com.youlai.boot.module.workflow.model.vo.RejectTargetVO; import com.youlai.boot.module.workflow.model.vo.TaskDetailVO; import com.youlai.boot.module.workflow.model.vo.TodoTaskVO; import com.youlai.boot.module.workflow.service.WorkflowTaskService; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -33,6 +34,7 @@ import java.util.List; * @since 4.9.0 */ @Tag(name = "13.工作流任务接口") +@ConditionalOnWorkflowEnabled @RestController @RequestMapping("/api/v1/workflow/tasks") @RequiredArgsConstructor diff --git a/src/main/java/com/youlai/boot/module/workflow/handler/ProcessCompletedHandler.java b/src/main/java/com/youlai/boot/module/workflow/handler/ProcessCompletedHandler.java index 1d916e1e..26605844 100644 --- a/src/main/java/com/youlai/boot/module/workflow/handler/ProcessCompletedHandler.java +++ b/src/main/java/com/youlai/boot/module/workflow/handler/ProcessCompletedHandler.java @@ -4,8 +4,7 @@ package com.youlai.boot.module.workflow.handler; * 流程审批通过后的业务处理器(扩展点) * *

一个流程定义 Key 对应一个处理器,由 ProcessCompletedListener 统一路由; - * 新增"审批通过后处理"(如报销入账、采购入库、离职禁用账号)只需实现本接口并注册为 Spring Bean, - * 无需改动审批与引擎代码

+ * 新增"审批通过后处理"(如报销入账、采购入库、离职禁用账号)只需实现本接口并注册为 Spring Bean

* * @author Ray.Hao * @since 4.9.0 diff --git a/src/main/java/com/youlai/boot/module/workflow/handler/expense/ExpenseProcessCompletedHandler.java b/src/main/java/com/youlai/boot/module/workflow/handler/expense/ExpenseProcessCompletedHandler.java index 75684459..5edcaa46 100644 --- a/src/main/java/com/youlai/boot/module/workflow/handler/expense/ExpenseProcessCompletedHandler.java +++ b/src/main/java/com/youlai/boot/module/workflow/handler/expense/ExpenseProcessCompletedHandler.java @@ -5,6 +5,7 @@ import com.youlai.boot.module.form.model.vo.FormDataVO; import com.youlai.boot.module.form.service.FormDataService; import com.youlai.boot.module.workflow.handler.ProcessCompletedContext; import com.youlai.boot.module.workflow.handler.ProcessCompletedHandler; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -19,6 +20,7 @@ import org.springframework.stereotype.Component; * @since 4.9.0 */ @Slf4j +@ConditionalOnWorkflowEnabled @Component @RequiredArgsConstructor public class ExpenseProcessCompletedHandler implements ProcessCompletedHandler { diff --git a/src/main/java/com/youlai/boot/module/workflow/handler/purchase/PurchaseProcessCompletedHandler.java b/src/main/java/com/youlai/boot/module/workflow/handler/purchase/PurchaseProcessCompletedHandler.java index e87a2ff0..8059cfe7 100644 --- a/src/main/java/com/youlai/boot/module/workflow/handler/purchase/PurchaseProcessCompletedHandler.java +++ b/src/main/java/com/youlai/boot/module/workflow/handler/purchase/PurchaseProcessCompletedHandler.java @@ -5,6 +5,7 @@ import com.youlai.boot.module.form.model.vo.FormDataVO; import com.youlai.boot.module.form.service.FormDataService; import com.youlai.boot.module.workflow.handler.ProcessCompletedContext; import com.youlai.boot.module.workflow.handler.ProcessCompletedHandler; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -19,6 +20,7 @@ import org.springframework.stereotype.Component; * @since 4.9.0 */ @Slf4j +@ConditionalOnWorkflowEnabled @Component @RequiredArgsConstructor public class PurchaseProcessCompletedHandler implements ProcessCompletedHandler { diff --git a/src/main/java/com/youlai/boot/module/workflow/listener/ProcessCompletedListener.java b/src/main/java/com/youlai/boot/module/workflow/listener/ProcessCompletedListener.java index 83ab0230..87cbbe84 100644 --- a/src/main/java/com/youlai/boot/module/workflow/listener/ProcessCompletedListener.java +++ b/src/main/java/com/youlai/boot/module/workflow/listener/ProcessCompletedListener.java @@ -2,6 +2,7 @@ package com.youlai.boot.module.workflow.listener; import com.youlai.boot.module.workflow.handler.ProcessCompletedContext; import com.youlai.boot.module.workflow.handler.ProcessCompletedHandler; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.api.delegate.event.FlowableEngineEvent; import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType; @@ -27,6 +28,7 @@ import java.util.stream.Collectors; * @since 4.9.0 */ @Slf4j +@ConditionalOnWorkflowEnabled @Component public class ProcessCompletedListener implements FlowableEventListener { diff --git a/src/main/java/com/youlai/boot/module/workflow/runner/WorkflowDemoInitializer.java b/src/main/java/com/youlai/boot/module/workflow/runner/WorkflowDemoInitializer.java index 62229515..c38120c3 100644 --- a/src/main/java/com/youlai/boot/module/workflow/runner/WorkflowDemoInitializer.java +++ b/src/main/java/com/youlai/boot/module/workflow/runner/WorkflowDemoInitializer.java @@ -1,6 +1,7 @@ package com.youlai.boot.module.workflow.runner; import com.youlai.boot.module.workflow.service.WorkflowDemoService; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; @@ -11,13 +12,14 @@ import org.springframework.stereotype.Component; * 演示流程启动初始化器 * *

委托 {@link WorkflowDemoService} 幂等初始化,重置能力由管理端接口提供。 - * 由 flowable.demo.enabled 控制(默认开启),生产环境置 false 后本组件不注册,启动零开销

+ * 由 workflow.demo.enabled 控制(默认关闭),置 true 后启动时初始化演示流程

* * @author Ray.Hao * @since 4.9.0 */ +@ConditionalOnWorkflowEnabled @Component -@ConditionalOnProperty(name = "flowable.demo.enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnProperty(name = "workflow.demo.enabled", havingValue = "true") @RequiredArgsConstructor public class WorkflowDemoInitializer implements ApplicationRunner { diff --git a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowDefinitionServiceImpl.java b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowDefinitionServiceImpl.java index 91aa2fde..f27ed613 100644 --- a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowDefinitionServiceImpl.java +++ b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowDefinitionServiceImpl.java @@ -15,6 +15,7 @@ import com.youlai.boot.system.model.entity.UserRole; import com.youlai.boot.system.service.RoleService; import com.youlai.boot.system.service.UserService; import com.youlai.boot.system.service.UserRoleService; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.ProcessDefinition; @@ -34,6 +35,7 @@ import java.util.stream.Collectors; * @author Ray.Hao * @since 4.9.0 */ +@ConditionalOnWorkflowEnabled @Service @RequiredArgsConstructor public class WorkflowDefinitionServiceImpl implements WorkflowDefinitionService { diff --git a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowDemoServiceImpl.java b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowDemoServiceImpl.java index bf875623..22d2e77b 100644 --- a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowDemoServiceImpl.java +++ b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowDemoServiceImpl.java @@ -5,8 +5,8 @@ import cn.hutool.json.JSONUtil; import com.youlai.boot.common.exception.BusinessException; import com.youlai.boot.module.form.service.FormDataService; import com.youlai.boot.module.workflow.service.WorkflowDemoService; -import com.youlai.boot.module.workflow.service.WorkflowDemoService; import com.youlai.boot.module.workflow.util.BpmnModelHelper; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.RepositoryService; @@ -29,12 +29,12 @@ import java.util.Set; *

初始化按 key 幂等双写:部署流程定义(可发起)+ 创建模型草稿(流程模型页可见),两者各自查重互不依赖。 * 引擎表(ACT_*)不走 SQL 预置:流程定义跨三表且主键由引擎生成,直接写库绕过解析校验,重置同理依赖引擎级联删除

* - *

重置为工作流数据全量恢复出厂:清空所有流程定义、模型、实例、历史(含用户自建)及关联表单提交数据后重建演示流程, - * 供演示环境定期复原,等价于业务脚本"DROP 重建"的数据效果而不动引擎表结构

+ *

重置供演示环境定期复原,数据效果等价业务脚本"DROP 重建",不动引擎表结构

* * @author Ray.Hao * @since 4.9.0 */ +@ConditionalOnWorkflowEnabled @Service @RequiredArgsConstructor @Slf4j @@ -141,7 +141,7 @@ public class WorkflowDemoServiceImpl implements WorkflowDemoService { } /** - * 幂等创建模型草稿(流程模型页数据源),editorSource 与部署 XML 同源,metaInfo 与服务层约定一致 + * 幂等创建模型草稿(流程模型页数据源),editorSource 与部署 XML 同源 */ private void createModelIfAbsent(DemoProcess process, String bpmnXml) { long count = repositoryService.createModelQuery() @@ -160,8 +160,6 @@ public class WorkflowDemoServiceImpl implements WorkflowDemoService { /** * 清理演示表单提交数据(流程 businessKey 指向 form_data,随流程一并复位) - * - *

formKey 到删除条件的解析封装在 form 模块(removeByFormKey 窄接口),本模块不感知表单实体

*/ private void deleteFormData(String formKey) { formDataService.removeByFormKey(formKey); diff --git a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowInstanceServiceImpl.java b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowInstanceServiceImpl.java index c8c3e71c..2949e59e 100644 --- a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowInstanceServiceImpl.java +++ b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowInstanceServiceImpl.java @@ -18,6 +18,7 @@ import com.youlai.boot.module.workflow.service.WorkflowDefinitionService; import com.youlai.boot.module.workflow.service.WorkflowInstanceService; import com.youlai.boot.module.workflow.util.ApprovalHistoryHelper; import com.youlai.boot.module.workflow.util.BpmnModelHelper; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.impl.identity.Authentication; @@ -47,6 +48,7 @@ import java.util.Set; * @since 4.9.0 */ @Slf4j +@ConditionalOnWorkflowEnabled @Service @RequiredArgsConstructor public class WorkflowInstanceServiceImpl implements WorkflowInstanceService { @@ -127,7 +129,7 @@ public class WorkflowInstanceServiceImpl implements WorkflowInstanceService { InstancePageVO pageVO = new InstancePageVO(); pageVO.setId(instance.getId()); pageVO.setProcessDefinitionKey(instance.getProcessDefinitionKey()); - // 实例名优先(发起时可自定义标题区分批次),旧实例 NAME_ 为空则回退流程定义名 + // 实例名优先,NAME_ 为空回退流程定义名 pageVO.setProcessName(StrUtil.isBlank(instance.getName()) ? instance.getProcessDefinitionName() : instance.getName()); pageVO.setBusinessKey(instance.getBusinessKey()); @@ -174,7 +176,7 @@ public class WorkflowInstanceServiceImpl implements WorkflowInstanceService { HistoricProcessInstance instance = getHistoricInstance(instanceId); InstanceDetailVO detailVO = new InstanceDetailVO(); detailVO.setId(instance.getId()); - // 实例名优先(与列表保持一致),旧实例 NAME_ 为空则回退流程定义名 + // 实例名优先,NAME_ 为空回退流程定义名 detailVO.setProcessName(StrUtil.isBlank(instance.getName()) ? instance.getProcessDefinitionName() : instance.getName()); detailVO.setStartUser(instance.getStartUserId()); diff --git a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowModelServiceImpl.java b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowModelServiceImpl.java index 2536becb..790b145f 100644 --- a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowModelServiceImpl.java +++ b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowModelServiceImpl.java @@ -16,6 +16,7 @@ import com.youlai.boot.module.workflow.service.WorkflowModelService; import com.youlai.boot.module.workflow.util.BpmnModelHelper; import com.youlai.boot.system.model.entity.Role; import com.youlai.boot.system.service.RoleService; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.Deployment; @@ -39,6 +40,7 @@ import java.util.stream.Collectors; * @author Ray.Hao * @since 4.9.0 */ +@ConditionalOnWorkflowEnabled @Service @RequiredArgsConstructor public class WorkflowModelServiceImpl implements WorkflowModelService { diff --git a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowTaskServiceImpl.java b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowTaskServiceImpl.java index f501841d..455b8148 100644 --- a/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowTaskServiceImpl.java +++ b/src/main/java/com/youlai/boot/module/workflow/service/impl/WorkflowTaskServiceImpl.java @@ -18,6 +18,7 @@ import com.youlai.boot.module.workflow.service.WorkflowDefinitionService; import com.youlai.boot.module.workflow.service.WorkflowTaskService; import com.youlai.boot.module.workflow.util.ApprovalHistoryHelper; import com.youlai.boot.module.workflow.util.BpmnModelHelper; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flowable.common.engine.impl.identity.Authentication; @@ -52,6 +53,7 @@ import java.util.stream.Collectors; * @since 4.9.0 */ @Slf4j +@ConditionalOnWorkflowEnabled @Service @RequiredArgsConstructor public class WorkflowTaskServiceImpl implements WorkflowTaskService { @@ -94,7 +96,6 @@ public class WorkflowTaskServiceImpl implements WorkflowTaskService { taskVO.setName(task.getName()); taskVO.setProcessInstanceId(task.getProcessInstanceId()); ProcessInstance instance = instances.get(task.getProcessInstanceId()); - // 实例名优先(发起时可自定义标题区分批次),旧实例 NAME_ 为空则回退流程定义名 taskVO.setProcessName(resolveProcessName( instance == null ? null : instance.getName(), processNames.get(task.getProcessDefinitionId()))); @@ -177,7 +178,6 @@ public class WorkflowTaskServiceImpl implements WorkflowTaskService { detailVO.setTaskName(task.getName()); detailVO.setTaskDefinitionKey(task.getTaskDefinitionKey()); detailVO.setProcessInstanceId(task.getProcessInstanceId()); - // 实例名优先(与列表口径一致),旧实例 NAME_ 为空则回退流程定义名 detailVO.setProcessName(resolveProcessName(instance.getName(), instance.getProcessDefinitionName())); detailVO.setTaskFormKey(bpmnModelHelper.getUserTaskFormKey( task.getProcessDefinitionId(), task.getTaskDefinitionKey())); @@ -227,7 +227,6 @@ public class WorkflowTaskServiceImpl implements WorkflowTaskService { public void completeTask(String taskId, CompleteTaskForm formData) { Task task = getCurrentUserTask(taskId); this.addComment(task, formData.getComment()); - // 或签(候选组)任务办理即认领,历史表写入办理人,已办列表可追溯 this.claimIfCandidate(task); taskService.complete(taskId, formData.getVariables() == null ? Map.of() : formData.getVariables()); } diff --git a/src/main/java/com/youlai/boot/module/workflow/util/ApprovalHistoryHelper.java b/src/main/java/com/youlai/boot/module/workflow/util/ApprovalHistoryHelper.java index 5089f55b..ff71f71b 100644 --- a/src/main/java/com/youlai/boot/module/workflow/util/ApprovalHistoryHelper.java +++ b/src/main/java/com/youlai/boot/module/workflow/util/ApprovalHistoryHelper.java @@ -2,6 +2,7 @@ package com.youlai.boot.module.workflow.util; import cn.hutool.core.util.StrUtil; import com.youlai.boot.module.workflow.model.vo.ApprovalHistoryVO; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import org.flowable.engine.HistoryService; import org.flowable.engine.TaskService; @@ -19,6 +20,7 @@ import java.util.stream.Collectors; * @author Ray.Hao * @since 4.9.0 */ +@ConditionalOnWorkflowEnabled @Component @RequiredArgsConstructor public class ApprovalHistoryHelper { diff --git a/src/main/java/com/youlai/boot/module/workflow/util/BpmnModelHelper.java b/src/main/java/com/youlai/boot/module/workflow/util/BpmnModelHelper.java index b3e593e4..4d380c89 100644 --- a/src/main/java/com/youlai/boot/module/workflow/util/BpmnModelHelper.java +++ b/src/main/java/com/youlai/boot/module/workflow/util/BpmnModelHelper.java @@ -3,6 +3,7 @@ package com.youlai.boot.module.workflow.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.youlai.boot.common.exception.BusinessException; +import com.youlai.boot.module.workflow.config.ConditionalOnWorkflowEnabled; import lombok.RequiredArgsConstructor; import org.flowable.bpmn.converter.BpmnXMLConverter; import org.flowable.bpmn.model.BpmnModel; @@ -22,11 +23,12 @@ import java.util.Set; import java.util.stream.Collectors; /** - * BPMN 模型读取辅助类(formKey 与 XML 解析统一收口,避免散落各 Service) + * BPMN 模型读取辅助(formKey 与 XML 解析) * * @author Ray.Hao * @since 4.9.0 */ +@ConditionalOnWorkflowEnabled @Component @RequiredArgsConstructor public class BpmnModelHelper { @@ -34,7 +36,7 @@ public class BpmnModelHelper { private final RepositoryService repositoryService; /** - * 用户任务节点的 BPMN 原始信息(办理人配置由上层翻译为角色/用户展示) + * 用户任务节点的 BPMN 原始信息(办理人为未翻译的原始配置) * * @param nodeId 节点ID * @param nodeName 节点名称 diff --git a/src/main/java/com/youlai/boot/support/file/property/StorageProperties.java b/src/main/java/com/youlai/boot/support/file/property/StorageProperties.java index f130b8c4..26b80f5b 100644 --- a/src/main/java/com/youlai/boot/support/file/property/StorageProperties.java +++ b/src/main/java/com/youlai/boot/support/file/property/StorageProperties.java @@ -2,6 +2,7 @@ package com.youlai.boot.support.file.property; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; import java.util.Collections; import java.util.List; @@ -18,6 +19,7 @@ import java.util.stream.Collectors; * @since 4.8.0 */ @Data +@Component @ConfigurationProperties(prefix = "storage") public class StorageProperties { diff --git a/src/main/java/com/youlai/boot/support/mail/MailProperties.java b/src/main/java/com/youlai/boot/support/mail/MailProperties.java index 0bed75c6..7a535474 100644 --- a/src/main/java/com/youlai/boot/support/mail/MailProperties.java +++ b/src/main/java/com/youlai/boot/support/mail/MailProperties.java @@ -2,6 +2,7 @@ package com.youlai.boot.support.mail; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; /** * 邮件配置属性 @@ -9,6 +10,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * @author Ray * @since 2024/8/17 */ +@Component @ConfigurationProperties(prefix = "spring.mail") @Data public class MailProperties { diff --git a/src/main/java/com/youlai/boot/support/sms/AliyunSmsProperties.java b/src/main/java/com/youlai/boot/support/sms/AliyunSmsProperties.java index 22e6651f..40f58c5c 100644 --- a/src/main/java/com/youlai/boot/support/sms/AliyunSmsProperties.java +++ b/src/main/java/com/youlai/boot/support/sms/AliyunSmsProperties.java @@ -2,6 +2,7 @@ package com.youlai.boot.support.sms; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; import java.util.Map; @@ -12,6 +13,7 @@ import java.util.Map; * @since 2024/8/17 */ @Data +@Component @ConfigurationProperties(prefix = "sms.aliyun") public class AliyunSmsProperties { diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories deleted file mode 100644 index f1851329..00000000 --- a/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,2 +0,0 @@ -org.springframework.boot.EnvironmentPostProcessor=\ - com.youlai.boot.module.config.WorkflowEnvironmentPostProcessor diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 77ba9031..a879b862 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -237,12 +237,21 @@ wx: appid: Your_AppId secret: Your_AppSecret -# 工作流 -flowable: - # 工作流总开关,未配置视为关闭 +# 工作流(默认关闭,开启见 README「可选扩展」) +workflow: + # 工作流模块开关,未配置视为关闭 enabled: false - # 引擎表初始化策略,true 启动时检查并自动建/更新 ACT_* 表;可选 true/false/create/create-drop - database-schema-update: true demo: # 演示流程自动部署开关 enabled: true + +flowable: + # 引擎开关跟随 workflow.enabled + process: + enabled: ${workflow.enabled:false} + idm: + enabled: ${workflow.enabled:false} + eventregistry: + enabled: ${workflow.enabled:false} + # 引擎表初始化策略,true 启动时检查并自动建/更新 ACT_* 表;可选 true/false/create/create-drop + database-schema-update: true diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index bc33bb0e..8006c685 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -236,11 +236,20 @@ wx: secret: Your_AppSecret # 工作流(默认关闭,开启见 README「可选扩展」) -flowable: - # 工作流总开关,未配置视为关闭 +workflow: + # 工作流模块开关,未配置视为关闭 enabled: false - # 引擎表初始化策略,false 要求 ACT_* 表已存在 - database-schema-update: false demo: # 演示流程自动部署开关 enabled: false + +flowable: + # 引擎开关跟随 workflow.enabled + process: + enabled: ${workflow.enabled:false} + idm: + enabled: ${workflow.enabled:false} + eventregistry: + enabled: ${workflow.enabled:false} + # 引擎表初始化策略,false 要求 ACT_* 表已存在 + database-schema-update: false