activiti工作流引擎元件

太陽以西.S發表於2020-10-13

學習目的

  • 為了解決專案中某些特殊的業務場景,流程審批業務(請假審批,出差審批,申請單審批,報銷單審批,公文的流轉)。

設計思想

  • 比如開發請假流程(員工請假申請apply–>部門經理審批–>if(請假天數>3天)–>總經理審批–>結束

​ -->if(請假天數<=3天)–>結束)。

  • 第一步:提供了ide外掛,視覺化流程定義,以bpmn流程定義描述性語言(xml描述)。

  • 第二步:提供api服務介面,進行部署流程定義(解析xml, 把xml流程資料儲存到資料庫)。

  • 第三步:開發請假申請業務(增刪改查),呼叫元件api服務去驅動流程向下一步步的執行。

在這裡插入圖片描述

使用

  • 搭建activiti資料庫環境(各種元件內的表)
    • 執行三個sql指令碼建立資料庫表
      • act_ge_*:後設資料表(儲存引擎版本資訊,流程定義xml檔案資料)
      • act_id_*:使用者與角色表(儲存系統使用者與使用者組資訊)
      • act_re_*:流程部署表(儲存流程部署資訊,流程定義檔案資訊)
      • act_ru_*:正在執行當中的流程資料表(儲存流程例項與任務資訊)
      • act_hi_*:執行完結的流程資料歷史表(儲存歷史流程例項與歷史任務資訊)
  • 搭建程式碼環境 (依賴jar包)與spring整合使用,依賴mybatis
    • 引入依賴jar
    • 建立activiti的xml配置檔案,注入spring容器相關的bean物件(ProcessEngineConfiguration,ProcessEngine,5個核心服務bean)
pom
<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring</artifactId>
    <version>5.22.0</version>
</dependency>

activiti.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"/>
        <property name="transactionManager" ref="transactionManager"/>
        <property name="databaseSchemaUpdate" value="false"/>
        <property name="jobExecutorActivate" value="false"/>
    </bean>

    <!-- 這個是activiti的核心類,這個類依賴另一個類processEngineConfiguration -->
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>

    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
    <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
    <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/>
    <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
    <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>

</beans>

  • 設計流程定義檔案並進行部署
    • 安裝外掛:actiBpm

    • 流程定義的節點(id,name,assignee|candidate users|candidate groups(節點的執行人))

    • 生成png圖片
      在這裡插入圖片描述

    • 進行流程部署

自己建立的任務表,一定要有對應的任務id欄位(processid)

流程變數

流程定義中的表示式,稱為流程變數

  • ${loginUser}

  • groups: deptMgr

  • users:mgr1,mgr2

  • ${days<=3}

  • ${approveResult}:審批通過與否

流程部署及執行

測試類

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
public class activitiTest {

    @Resource
    private LeaveService leaveService;

    @Resource
    private RepositoryService rs;
    @Resource
    private IdentityService is;


    /**
     * 流程部署,正式開發中在系統管理-流程定義(增刪查)
     */
    @Test
    public void deployTest() {
        DeploymentBuilder deployment = rs.createDeployment();
        deployment.name("請假申請");
        deployment.addClasspathResource("bpmn/LeaveApply.bpmn");
        deployment.addClasspathResource("bpmn/LeaveApply.png");
        Deployment deploy = deployment.deploy(); // 執行資料庫的insert操作
        String id = deploy.getId();
        System.out.println(id);
    }

    // 查詢流程
    @Test
    public void deployQueryTest() {
        DeploymentQuery deploymentQuery = rs.createDeploymentQuery();
        List<Deployment> list = deploymentQuery.list();
        System.out.println(list);
    }

    /**
     * 維護使用者資訊與組資訊,流程稽核許可權的分配;
     * 實現系統使用者表的人,除了自身的系統使用者表以外,還需要在流程控制元件內的使用者表維護一份
     */
    @Test
    public void addUser() {
        User wj = is.newUser("wj"); // 普通員工
        User deptMgr1 = is.newUser("deptMgr1"); // 部門經理1
        User deptMgr2 = is.newUser("deptMgr2"); // 部門經理2
        User mgr1 = is.newUser("mgr1"); // 總經理1
        User mgr2 = is.newUser("mgr2"); // 總經理2

        is.saveUser(wj);
        is.saveUser(deptMgr1);
        is.saveUser(deptMgr2);
        is.saveUser(mgr1);
        is.saveUser(mgr2);
    }

    // 維護組資訊
    @Test
    public void addGroup() {
        Group employee = is.newGroup("employee");
        Group deptMgr = is.newGroup("deptMgr");
        Group mgr = is.newGroup("mgr");
        is.saveGroup(employee);
        is.saveGroup(deptMgr);
        is.saveGroup(mgr);
    }

    @Test
    public void addMemberShip() {
        is.createMembership("wj", "employee");
        is.createMembership("deptMgr1", "deptMgr");
        is.createMembership("deptMgr2", "deptMgr");
        is.createMembership("mgr1", "mgr");
        is.createMembership("mgr2", "mgr");
    }

    /**
     * 開始流程
     */

