自定義工作流設(shè)計(jì)

引言

工作偶爾會(huì)遇到需要審批相關(guān)的系統(tǒng),對(duì)于流程步驟相對(duì)固定的,一般會(huì)采取某些第三方的工作流來(lái)做對(duì)應(yīng)的系統(tǒng)。目前唯一用過(guò)的就是activiti工作流。對(duì)它進(jìn)行了簡(jiǎn)單的研究學(xué)習(xí)。參考以前入門的文章,發(fā)現(xiàn)它大概會(huì)生成二十多表,但是很多表基本沒(méi)有使用。由于對(duì)于其源碼沒(méi)有進(jìn)入深層次的研究,所以一旦遇到流程錯(cuò)亂就容易找不到問(wèn)題?;诖?,嘗試寫(xiě)一個(gè)簡(jiǎn)單的關(guān)于自定義流程的設(shè)計(jì),多一個(gè)備選方案。

實(shí)現(xiàn)

1.設(shè)計(jì)基于需求,經(jīng)典圖
image.png

從這張圖我抽出了四個(gè)對(duì)象:事件、節(jié)點(diǎn)、網(wǎng)關(guān)、流程線。
為什么這么抽取對(duì)象???
看前言尋找答案,找不到那就是因?yàn)榻?jīng)驗(yàn)?。?!
為什么一根線走組長(zhǎng)審批了還走經(jīng)理,另外一根線直接走經(jīng)理???
需求如此。。。。

2.貼代碼的時(shí)候到了

2.1.整體目錄設(shè)計(jì)

image.png

2.2.事件類

package com.example.customprocessengine.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Getter
@Setter
public class Event {

    @Id
    private Long id;
    private String eventId;
    private String eventName;
}

2.3.網(wǎng)關(guān)

package com.example.customprocessengine.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Getter
@Setter
public class ExclusiveGateway {

    @Id
    private Long id;
    private String gatewayId;
    private String name;
}

2.4.節(jié)點(diǎn)

package com.example.customprocessengine.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
@Getter
@Setter
public class UserTask {

    @Id
    private Long id;

    private String taskId;

//    private String taskname;

    /*@ElementCollection
    private List<String> username;*/

    @OneToOne
    private Parameter parameter;

    @OneToOne
    PassCondition passCondition;
}

2.5.流程線

package com.example.customprocessengine.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Getter
@Setter
@Entity
public class SequenceFlow {
    @Id
    private Long id;
    private String sourceRef;
    private String targetRef;
    private String conditionExpression;
    @OneToOne
    private Parameter parameter;
}

2.6.延伸重要類-進(jìn)行中的任務(wù)

package com.example.customprocessengine.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.List;

@Entity
@Getter
@Setter
public class Tasking {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private LocalDateTime operateTime;

    private String username;

    /*@OneToOne
    private UserTask userTask;*/

    @OneToOne
    private SequenceFlow sequenceFlow;

    @OneToOne
    private ProcessInstance processInstance;

    @ElementCollection(fetch = FetchType.EAGER)
    List<String> usernames;
}

2.7.延伸重要類-歷史任務(wù)

package com.example.customprocessengine.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@Getter
@Setter
public class TaskHistory {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private LocalDateTime operateTime;

    private String username;

    /*@OneToOne
    private UserTask userTask;*/

    @OneToOne
    private SequenceFlow sequenceFlow;

    @OneToOne
    private ProcessInstance processInstance;

    @OneToOne
    private UserTask userTask;

}

代碼一貼字?jǐn)?shù)瞬間翻兩番

3.對(duì)比流程圖,當(dāng)前設(shè)計(jì)表能否放下頁(yè)面上的東西

tips:所謂工作流,簡(jiǎn)單點(diǎn)就是把規(guī)則定好,存在某個(gè)地方(可以是txt文件,xml文件,或者數(shù)據(jù)庫(kù))

event表
對(duì)應(yīng)標(biāo)紅
task表
對(duì)應(yīng)標(biāo)紅

gateway表
對(duì)應(yīng)標(biāo)紅

SequenceFlow表.png

對(duì)應(yīng)標(biāo)紅

結(jié)論-----》表設(shè)計(jì)基本能放下所有。

4.代碼控制流程

流程服務(wù)類
package com.example.customprocessengine.service;

import java.util.Map;

public interface Customprocessengine {


    Long startProcess(String processKey, Map<String, Object> variavle);

    void completeTask(Long ProcessInstanceId,Map<String, Object> variavle);
}
目前提供兩個(gè)方法:
1.開(kāi)啟流程
2.完成任務(wù)
后續(xù)接口還未完成。

5.單元測(cè)試

  @Test
    @Transactional
    @Rollback(value = false)
    public void test2() {
        Map<String,Object> params = new HashMap<>();
        List<String> zzspr = new ArrayList<>();
        zzspr.add("ysh員工");
        params.put("fqr",zzspr);
        System.out.println(customprocessengine.startProcess("1",params));
    }
