1. 程式人生 > >Activiti(二)簡單請假流程實現

Activiti(二)簡單請假流程實現

在SpringBoot2整合Activiti6的環境中,實現簡單的請假流程。編寫請假業務流程。流程業務為:

1,員工請假,先建立請假流程

2,員工填寫請假申請,也可以不填寫,直接結束流程

3,提交給直接主管審批,如果直接主管拒絕,則重新填寫,如果直接主管同意,再到部門主管審批,

4,部門主管審批部門主管同意,則請假流程結束,請假成功,如果部門主管不同意,返回員工重新提交申請。

建立流程檔案

流程定義程式碼如下

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/testm1539766523202" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1539766523202" name="" targetNamespace="http://www.activiti.org/testm1539766523202" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="leave1" isClosed="false" isExecutable="true" processType="None">
    <startEvent id="_2" name="start"/>
    <userTask activiti:assignee="${leave.userId}" activiti:exclusive="true" id="_3" name="submit"/>
    <exclusiveGateway gatewayDirection="Unspecified" id="_4" name="result"/>
    <userTask activiti:assignee="${leave.approver1}" activiti:exclusive="true" id="_5" name="approve1"/>
    <exclusiveGateway gatewayDirection="Unspecified" id="_6" name="result"/>
    <userTask activiti:assignee="${leave.approver2}" activiti:exclusive="true" id="_7" name="approve2"/>
    <exclusiveGateway gatewayDirection="Unspecified" id="_8" name="result"/>
    <endEvent id="_9" name="end"/>
    <sequenceFlow id="_10" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_11" sourceRef="_3" targetRef="_4"/>
    <sequenceFlow id="_12" name="y" sourceRef="_4" targetRef="_5">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave.submit==true}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_13" name="n" sourceRef="_4" targetRef="_9">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave.submit==false}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_14" sourceRef="_5" targetRef="_6"/>
    <sequenceFlow id="_15" name="n" sourceRef="_6" targetRef="_7">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave.agree1==true}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_16" sourceRef="_7" targetRef="_8"/>
    <sequenceFlow id="_17" name="y" sourceRef="_6" targetRef="_3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave.agree1==false}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_18" name="n" sourceRef="_8" targetRef="_3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave.agree2==false}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_19" name="y" sourceRef="_8" targetRef="_9">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${leave.agree2==true}]]></conditionExpression>
    </sequenceFlow>
  </process>
</definitions>

請注意流程圖中userTask的assignee屬性表示任務的所有者,userTask需要指定任務的所有者變數,如:

sequenceFlow中的condition描述流程的走向,當滿足條件是,流程自動走該sequenceFlow

編寫使用者介面

@RestController
@RequestMapping("/level/v1")
public class LeaveController {

    public static final Logger log = LoggerFactory.getLogger(LeaveController.class);

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ProcessEngine processEngine;

    /**
     * 啟動流程
     * @param userId
     * @return
     */
    @RequestMapping(value = "/start", method = RequestMethod.GET)
    public Map<String, Object> start(@RequestParam String userId){
        Map<String, Object> vars = new HashMap<>();
        Leave leave = new Leave();
        leave.setUserId(userId);
        vars.put("leave",leave);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leave1",vars);
        Map<String, Object> resultMap = new HashMap<>();
        return resultMap;
    }

    /**
     * 填寫請假單
     * @param leave
     * @return
     */
    @RequestMapping(value="/apply", method = RequestMethod.POST)
    public Map<String, Object> apply(@RequestBody Leave leave){
        Task task = taskService.createTaskQuery().taskId(leave.getTaskId()).singleResult();
        Map<String, Object> vars = new HashMap<>();
        Leave origin = (Leave) taskService.getVariable(leave.getTaskId(), "leave");
        origin.setDesc(leave.getDesc());
        origin.setStartDate(leave.getStartDate());
        origin.setEndDate(leave.getEndDate());
        origin.setTotalDay(leave.getTotalDay());
        origin.setApprover1(leave.getApprover1());
        origin.setApprover2(leave.getApprover2());
        origin.setSubmit(leave.getSubmit());
        vars.put("leave", origin);
        taskService.complete(leave.getTaskId(), vars);
        Map<String, Object> resultMap = ResultMapHelper.getSuccessMap();
        return resultMap;
    }