    // 儲存草稿
    @Test
    public void addLeaveApplyTest() {
        LeaveApply apply = new LeaveApply();
        apply.setLapplyuser("張三");
        apply.setLreason("探親");
        apply.setLdays("10");
        leaveService.addLeaveApply(apply);
    }

    // 儲存請假申請單並開始流程審批
    @Test
    public void addLeaveApplyAndStartProcessTest() {
        String loginUser = "wj"; // 當前系統登入人
        LeaveApply apply = new LeaveApply();
        apply.setLapplyuser("wj");
        apply.setLreason("探親");
        apply.setLdays("10");
        leaveService.startProcess(apply, loginUser);
    }

    //獲取代辦任務列表,deptMgr1與deptMgr2登入系統後都能看到部門經理審批的任務
    @Test
    public void getTodoTask(){
        String loginUser="deptMgr2";
        List<Task> todoTask = leaveService.getTodoTask(loginUser);
        System.out.println(todoTask);
    }
    
    //在頁面新增簽收操作
    @Test
    public void claimTask(){
        String loginUser="mgr2";
        String taskid = "17505";
        ls.claimTask(loginUser,taskid);
    }

	// 總經理審批
    @Test
    public void approve(){
        String loginUser="mgr2";
        String taskid = "17505";
        boolean approveResult = true;
        ls.approveTask(loginUser,taskid,"回家吧",approveResult);
    }

}

LeaveService

public interface ILeaveService {

    public void addLeaveApply(LeaveApply apply);
	// 啟動流程
    void startProcess(LeaveApply la,String loginUser);
	// 獲得代辦任務
    List<ProcessTask> getTodoTask(String loginUser);
	// 簽收任務
    void claimTask(String loginUser, String taskid);

    void approveTask(String loginUser, String taskid,String comment,boolean approveResult);
}

LeaveServiceImpl

@Service
public class LeaveServiceImpl implements ILeaveService {
    @Resource
    private LeaveApplyMapper lm;

    @Resource
    private RuntimeService rs;

    @Resource
    private TaskService ts;

    @Override
    public void addLeaveApply(LeaveApply apply) {
        lm.insertSelective(apply);
    }

    @Transactional
    @Override
    public void startProcess(LeaveApply la,String loginUser) {
        //儲存請假申請單
        addLeaveApply(la);

        //開始流程(流程定義的key,流程依賴的變數)
        Map<String,Object> valiables = new HashMap<>();
        valiables.put("loginUser",loginUser);
        valiables.put("days",la.getLdays());
        ProcessInstance processInstance = rs.startProcessInstanceByKey("LEAVE_APPLY",valiables);//
        String processInstanceId = processInstance.getId();

        //把請假申請task繼續向下執行
        String taskid = querySingTaskByAssigneeAndPid(processInstanceId,loginUser).getId();
        ts.complete(taskid);//完成某個task

        //把processInstanceId作為外來鍵關聯到請假申請單
        la.setProcessid(processInstanceId);
        updateProcessId(la);
    }

    //獲取所有的代辦任務列表(包含申請單資訊以及Task物件資訊)
    @Override
    public List<ProcessTask> getTodoTask(String loginUser) {
        List<ProcessTask>  result = new ArrayList<>();
        TaskQuery taskQuery = ts.createTaskQuery();
        taskQuery.taskCandidateOrAssigned(loginUser);
        taskQuery.processDefinitionKey("LEAVE_APPLY");//不指定該條件是得到所有的流程定義下的代辦任務列表,適合於放歡迎頁面
        List<Task> list = taskQuery.list();
        for (Task t:list){
            String processInstanceId = t.getProcessInstanceId();
            //根據流程例項id,去查詢申請單詳情。
            LeaveApply leaveApply = queryLeaveApplyByProcessId(processInstanceId);
            ProcessTask pt = new ProcessTask();
            pt.setOrder(leaveApply);
            pt.setTask(t);
            result.add(pt);
        }
        return result;
    }

    @Override
    public void claimTask(String loginUser, String taskid) {
        ts.claim(taskid,loginUser);
    }

    public LeaveApply queryLeaveApplyByProcessId(String processid){
        LeaveApply la = lm.selectByProcessId(processid);
        return la;
    }

    public void updateProcessId(LeaveApply la){
        lm.updateByPrimaryKeySelective(la);
    }

    //根據流程例項id與執行人查詢task物件
    public Task querySingTaskByAssigneeAndPid(String processInstanceId,String assignee){
        TaskQuery taskQuery = ts.createTaskQuery();
        taskQuery.processInstanceId(processInstanceId);
        taskQuery.taskAssignee(assignee);//指定了執行人
        Task task = taskQuery.singleResult();
        return task;
    }

    //審批任務(審批結果,審批意見,審批人)
    @Override
    public void approveTask(String loginUser,String taskid,String comment, boolean approveResult) {
        TaskQuery taskQuery = ts.createTaskQuery();
        taskQuery.taskId(taskid);
        String processInstanceId = taskQuery.singleResult().getProcessInstanceId();

        Map<String,Object> valiables = new HashMap<>();
        valiables.put("approveResult",approveResult);
        ts.addComment(taskid,processInstanceId,"通過",comment);
        ts.complete(taskid,valiables);
    }
}

相關文章