成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Activiti6通過(guò)監(jiān)聽(tīng)修改實(shí)體id、springboot集成配置

Taste / 2464人閱讀

摘要:當(dāng)一個(gè)根級(jí)的結(jié)束時(shí),就會(huì)進(jìn)行上述的緩存對(duì)象統(tǒng)一的持久化。解決的辦法也很簡(jiǎn)單,改為監(jiān)聽(tīng),判斷是否時(shí)需要修改的任務(wù)實(shí)體即可。這樣后面要進(jìn)行駁回時(shí),只要通過(guò)這樣關(guān)系表,馬上就可以定位到要駁回到的任務(wù)了。

1.前言

本文內(nèi)容主要為以下兩點(diǎn),因?yàn)閮?nèi)容有交叉,所以會(huì)放在一起介紹。

1.以自由跳轉(zhuǎn)為基礎(chǔ)實(shí)現(xiàn)不改變?cè)热蝿?wù)id的駁回
關(guān)于Activiti6動(dòng)態(tài)跳轉(zhuǎn)可以查看我的另一篇文章Activiti6實(shí)現(xiàn)自由跳轉(zhuǎn)

2.java類(lèi)方式進(jìn)行Activiti6配置、spring boot集成
因?yàn)橛幸恍┳远x的需求,如流程字體、自動(dòng)部署、自定義監(jiān)聽(tīng)器等,直接引入[activit-spring-boot]又沒(méi)有必要,所以參考activit6源碼中[activit-spring-boot]模塊的代碼完成。

2.實(shí)現(xiàn)介紹

關(guān)于自由跳轉(zhuǎn)的內(nèi)容我就不再多說(shuō),主要介紹如何修改Activiti生成的實(shí)體的id,以達(dá)到駁回時(shí)重新生成的任務(wù)id與原先的任務(wù)id一致。(某些業(yè)務(wù)場(chǎng)景下可能會(huì)用到,例如某流程中A環(huán)節(jié)提交的表單與task id綁定,當(dāng)環(huán)節(jié)提交又被駁回時(shí),為保證表單內(nèi)容與任務(wù)關(guān)系不變,駁回后的任務(wù)id與原先任務(wù)id要一致)

2.1前提知識(shí)

1.Activiti持久化實(shí)體的過(guò)程時(shí)先創(chuàng)建實(shí)體對(duì)象,記錄到緩存中,在完成執(zhí)行后統(tǒng)一進(jìn)行緩存對(duì)象的持久化,并清空緩存。

2.Activiti采用命令模式執(zhí)行操作,所有操作都時(shí)一個(gè)CMD。執(zhí)行一個(gè)CMD的時(shí)候會(huì)創(chuàng)建一個(gè)上下文環(huán)境,包含待持久化的實(shí)體緩存等,如果在CMD中嵌套執(zhí)行CMD,新的CMD默認(rèn)會(huì)使用上級(jí)上下文環(huán)境。當(dāng)一個(gè)根級(jí)的CMD結(jié)束時(shí),Activiti就會(huì)進(jìn)行上述的緩存對(duì)象統(tǒng)一的持久化。

3.Activiti有豐富的事件類(lèi)型(具體可以查看事件枚舉類(lèi)ActivitiEventType)供我們實(shí)現(xiàn)相應(yīng)監(jiān)聽(tīng)器,進(jìn)行特殊業(yè)務(wù)處理。例如ENTITY_CREATED——實(shí)體創(chuàng)建完成(task、activity、Execution等所有實(shí)體)、TASK_CREATED——任務(wù)創(chuàng)建完成(針對(duì)task)、TASK_COMPLETED——任務(wù)完成等等。

2.2關(guān)于修改任務(wù)id