    /**
     * 查詢使用者流程
     * @param userId
     * @return
     */
    @RequestMapping(value = "/find", method = RequestMethod.GET)
    public Map<String, Object> find(@RequestParam("userId")String userId){
        List<Task> taskList = taskService.createTaskQuery().taskAssignee(userId).list();
        List<Leave> resultList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(taskList)){
            for(Task task : taskList){
                Leave leave = (Leave) taskService.getVariable(task.getId(),"leave");
                leave.setTaskId(task.getId());
                leave.setTaskName(task.getName());
                resultList.add(leave);
            }
        }
        Map<String, Object> resultMap = ResultMapHelper.getSuccessMap();
        resultMap.put("datas", resultList);
        return resultMap;
    }

    /**
     * 直接主管審批
     * @param leave
     * @return
     */
    @RequestMapping(value = "/approve1", method = RequestMethod.POST)
    public Map<String, Object> approve1(@RequestBody Leave leave){
        Task task = taskService.createTaskQuery().taskId(leave.getTaskId()).singleResult();
        Map<String, Object> vars = new HashMap<>();
        Leave origin = (Leave) taskService.getVariable(leave.getTaskId(), "leave");
        origin.setApproveDesc1(leave.getApproveDesc1());
        origin.setAgree1(leave.getAgree1());
        vars.put("leave", origin);
        taskService.complete(leave.getTaskId(),vars);
        Map<String, Object> resultMap = ResultMapHelper.getSuccessMap();
        return resultMap;
    }

    /**
     * 部門主管審批
     * @param leave
     * @return
     */
    @RequestMapping(value = "/approve2", method = RequestMethod.POST)
    public Map<String, Object> approve2(@RequestBody Leave leave){
        Task task = taskService.createTaskQuery().taskId(leave.getTaskId()).singleResult();
        Map<String, Object> vars = new HashMap<>();
        Leave origin = (Leave) taskService.getVariable(leave.getTaskId(), "leave");
        origin.setApproveDesc2(leave.getApproveDesc2());
        origin.setAgree2(leave.getAgree2());
        vars.put("leave", origin);
        taskService.complete(leave.getTaskId(),vars);
        Map<String, Object> resultMap = ResultMapHelper.getSuccessMap();
        return resultMap;
    }

    /**
     * 檢視歷史記錄
     * @param userId
     * @return
     */
    @RequestMapping(value="/findClosed", method = RequestMethod.GET)
    public Map<String, Object> findClosed(String userId){
        HistoryService historyService = processEngine.getHistoryService();

        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("leave1").variableValueEquals("leave.userId",userId).list();
        List<Leave> leaves = new ArrayList<>();
        for(HistoricProcessInstance pi : list){
            leaves.add((Leave) pi.getProcessVariables().get("leave"));
        }
        Map<String, Object> resultMap = ResultMapHelper.getSuccessMap();
        resultMap.put("datas", leaves);
        return resultMap;
    }

}

請假相關Java Model

public class Leave implements Serializable {
    private static final long serialVersionUID = 2248469053125414262L;

    private String userId;

    private Boolean submit;

    private Date startDate;

    private Date endDate;

    private float totalDay;

    private String desc;

    private String taskId;

    private String taskName;

    private String approver1;

    private Boolean agree1;

    private String approveDesc1;

    private String approver2;

    private Boolean agree2;

    private String approveDesc2;
}

測試

1,啟動流程

訪問GET請求http://192.168.104.24:8092/level/v1/start?userId=3000,使用者3000啟動請求流程

curl -X GET --header 'Accept: application/json' 'http://192.168.104.24:8092/level/v1/start?userId=3000'

2,檢視使用者的3000的任務

