Activiti workflow from entry to be buried: complete Hello World Competition (Activiti workflow API with examples to explain)

Article Source Hosted: github.com/OUYANGSIHAI... welcome star! ! !

Originally thinking about nothing else, just in front of the project used the Activiti workflow framework, writing a blog, but things always have the magazine, has been delayed until now, this section had wanted to write something about the Activiti APIHowever, too much thinking about this blog, and it seems too stiff, difficult to understand, so that APIin the actual demo to explain.

First, create flow charts

Before you start doing the work flow, we should first put in the deployment of specific business workflow flow chart reflected, and all tests pass, this is equivalent to half success, the development of specific business behind the relatively easier.

First, let's take a look at what controls idea, commonly used controls were labeled.

Let's talk about the establishment of a specific flow chart of the process.

First, we need to pull into a starting node to the bpmnfile, which is a graphical interface, you can just pull.

Then, we pulled into a control from UserTaskthe user node to the task bpmnfile.

This way there will be two nodes approval, and if it requires some other business needs, we can also add some gateway , where it is temporarily added.

Finally, we need only one end node EndEventto complete the deployment diagram drawing workflow.

Our last look at the complete example.

It appears to have completed mapping the entire flow chart, but the fly in the ointment is that we currently do not set the supervisor for approval and instructor approval in the end who is going to approve, so we still need to take a look a look how to set approvers .

First, we need to select a node for approval , for example, select the node supervisor approval.

Secondly, we can see an obvious idea, called the left side of the editor of the BPMN editorproperties box, which includes an all attributes of the user task node can be set .

** Note: ** user candidate, the candidate group, task listener, these three attributes do not speak here temporarily, and then add back.

Since this step we need to set the approver, so we need to Assigneeset our approver this property.

As shown above, there is provided supervisor approval approval man this node sihai. In addition to setting the approver directly, there are two ways to set up the back to add.

Another approval node is also set in this way can be completed approver is provided.

very good, so basically it completes the creation of a flow chart. Next, we will explain in detail by way of example to explain the Activiti of the API .

Second, the API examples to explain

In creating this flow chart above, we have not generated png image, so if you do not know how to produce, and can refer to this article before: the Activiti workflow from entry to be buried: the integration of the Spring .

Since it is to explain the API, it is still mainly look at what API it, so that it can hold a whole.

Specifically how to use the API, the next 11 years.

2.1 Process Definition

Since it is a process definition, it is definitely not how to deploy a process definition.

2.1.1 deployment process definition Method 1
 @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;

    /**
     * 部署流程定义(从classpath)
     */
    @Test
    public void deploymentProcessDefinition_classpath(){
        Deployment deployment = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                .createDeployment()//创建一个部署对象
                .name("流程定义")//添加部署的名称
                .addClasspathResource("bpmn/hello.bpmn")//从classpath的资源中加载,一次只能加载一个文件
                .addClasspathResource("bpmn/hello.png")//从classpath的资源中加载,一次只能加载一个文件
                .deploy();//完成部署
        System.out.println("部署ID:"+deployment.getId());
        System.out.println("部署名称:"+deployment.getName());
    }
复制代码

Note: here is the junit test environment after integration spring, see how to integrate the spring of this article: the Activiti workflow from entry to be buried: the integration of spring .

Output:

Thus, we deployed the process. So specifically how to operate it, let us look at the whole process.

  • Target acquisition process engine: this integrates with the spring.

  • Acquired a RepositoryService objects (warehouse objects) through workflow engine

  • Generating a target deployment configuration object to configure the associated service package deployment operation by the object warehouse.

  • This is a chain program, set the display name in the deployment configuration object, file upload process definition rules

  • Storage process definition to the database table rules information.

In fact, this step, use the Activiti database in three tables, namely: act_re_deployment (deployment object table), act_re_procdef (process definition table), act_ge_bytearray (Resource File Table).

We look at three tables of changes: 1) act_re_deployment

You can see, the name of the deployment ID and deploy there this table.

2)act_re_procdef

This table, stored for Deployment_ID deployment process deployed id, bpmn resource file name, png image name and other information.

3)act_ge_bytearray

Storing information related to the deployment of process definitions. That repository for process definition document. Each deployment will increase once two records, one is about bpmn rules file is a picture (if deployed specify only bpmn a file, activiti parses the contents of the file is automatically generated bpmn flow chart at deployment). Not large two files are stored in binary form in the database.