結(jié)合上述內(nèi)容我們就可以知道,只要在TASK_CREATED進(jìn)行監(jiān)聽(tīng),直接在監(jiān)聽(tīng)器中將id改為需要的值即可。理論上是這樣,但是需要注意,Activiti6中歷史任務(wù)實(shí)體創(chuàng)建是在TASK_CREATED之前的,如果你在TASK_CREATED中修改任務(wù)id,實(shí)際上歷史任務(wù)實(shí)體創(chuàng)建時(shí)是獲取不到的,這樣就會(huì)導(dǎo)致歷史任務(wù)的id與運(yùn)行時(shí)任務(wù)id不一致。解決的辦法也很簡(jiǎn)單,改為監(jiān)聽(tīng)ENTITY_CREATED,判斷是否時(shí)需要修改id的任務(wù)實(shí)體即可。

實(shí)現(xiàn)代碼 properties配置文件
# 是否更新數(shù)據(jù)庫(kù)表
spring.activiti.databaseSchemaUpdate=true
# 是否激活異步執(zhí)行器
spring.activiti.asyncExecutorActivate=false
# 流程歷史記錄登錄
spring.activiti.historyLevel=audit
# 是否檢查更新流程定義
spring.activiti.checkProcessDefinitions=false
# 流程定義所在前綴
spring.activiti.processDefinitionLocationPrefix=classpath*:/procDef/
# 流程定義后綴
spring.activiti.processDefinitionLocationSuffixes=**.bpmn
# 部署流程定義時(shí)是否生成圖片
spring.activiti.createDiagramOnDeploy=false
# 字體 下面內(nèi)容為轉(zhuǎn)成unicode的"宋體"
spring.activiti.activityFontName=u5b8bu4f53
spring.activiti.labelFontName=u5b8bu4f53
解析Properties類(lèi)
@ConfigurationProperties("spring.activiti")
public class ActivitiProperties {
    private boolean checkProcessDefinitions = true;
    private boolean asyncExecutorActivate = true;
    private boolean restApiEnabled;
    private String deploymentName;
    private String mailServerHost = "localhost";
    private int mailServerPort = 1025;
    private String mailServerUserName;
    private String mailServerPassword;
    private String mailServerDefaultFrom;
    private boolean mailServerUseSsl;
    private boolean mailServerUseTls;
    private String databaseSchemaUpdate = "true";
    private String databaseSchema;
    private boolean isDbIdentityUsed = true;
    private boolean isDbHistoryUsed = true;
    private HistoryLevel historyLevel = HistoryLevel.AUDIT;
    private String processDefinitionLocationPrefix = "classpath:/processes/";
    private List processDefinitionLocationSuffixes = Arrays.asList("**.bpmn20.xml", "**.bpmn");
    private String restApiMapping = "/api/*";
    private String restApiServletName = "activitiRestApi";
    private boolean jpaEnabled = true; // true by default
    private List customMybatisMappers;
    private List customMybatisXMLMappers;

    private boolean createDiagramOnDeploy;
    private String activityFontName;
    private String labelFontName;
    //省略getter、setter
}
spring boot配置類(lèi)
@Configuration
@EnableConfigurationProperties(ActivitiProperties.class)
public class ActivitiConfig {
    private static final Logger logger = LoggerFactory.getLogger(ActivitiConfig.class);
    @Autowired
    private ActivitiProperties activitiProperties;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private PlatformTransactionManager transactionManager;
    @Autowired
    private TaskCreatedListener taskCreatedListener;
    @Autowired
    private TaskCompletedListener taskCompletedListener;
    @Autowired
    private EntityCreatedListener entityCreatedListener;
    @Autowired
    private ResourcePatternResolver resourceLoader;