訪問GET請求http://192.168.104.24:8092/level/v1/find?userId=3000

curl -X GET --header 'Accept: application/json' 'http://192.168.104.24:8092/level/v1/find?userId=3000'

返回:

{
  "msg": "ok",
  "code": "0",
  "datas": [
    {
      "userId": "3000",
      "submit": null,
      "startDate": null,
      "endDate": null,
      "totalDay": 0,
      "desc": null,
      "taskId": "15021",
      "taskName": "submit",
      "approver1": null,
      "agree1": null,
      "approveDesc1": null,
      "approver2": null,
      "agree2": null,
      "approveDesc2": null
    }
  ]
}

表示使用者3000已經有請假單待提交

3,使用者提交請假單

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ \ 
   "desc": "沒有理由", \ 
   "endDate": "2018-10-24 18:00:00", \ 
   "startDate": "2018-10-21 09:00:00", \ 
   "submit": true, \ 
   "taskId": "15021", \ 
   "totalDay": 3, \ 
   "approver1": "3001", \ 
   "approver2": "3002" \ 

4,檢視直接主管任務提交請假理由,直接主管3001,部門主管3002,開始時間,結束時間,提交狀態(提交,或者關閉),任務ID,請假天數,請假事由等。

curl -X GET --header 'Accept: application/json' 'http://192.168.104.24:8092/level/v1/find?userId=3001'

返回直接主管審批任務資訊

{
  "msg": "ok",
  "code": "0",
  "datas": [
    {
      "userId": "3000",
      "submit": true,
      "startDate": "2018-10-21 09:00:00",
      "endDate": "2018-10-24 18:00:00",
      "totalDay": 3,
      "desc": "沒有理由",
      "taskId": "15025",
      "taskName": "approve1",
      "approver1": "3001",
      "agree1": null,
      "approveDesc1": null,
      "approver2": "3002",
      "agree2": null,
      "approveDesc2": null
    }
  ]
}

5,直接主管審批

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ \ 
   "agree1": true, \ 
   "approveDesc1": "同意", \ 
   "taskId": "15025" \ 
  \ 
 }' 'http://192.168.104.24:8092/level/v1/approve1'

提交審批結果agree1,審批意見,任務id


6,檢視部門主管任務提交審批結果agree1,審批意見,任務id

curl -X GET --header 'Accept: application/json' 'http://192.168.104.24:8092/level/v1/find?userId=3002'

返回部門主管審批任務資訊

{
  "msg": "ok",
  "code": "0",
  "datas": [
    {
      "userId": "3000",
      "submit": true,
      "startDate": "2018-10-21 09:00:00",
      "endDate": "2018-10-24 18:00:00",
      "totalDay": 3,
      "desc": "沒有理由",
      "taskId": "15029",
      "taskName": "approve2",
      "approver1": "3001",
      "agree1": true,
      "approveDesc1": "同意",
      "approver2": "3002",
      "agree2": null,
      "approveDesc2": null
    }
  ]
}

7,部門主管審批 

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ \ 
   "agree2": true, \ 
   "approveDesc2": "string", \ 
   "taskId": "15029" \ 
 }' 'http://192.168.104.24:8092/level/v1/approve2'

執行成功後請假流程執行成功。

8,檢視歷史任務


curl -X GET --header 'Accept: application/json' 'http://192.168.104.24:8092/level/v1/findClosed?userId=3000'

返回任務的歷史記錄資訊

{
  "msg": "ok",
  "code": "0",
  "datas": [
    {
      "userId": "3000",
      "submit": true,
      "startDate": "2018-10-21 09:00:00",
      "endDate": "2018-10-24 18:00:00",
      "totalDay": 3,
      "desc": "沒有理由",
      "taskId": null,
      "taskName": null,
      "approver1": "3001",
      "agree1": true,
      "approveDesc1": "同意",
      "approver2": "3002",
      "agree2": true,
      "approveDesc2": "string"
    }
  ]
}

篇幅有限,就不一一羅列其他測試用例了。

(完)