2.1.2 process definition deployment method 2
 /**
     * 部署流程定义(从zip)
     */
    @Test
    public void deploymentProcessDefinition_zip(){
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("bpmn/hello.zip");
        ZipInputStream zipInputStream = new ZipInputStream(in);
        Deployment deployment = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                .createDeployment()//创建一个部署对象
                .name("流程定义")//添加部署的名称
                .addZipInputStream(zipInputStream)//指定zip格式的文件完成部署
                .deploy();//完成部署
        System.out.println("部署ID:"+deployment.getId());//
        System.out.println("部署名称:"+deployment.getName());//
    }

复制代码

Project is structured as follows:

Output:

It seems that is no problem, the only difference is compressed into a zip file format, using the input stream as a zip deployment process definition, the use of other no difference.

After deploying a process definition, we should want to look at some of the information process definition.

2.1.3 View process definition
/**
     * 查询流程定义
     */
    @Test
    public void findProcessDefinition(){
        List<ProcessDefinition> list = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                .createProcessDefinitionQuery()//创建一个流程定义的查询
                /**指定查询条件,where条件*/
//						.deploymentId(deploymentId)//使用部署对象ID查询
//						.processDefinitionId(processDefinitionId)//使用流程定义ID查询
//						.processDefinitionKey(processDefinitionKey)//使用流程定义的key查询
//						.processDefinitionNameLike(processDefinitionNameLike)//使用流程定义的名称模糊查询

                /**排序*/
                .orderByProcessDefinitionVersion().asc()//按照版本的升序排列
//						.orderByProcessDefinitionName().desc()//按照流程定义的名称降序排列

                /**返回的结果集*/
                .list();//返回一个集合列表,封装流程定义
//						.singleResult();//返回惟一结果集
//						.count();//返回结果集数量
//						.listPage(firstResult, maxResults);//分页查询
        if(list!=null && list.size()>0){
            for(ProcessDefinition pd:list){
                System.out.println("流程定义ID:"+pd.getId());//流程定义的key+版本+随机生成数
                System.out.println("流程定义的名称:"+pd.getName());//对应hello.bpmn文件中的name属性值
                System.out.println("流程定义的key:"+pd.getKey());//对应hello.bpmn文件中的id属性值
                System.out.println("流程定义的版本:"+pd.getVersion());//当流程定义的key值相同的相同下,版本升级,默认1
                System.out.println("资源名称bpmn文件:"+pd.getResourceName());
                System.out.println("资源名称png文件:"+pd.getDiagramResourceName());
                System.out.println("部署对象ID:"+pd.getDeploymentId());
                System.out.println("*********************************************");
            }
        }
    }
复制代码

Output:

Query process definition Summary:

  • Process definition and deployment of objects related to the Service are RepositoryServicebehind'll find all about the process definition RepositoryService.

  • With this createProcessDefinitionQuery()setting method a number of query parameters, conditions such as by descending ascending like.

2.1.4 Delete process definition

By removing the deployment of ID information for the 2501.

/**
     * 删除流程定义
     */
    @Test
    public void deleteProcessDefinition(){
        //使用部署ID,完成删除,指定部署对象id为2501删除
        String deploymentId = "2501";
        /**
         * 不带级联的删除
         *    只能删除没有启动的流程,如果流程启动,就会抛出异常
         */
//		processEngine.getRepositoryService()//
//						.deleteDeployment(deploymentId);

        /**
         * 级联删除
         * 	  不管流程是否启动,都能可以删除
         */
        processEngine.getRepositoryService()//
                .deleteDeployment(deploymentId, true);
        System.out.println("删除成功!");
    }
复制代码

Output:

To view the database and found that act_re_deploymentdata does not exist anymore.

  • Here or through getRepositoryService()acquisition method to deploy custom object, and then delete the specified ID information.
2.1.5 acquisition process definition document resources

The main role here is to query the picture, the process can be done in the back with a show by the picture. We look at how specific view.

/**
     * 查看流程图
     *
     * @throws IOException
     */
    @Test
    public void viewPic() throws IOException {
        /**将生成图片放到文件夹下*/
        String deploymentId = "5001";
        //获取图片资源名称
        List<String> list = processEngine.getRepositoryService()//
                .getDeploymentResourceNames(deploymentId);
        //定义图片资源的名称
        String resourceName = "";
        if (list != null && list.size() > 0) {
            for (String name : list) {
                if (name.indexOf(".png") >= 0) {
                    resourceName = name;
                }
            }
        }

        //获取图片的输入流
        InputStream in = processEngine.getRepositoryService()//
                .getResourceAsStream(deploymentId, resourceName);

        //将图片生成到F盘的目录下
        File file = new File("F:/" + resourceName);

        //将输入流的图片写到磁盘
        FileUtils.copyInputStreamToFile(in, file);
    }