// 257 260 263
    @Test
    @Transactional
    @Rollback(value = false)
    public void  tets(){
        Map<String,Object> params = new HashMap<>();
        List<String> zzspr = new ArrayList<>();
        zzspr.add("ysh組長(zhǎng)1");
        zzspr.add("ysh組長(zhǎng)2");
        params.put("zzspr",zzspr);
        params.put("days", 3);
//        params.put("jlspr", "ysh");
        customprocessengine.completeTask(279l,params);
    }

    @Test
    @Transactional
    @Rollback(value = false)
    public void  tets3(){
        Map<String,Object> params = new HashMap<>();
        List<String> zzspr = new ArrayList<>();
        zzspr.add("ysh經(jīng)理");
        params.put("jlspr",zzspr);
        params.put("dealpeople", "ysh組長(zhǎng)1");
//        params.put("days", 3);
//        params.put("jlspr", "ysh");
//        params.put("dealMan")
        customprocessengine.completeTask(279l,params);
    }

    @Test
    @Transactional
    @Rollback(value = false)
    public void  tets41(){
        Map<String,Object> params = new HashMap<>();
        List<String> zzspr = new ArrayList<>();
        zzspr.add("ysh經(jīng)理");
        params.put("jlspr",zzspr);
        params.put("dealpeople", "ysh組長(zhǎng)2");
//        params.put("days", 3);
//        params.put("jlspr", "ysh");
//        params.put("dealMan")
        customprocessengine.completeTask(279l,params);
    }

    @Test
    @Transactional
    @Rollback(value = false)
    public void  tets4(){
        Map<String,Object> params = new HashMap<>();
//        List<String> zzspr = new ArrayList<>();
//        zzspr.add("yshjl");
//        params.put("jlspr",zzspr);
//        params.put("days", 3);
//        params.put("jlspr", "ysh");
        customprocessengine.completeTask(279l,params);
    }


5.1.開(kāi)啟流程

歷史任務(wù)表

進(jìn)行中的任務(wù)表

5.2員工完成任務(wù)

進(jìn)行中的任務(wù)表

歷史任務(wù)表
這兒設(shè)置的多人會(huì)簽,所以當(dāng)員工提交任務(wù)后,會(huì)有兩個(gè)組長(zhǎng)收到任務(wù)。通過(guò)條件是兩人都通過(guò)。

5.3組長(zhǎng)1通過(guò)

進(jìn)行中的任務(wù)表

歷史任務(wù)表
組長(zhǎng)1完成,進(jìn)行中任務(wù)少了一條數(shù)據(jù),歷史中多了一條數(shù)據(jù),且未跳轉(zhuǎn)至下一流程,完成會(huì)簽功能設(shè)計(jì)。

5.4組長(zhǎng)2通過(guò)

進(jìn)行中的任務(wù)表

歷史任務(wù)表
兩個(gè)組長(zhǎng)審批通過(guò)后順利跳轉(zhuǎn)經(jīng)理審批,滿足預(yù)期設(shè)計(jì)。

5.5經(jīng)理審批通過(guò)

進(jìn)行中的任務(wù)表

歷史任務(wù)表
經(jīng)理審批通過(guò)后,進(jìn)行中的任務(wù)清空,流程結(jié)束。滿足設(shè)計(jì)預(yù)期要求。

6.難點(diǎn)

字符串轉(zhuǎn)執(zhí)行代碼

package com.example.customprocessengine.util;

import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlExpression;
import org.apache.commons.jexl3.MapContext;
import org.apache.commons.jexl3.internal.Engine;

import java.util.Map;

public class ReflectUtils {

    private static JexlEngine jexlEngine = new Engine();

    public static boolean executeExpression(String jexlExpression, Map<String, Object> map) {
        JexlExpression expression = jexlEngine.createExpression(jexlExpression);
        JexlContext context = new MapContext();
        if (null != map && map.size() > 0) {
            map.forEach(context::set);
        }
        return (boolean) expression.evaluate(context);
    }
}

7.不足

  • 流程服務(wù)類api未提供任務(wù)查詢方法
  • 錯(cuò)誤提示待完成
  • 任意流程跳轉(zhuǎn)未實(shí)現(xiàn)

8.結(jié)語(yǔ)

作為自定義流程引擎初版,后續(xù)會(huì)繼續(xù)完善,基本功能完成后將上傳github。喜歡的朋友可以持續(xù)關(guān)注,評(píng)論區(qū)留下郵箱可私發(fā)未完成的代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,460評(píng)論 6 538
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,067評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,467評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,468評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,184評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,582評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,616評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,794評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,343評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,096評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,291評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,863評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,513評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,941評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,190評(píng)論 1 291
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,026評(píng)論 3 396
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,253評(píng)論 2 375