    @Bean
    public SpringProcessEngineConfiguration processEngineConfiguration() throws IOException {
        SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
        configuration.setDataSource(dataSource);
        configuration.setTransactionManager(transactionManager);
        configuration.setDatabaseSchemaUpdate(activitiProperties.getDatabaseSchemaUpdate());
        configuration.setAsyncExecutorActivate(activitiProperties.isAsyncExecutorActivate());
        configuration.setHistory(activitiProperties.getHistoryLevel().getKey());
        configuration.setCreateDiagramOnDeploy(activitiProperties.isCreateDiagramOnDeploy());
        configuration.setActivityFontName(activitiProperties.getActivityFontName());
        configuration.setLabelFontName(activitiProperties.getLabelFontName());
        //todo 修改自動(dòng)部署,當(dāng)前自動(dòng)部署直接搬自[activit-spring-boot]
        //如果checkProcessDefinitions為true,則發(fā)布新版流程定義,后續(xù)可能根據(jù)流程定義文件MD5等判斷是否真正變化而進(jìn)行發(fā)布
        List procDefResources = discoverProcessDefinitionResources(activitiProperties.getProcessDefinitionLocationPrefix(),            activitiProperties.getProcessDefinitionLocationSuffixes(),this.activitiProperties.isCheckProcessDefinitions());
        configuration.setDeploymentResources(procDefResources.toArray(new Resource[procDefResources.size()]));
        Map> typedListeners = new HashMap<>();
        typedListeners.put("ENTITY_CREATED", Collections.singletonList(entityCreatedListener));
        typedListeners.put("TASK_CREATED", Collections.singletonList(taskCreatedListener));
        typedListeners.put("TASK_COMPLETED", Collections.singletonList(taskCompletedListener));
        configuration.setTypedEventListeners(typedListeners);
        return configuration;
    }
    private List discoverProcessDefinitionResources(String prefix, List suffixes, boolean checkPDs) throws IOException {
        if (checkPDs) {
            List result = new ArrayList<>();
            for (String suffix : suffixes) {
                String path = prefix + suffix;
                Resource[] resources = resourceLoader.getResources(path);
                if (resources != null && resources.length > 0) {
                    CollectionUtils.mergeArrayIntoCollection(resources, result);
                }
            }
            if (result.isEmpty()) {
                logger.info("No process definitions were found for autodeployment");
            }
            return result;
        }
        return new ArrayList<>();
    }
    @Bean
    public ProcessEngineFactoryBean processEngine() throws IOException {
        ProcessEngineFactoryBean factoryBean = new ProcessEngineFactoryBean();
        factoryBean.setProcessEngineConfiguration(processEngineConfiguration());
        return factoryBean;
    }
    @Bean
    public RuntimeService runtimeService(ProcessEngine processEngine) {
        return processEngine.getRuntimeService();
    }
    @Bean
    public RepositoryService repositoryService(ProcessEngine processEngine) {
        return processEngine.getRepositoryService();
    }
    @Bean
    public TaskService taskService(ProcessEngine processEngine) {
        return processEngine.getTaskService();
    }
    @Bean
    public HistoryService historyService(ProcessEngine processEngine) {
        return processEngine.getHistoryService();
    }
    @Bean
    public ManagementService managementService(ProcessEngine processEngine) {
        return processEngine.getManagementService();
    }
    @Bean
    public IdentityService identityService(ProcessEngine processEngine) {
        return processEngine.getIdentityService();
    }
實(shí)體創(chuàng)建完成監(jiān)聽(tīng)器
@Component
public class EntityCreatedListener implements ActivitiEventListener {
    public void onEvent(ActivitiEvent event){
        Object entity = ((ActivitiEntityEvent)event).getEntity();
        if(entity instanceof TaskEntity){
            TaskEntity taskEntity = (TaskEntity)entity;
            // 這個(gè)要改變的id值,可以在上篇文章中的SetFLowNodeAndGoCmd中設(shè)置相應(yīng)流程變量即可。
            String changeTaskId = (String)taskEntity.getVariable("changeTaskIdVarKey");
            if(!StringUtils.isEmpty(changeTaskId)){
                taskEntity.setId(changeTaskId);
                taskEntity.setVariable("changeTaskIdKey","");
            }
        }
    }
    public boolean isFailOnException(){
        return true;
    }
}
2.3關(guān)于如何獲取當(dāng)前任務(wù)的來(lái)源任務(wù),以進(jìn)行駁回

我們知道Activiti中有TASK_CREATED和TASK_COMPLETED事件,在同一個(gè)流程實(shí)例中,一個(gè)任務(wù)A如果不是最后的結(jié)束任務(wù),那么在它完成后,必定會(huì)有一個(gè)新的任務(wù)B創(chuàng)建,而我們簡(jiǎn)單理解為A為B的來(lái)源任務(wù)。(假設(shè)A是申請(qǐng)任務(wù),B就時(shí)審批任務(wù),B的處理人對(duì)當(dāng)前審批不同意要駁回時(shí),流程就要回退到任務(wù)A。)
這樣一來(lái),我們可以監(jiān)聽(tīng)TASK_COMPLETED,在此時(shí)為流程設(shè)置一個(gè)變量fromTaskId,值為任務(wù)A的id,當(dāng)任務(wù)A的TASK_COMPLETED結(jié)束后,就來(lái)到的了任務(wù)B的TASK_CREATED中,我們此時(shí)從流程變量中獲取fromTaskId,并將次id作為任務(wù)B的來(lái)源id持久化到一張自己創(chuàng)建的任務(wù)關(guān)系表中。這樣后面要進(jìn)行駁回時(shí),只要通過(guò)這樣關(guān)系表,馬上就可以定位到要駁回到的任務(wù)id了。

實(shí)現(xiàn)代碼 任務(wù)完成監(jiān)聽(tīng)器
// 關(guān)于監(jiān)聽(tīng)器的注冊(cè)看上面配置類(lèi)中typedListeners部分已有
@Component
public class TaskCompletedListener implements ActivitiEventListener {
    public void onEvent(ActivitiEvent event){
        TaskEntity taskEntity = (TaskEntity)((ActivitiEntityEvent)event).getEntity();
        taskEntity.setVariable("fromTaskIdVarKey", taskEntity.getId());
    }