复制代码

In the F disk, you can find a picture.

2.1.6 for the latest version of the process definition
 /**
     * 查询最新版本的流程定义
     */
    @Test
    public void findLastVersionProcessDefinition() {
        List<ProcessDefinition> list = processEngine.getRepositoryService()//
                .createProcessDefinitionQuery()//
                .orderByProcessDefinitionVersion().asc()//使用流程定义的版本升序排列
                .list();
        /**
         map集合的特点:当map集合key值相同的情况下,后一次的值将替换前一次的值
         */
        Map<String, ProcessDefinition> map = new LinkedHashMap<String, ProcessDefinition>();
        if (list != null && list.size() > 0) {
            for (ProcessDefinition pd : list) {
                map.put(pd.getKey(), pd);
            }
        }
        List<ProcessDefinition> pdList = new ArrayList<ProcessDefinition>(map.values());
        if (pdList != null && pdList.size() > 0) {
            for (ProcessDefinition pd : pdList) {
                System.out.println("流程定义ID:" + pd.getId());//流程定义的key+版本+随机生成数
                System.out.println("流程定义的名称:" + pd.getName());//对应hello.bpmn文件中的name属性值
                System.out.println("流程定义的key:" + pd.getKey());//对应hello.bpmn文件中的id属性值
                System.out.println("流程定义的版本:" + pd.getVersion());//当流程定义的key值相同的相同下,版本升级,默认1
                System.out.println("资源名称bpmn文件:" + pd.getResourceName());
                System.out.println("资源名称png文件:" + pd.getDiagramResourceName());
                System.out.println("部署对象ID:" + pd.getDeploymentId());
                System.out.println("*********************************************************************************");
            }
        }
    }
复制代码

Output:

2.1.7 process definition summary

1, the deployment process definition uses the following Activiti a few tables.

  • act_re_deployment: deployment object table
  • act_re_procdef: process definition table
  • act_ge_bytearray: Resource File Table
  • act_ge_property: primary key generation strategy table

2, we find operational deployment process definitions are in RepositoryServiceoperation under this class, we only need to pass getRepositoryService()all operations to get the object, you can define the deployment process by the chain rule.

Examples of the use of the full 2.2 workflow

In this section, we passed a complete example to summarize some basic knowledge discussed before, this can be a better learning and knowledge points behind the front, it would be a transition chapter.

Back to establish a flow chart of the first section , we have the basic bpmn map has been created, however, we need to do a complete example, we still need to add some content, so as to be able to do such an instance, our first view of the first section of the bpmn take over.

First, we need to be clear: this figure so far, we just simply put the process to draw out, for example, when we need to review, is the need to a specific person to a specific audit, so we need each node is set to a specific audit staff.

** Note: ** Set behind auditors also points a node go into detail, here is a simple example to do so, only here you can understand, well ok.

Set auditing staff step

First, we need to select a node, for example, in the figure of "mentor approval" node.

Then, in the tool bar on the left, we will see a lot of options, there is an entry for Assignee, we need to set our approver nodes need to be set in this option.

Assignee format **: ** directly English or Chinese may be, for example sihai, a more complex set back repeat.

The following node set is exactly the same with the above.

Counselors approval approvers are: Ouyang hai.

perfect, so the task flow diagram is complete, here we can test this instance the stage.

1) Deployment process definition deployment process defined in the previous section already mentioned, there are two ways to process a file is loaded and bpmn png file, there is a two these compressed files into a compressed zip format file, then loaded. Here we use the first method for processing.

/**
     * 部署流程定义(从classpath)
     */
    @Test
    public void deploymentProcessDefinition_classpath() {
        Deployment deployment = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
                .createDeployment()//创建一个部署对象
                .name("hello")//添加部署的名称
                .addClasspathResource("bpmn/hello.bpmn")//从classpath的资源中加载,一次只能加载一个文件
                .addClasspathResource("bpmn/hello.png")//从classpath的资源中加载,一次只能加载一个文件
                .deploy();//完成部署
        log.info("部署ID:" + deployment.getId());
        log.info("部署名称:" + deployment.getName());
    }

复制代码

Now the process has been defined, here we need to start the process instance.

This step is done on about something, you can see in the previous chapter.

2) process instance is started

 /**
     * 启动流程实例
     */
    @Test
    public void startProcessInstance(){
        //1、流程定义的key,通过这个key来启动流程实例
        String processDefinitionKey = "hello";
        //2、与正在执行的流程实例和执行对象相关的Service
        // startProcessInstanceByKey方法还可以设置其他的参数,比如流程变量。
        ProcessInstance pi = processEngine.getRuntimeService()
                .startProcessInstanceByKey(processDefinitionKey);//使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中id的属性值,使用key值启动,默认是按照最新版本的流程定义启动
        log.info("流程实例ID:"+pi.getId());//流程实例ID
        log.info("流程定义ID:"+pi.getProcessDefinitionId());//流程定义ID
    }
复制代码

Note: processDefinitionKey bpmn is the name of the file.

Step 1 acquired runtimeService instance. 2 bpmn files by name, which is processDefinitionKey to start the process instance. After 3 to start the process, the process of the task went to the supervisor for approval node.

Here is a query personal tasks, we can query task supervisor approval node.

3) access to personal tasks

/**
     * 查询当前人的个人任务
     */
    @Test
    public void findPersonalTask(){
        String assignee = "sihai";
        List<Task> list = processEngine.getTaskService()//与正在执行的任务管理相关的Service
                .createTaskQuery()//创建任务查询对象
                /**查询条件(where部分)*/
                .taskAssignee(assignee)//指定个人任务查询,指定办理人
//						.taskCandidateUser(candidateUser)//组任务的办理人查询
//						.processDefinitionId(processDefinitionId)//使用流程定义ID查询
//						.processInstanceId(processInstanceId)//使用流程实例ID查询
//						.executionId(executionId)//使用执行对象ID查询
                /**排序*/
                .orderByTaskCreateTime().asc()//使用创建时间的升序排列
                /**返回结果集*/
//						.singleResult()//返回惟一结果集
//						.count()//返回结果集的数量
//						.listPage(firstResult, maxResults);//分页查询
                .list();//返回列表
        if(list!=null && list.size()>0){
            for(Task task:list){
                log.info("任务ID:"+task.getId());
                log.info("任务名称:"+task.getName());
                log.info("任务的创建时间:"+task.getCreateTime());
                log.info("任务的办理人:"+task.getAssignee());
                log.info("流程实例ID:"+task.getProcessInstanceId());
                log.info("执行对象ID:"+task.getExecutionId());
                log.info("流程定义ID:"+task.getProcessDefinitionId());
                log.info("********************************************");
            }
        }
    }
复制代码

By sihaithis reviewer, the query to the following information.

Analysis Step 1 firstly getTaskService method TaskService acquired object. 2 Create a query object by createTaskQuery method. 3 Set reviewer by taskAssignee method. 4 the results returned, we can orderByTaskCreateTime (). Asc () set the sort, and other information.

It should be noted that the inquiry into an important message is: task id (taskId), the next step, we need to pass this task id, to complete the task.

4) for personal tasks

/**
     * 完成我的任务
     */
    @Test
    public void completePersonalTask() {
        //任务ID,上一步查询得到的。
        String taskId = "7504";
        processEngine.getTaskService()//与正在执行的任务管理相关的Service
                .complete(taskId);
        log.info("完成任务:任务ID:" + taskId);
    }
复制代码

Previous tasks by id: 7504, to complete the task.

Step 1 First, to get the object by getTaskService TaskService method. 2 call the complete method, given a specific task to complete the task id.

5) query process status (where are judging process a node) This interface is much needed when we are in a particular business, we need to determine our processes of state What is the state, or that our processes which come when a node, an interface that let us achieve business save a lot of things.

/**
     * 查询流程状态(判断流程走到哪一个节点)
     */
    @Test
    public void isProcessActive() {
        String processInstanceId = "7501";
        ProcessInstance pi = processEngine.getRuntimeService()//表示正在执行的流程实例和执行对象
                .createProcessInstanceQuery()//创建流程实例查询
                .processInstanceId(processInstanceId)//使用流程实例ID查询
                .singleResult();
        if (pi == null) {
            log.info("流程已经结束");
        } else {
            log.info("流程没有结束");
            //获取任务状态
            log.info("节点id:" + pi.getActivityId());
        }
    }
复制代码

Step: 1 ProcessInstance acquired process instance object. Example 2 obtained Id (node id) by getActivityId method.

So we got 节点 Idwhat effect? In fact, the arrival of the Id, we can determine where one process step. For example, the above output node id is _4, this is the corresponding _4 辅导员审批节点的 id, so we can actually interpret the process has come to this node, and the latter needs to play a role in the process status page display time.