    public boolean isFailOnException(){
        return true;
    }
}
任務(wù)創(chuàng)建完成監(jiān)聽(tīng)器
@Component
public class TaskCreatedListener implements ActivitiEventListener {
    public void onEvent(ActivitiEvent event){
        TaskEntity taskEntity = (TaskEntity)((ActivitiEntityEvent)event).getEntity();
        String fromTaskId = (String)taskEntity.getVariable(WfVarKeyConstants.fromTaskId);
        if(StringUtils.isEmpty(fromTaskId)) return;
        xxxTaskInfo info = new xxxTaskInfo();
        info.setId(taskEntity.getId());
        info.setFromId(fromTaskId);
        //此處進(jìn)行任務(wù)關(guān)系持久化,自行實(shí)現(xiàn)
        xxxTaskInfoRepository.save(info);
    }
    public boolean isFailOnException(){
        return true;
    }
}
3.最后

本來(lái)打算做一個(gè)Activiti小貼士列表,不過(guò)看篇幅已經(jīng)很長(zhǎng)了,小貼士好像也湊不齊一篇文章,而且還沒(méi)人看:)
那就放到下次來(lái)說(shuō)
todo
1.Activiti命令執(zhí)行模式
2.持久化過(guò)程與會(huì)話緩存(CRUD)
3.BPMN流程執(zhí)行計(jì)劃

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68932.html