6) historical information query process performed by looking at the official API interface activiti 5 and found to view historical information have the following query interface.

Here we test one by one on the following method by the above examples.

Examples of historical activity query interface

/**
     * 历史活动查询接口
     */
    @Test
    public void findHistoryActivity() {
        String processInstanceId = "7501";
        List<HistoricActivityInstance> hais = processEngine.getHistoryService()//
                .createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();
        for (HistoricActivityInstance hai : hais) {
            log.info("活动id:" + hai.getActivityId()
                    + "   审批人:" + hai.getAssignee()
                    + "   任务id:" + hai.getTaskId());
            log.info("************************************");
        }
    }
复制代码

Through this interface not only this information, there are other ways be found, you can get more about the history of activities other information.

Historical process instance query interface

/**
     * 查询历史流程实例
     */
    @Test
    public void findHistoryProcessInstance() {
        String processInstanceId = "7501";
        HistoricProcessInstance hpi = processEngine.getHistoryService()// 与历史数据(历史表)相关的Service
                .createHistoricProcessInstanceQuery()// 创建历史流程实例查询
                .processInstanceId(processInstanceId)// 使用流程实例ID查询
                .orderByProcessInstanceStartTime().asc().singleResult();
        log.info(hpi.getId() + "    " + hpi.getProcessDefinitionId() + "    " + hpi.getStartTime() + "    "
                + hpi.getEndTime() + "     " + hpi.getDurationInMillis());
    }

复制代码

This interface can be queried about the history of the process instance all information.

The historical task instance query interface

 /**
     * 查询历史任务
     */
    @Test
    public void findHistoryTask() {
        String processInstanceId = "7501";
        List<HistoricTaskInstance> list = processEngine.getHistoryService()// 与历史数据(历史表)相关的Service
                .createHistoricTaskInstanceQuery()// 创建历史任务实例查询
                .processInstanceId(processInstanceId)//
                .orderByHistoricTaskInstanceStartTime().asc().list();
        if (list != null && list.size() > 0) {
            for (HistoricTaskInstance hti : list) {
                log.info("\n 任务Id:" + hti.getId() + "    任务名称:" + hti.getName() + "    流程实例Id:" + hti.getProcessInstanceId() + "\n 开始时间:"
                        + hti.getStartTime() + "   结束时间:" + hti.getEndTime() + "   持续时间:" + hti.getDurationInMillis());
            }
        }
    }
复制代码

This query interface to query the historical task information .

Historical process variables query interface

/**
     * 查询历史流程变量
     */
    @Test
    public void findHistoryProcessVariables() {
        String processInstanceId = "7501";
        List<HistoricVariableInstance> list = processEngine.getHistoryService()//
                .createHistoricVariableInstanceQuery()// 创建一个历史的流程变量查询对象
                .processInstanceId(processInstanceId)//
                .list();
        if (list != null && list.size() > 0) {
            for (HistoricVariableInstance hvi : list) {
                log.info("\n" + hvi.getId() + "   " + hvi.getProcessInstanceId() + "\n" + hvi.getVariableName()
                        + "   " + hvi.getVariableTypeName() + "    " + hvi.getValue());
            }
        }
    }
复制代码

There is no set process variables In this example, therefore, there is not any query historical information.

This interface is mainly about the history of the process variable number of settings.

History local interface Query Interface

/**
     * 通过执行sql来查询历史数据,由于activiti底层就是数据库表。
     */
    @Test
    public void findHistoryByNative() {
        HistoricProcessInstance hpi = processEngine.getHistoryService()
                .createNativeHistoricProcessInstanceQuery()
                .sql("查询底层数据库表的sql语句")
                .singleResult();
        log.info("\n" + hpi.getId() + "    " + hpi.getProcessDefinitionId() + "    " + hpi.getStartTime()
                + "\n" + hpi.getEndTime() + "     " + hpi.getDurationInMillis());
    }

复制代码

This interface is provided through a direct sql 语句query of historical information, we only need to sql()write the sql statement native method can perform data queries.

I write to you, I should think through almost a complete example of this would Activiti API workflow are introduced, and this section will be here to say goodbye. Come back to look at the API interface to the beginning of the article, which also summed up in this section.

Articles have inappropriate, please correct me, if you like micro-letters to read, you can also concerned about my micro-channel public number : , 好好学javaaccess to quality learning resources.

Guess you like

Origin juejin.im/post/5cfa290d6fb9a07ec27b9518