相關(guān)文章

  • Activiti6實(shí)現(xiàn)自由跳轉(zhuǎn)

    摘要:跳轉(zhuǎn)方法當(dāng)前任務(wù)獲取流程定義獲取目標(biāo)節(jié)點(diǎn)定義刪除當(dāng)前運(yùn)行任務(wù)流程執(zhí)行到來(lái)源節(jié)點(diǎn)刪除當(dāng)前運(yùn)行時(shí)任務(wù)命令,并返回當(dāng)前任務(wù)的執(zhí)行對(duì)象這里繼承了,主要時(shí)很多跳轉(zhuǎn)業(yè)務(wù)場(chǎng)景下,要求不能時(shí)掛起任務(wù)。 前言 工作快2年的小白,如有錯(cuò)誤,懇請(qǐng)大家批評(píng)指點(diǎn),這也是開(kāi)始寫(xiě)博客的一個(gè)初衷,能夠在分享互動(dòng)、知識(shí)梳理中進(jìn)步。之前工作的項(xiàng)目使用activiti5進(jìn)行企業(yè)流程系統(tǒng)開(kāi)發(fā),現(xiàn)在這份工作也開(kāi)始需要流程開(kāi)發(fā),...

    tianhang 評(píng)論0 收藏0
  • SpringBoot非官方教程 | 第十一篇:SpringBoot集成swagger2,構(gòu)建優(yōu)雅的R

    摘要:另外很容易構(gòu)建風(fēng)格的,簡(jiǎn)單優(yōu)雅帥氣,正如它的名字。配置一些基本的信息。三寫(xiě)生產(chǎn)文檔的注解通過(guò)注解表明該接口會(huì)生成文檔,包括接口名請(qǐng)求方法參數(shù)返回信息的等等。四參考資料中使用構(gòu)建強(qiáng)大的文檔 swagger,中文拽的意思。它是一個(gè)功能強(qiáng)大的api框架,它的集成非常簡(jiǎn)單,不僅提供了在線文檔的查閱,而且還提供了在線文檔的測(cè)試。另外swagger很容易構(gòu)建restful風(fēng)格的api,簡(jiǎn)單優(yōu)雅帥氣...

    荊兆峰 評(píng)論0 收藏0
  • SpringBoot集成Mybatis 自動(dòng)生成實(shí)體類(lèi)和Mapper

    摘要:優(yōu)化當(dāng)我們?cè)跀?shù)據(jù)庫(kù)中增加字段時(shí),需要在對(duì)應(yīng)的實(shí)體類(lèi)中增加字段,中也需要去增加字段,去維護(hù),會(huì)消耗大量的時(shí)間我們可以讓接口去繼承,刪除接口中的所有方法,因?yàn)橹卸家呀?jīng)實(shí)現(xiàn)了。遇到這里問(wèn)題不會(huì)報(bào)錯(cuò),只要注意打印出來(lái)的語(yǔ)句即可。 SpringBoot集成Mybatis 自動(dòng)生成實(shí)體類(lèi)和Mapper 1.使用IDEA創(chuàng)建一個(gè)空的SpringBoot項(xiàng)目 2.在pom.xml中引入以下配置 ...

    codercao 評(píng)論0 收藏0
  • Activiti6之表結(jié)構(gòu)分析-引擎配置及流程部署

    摘要:如圖流程引擎創(chuàng)建完成后,只會(huì)對(duì)進(jìn)行操作,屬性數(shù)據(jù)表存儲(chǔ)整個(gè)流程引擎級(jí)別的數(shù)據(jù)初始化表結(jié)構(gòu)時(shí),會(huì)默認(rèn)插入四條記錄,流程部署測(cè)試流程部署,先把上面的流程引擎配置的注解改為。如圖資源流程定義數(shù)據(jù)表這里面存放的就是我們部署的資源元數(shù)據(jù)信息。 關(guān)于activiti是什么,我這里就不多說(shuō)了,我們直接上路,O(∩_∩)O哈哈~ 引擎配置 配置方式有好幾種:1): /** * 獲取默認(rèn)的流程引擎實(shí)例...

    xorpay 評(píng)論0 收藏0
  • 第三十章:SpringBoot使用MapStruct自動(dòng)映射DTO

    摘要:商品類(lèi)型實(shí)體恒宇少年碼云商品基本信息實(shí)體恒宇少年碼云接下來(lái)我們繼續(xù)創(chuàng)建相關(guān)的。注解是用于標(biāo)注接口抽象類(lèi)是被自動(dòng)映射的標(biāo)識(shí),只有存在該注解才會(huì)將內(nèi)部的接口方法自動(dòng)實(shí)現(xiàn)。 MapStruct是一種類(lèi)型安全的bean映射類(lèi)生成java注釋處理器。我們要做的就是定義一個(gè)映射器接口,聲明任何必需的映射方法。在編譯的過(guò)程中,MapStruct會(huì)生成此接口的實(shí)現(xiàn)。該實(shí)現(xiàn)使用純java方法調(diào)用的源和目...

    weakish 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<