spring boot integrates activiti6 0. Integrate online design

1. Integrate activiti6 0

Add dependency

Add activiti6.0 to maven in spring boot 0 dependency

<dependency>
	<groupId>org.activiti</groupId>
	<artifactId>activiti-spring-boot-starter-basic</artifactId>
	<version>6.0.0</version>
</dependency>

activiti configuration

In application Add in yaml

activiti:
    check-process-definitions: false # Does activti deploy automatically without loading bpmn files
    db-identity-used: true #Whether to use the user system provided by activti. There can be no data in the user table provided by activt, but the table must exist
    database-schema-update: true #Update database every time
    history-level: full  #full highest level

The startup class @ SpringBootApplication of spring boot needs to exclude Security, otherwise an error will be reported when starting the project, which may affect Shiro or other plug-ins.

@SpringBootApplication(exclude = SecurityAutoConfiguration.class)

actiBPM plug-in use, process testing

After completing the above steps, you can use the workflow. If you test the workflow, you can test it together after integrating and completing the online design. Because the experience of the plug-in activiti process in idea is not very good. If you use plug-ins to draw flow charts, you might as well use eclipse.
If the online design is not integrated in the idea editor, you can test whether the integration is successful in the following way.

Install the plug-in actiBPM.

idea2020 doesn't seem to be able to search this plug-in. You can only download it from the plug-in market and add it manually.
Link: https://plugins.jetbrains.com/search?products=idea&search=actiBPM .

New bpmn file

Create a new test01.0 in the resources directory BPMN file. Draw a simple process as follows. (why is it that this plug-in is not easy to use? Because many events can't be found, such as signal start event, signal end event, sub process, etc. and I don't know where to set the node's properties, monitor, etc. strange, I can't understand it. I don't know if my opening method is wrong. I can't understand this plug-in anyway)

This bpmn file can be opened in notepad++da

<?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/testm1604023359723" 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="m1604023359723" name="" targetNamespace="http://www.activiti.org/testm1604023359723" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="myProcess_1" isClosed="false" isExecutable="true" processType="None">
    <startEvent id="_2" name="StartEvent"/>
    <userTask activiti:exclusive="true" id="_3" name="apply"/>
    <userTask activiti:exclusive="true" id="_4" name="Approval"/>
    <endEvent id="_5" name="EndEvent"/>
    <sequenceFlow id="_6" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_7" sourceRef="_3" targetRef="_4"/>
    <sequenceFlow id="_8" sourceRef="_4" targetRef="_5"/>
  </process>
  <bpmndi:BPMNDiagram documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="myProcess_1">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <dc:Bounds height="32.0" width="32.0" x="300.0" y="50.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <dc:Bounds height="55.0" width="85.0" x="275.0" y="135.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
        <dc:Bounds height="55.0" width="85.0" x="285.0" y="250.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <dc:Bounds height="32.0" width="32.0" x="330.0" y="365.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_6" id="BPMNEdge__6" sourceElement="_2" targetElement="_3">
        <di:waypoint x="316.0" y="82.0"/>
        <di:waypoint x="316.0" y="135.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_3" targetElement="_4">
        <di:waypoint x="322.5" y="190.0"/>
        <di:waypoint x="322.5" y="250.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_4" targetElement="_5">
        <di:waypoint x="346.0" y="305.0"/>
        <di:waypoint x="346.0" y="365.0"/>
        <bpmndi:BPMNLabel>
          <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Look at this tag. id="myProcess_1" is used when starting the process (roast again. I can't find the plug-in. I can't set this id there. I modify this id directly by opening this file. I really don't understand.)

<process id="myProcess_1" isClosed="false" isExecutable="true" processType="None">

Deployment file

Once the process file is available, it needs to be deployed. After deployment, it will be displayed in act_re_procdef (insert process definition in the process definition table). KEY_ This field is the key to start the process

Start the process and complete the task

@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
/**
 * Test start
 */
public void testStart(String key){
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key);
    System.out.println("Process started successfully, process id: "+processInstance.getId());
}

/**
 * Test task completed
 */
public void  testCompleteTask(String processInstanceId){
    //Get the current task according to the process id
    org.activiti.engine.task.Task task = taskService.createTaskQuery()
            .processInstanceId(processInstanceId)
            .active()
            .singleResult();
    taskService.complete(task.getId());
    System.out.println();
    System.out.println("Complete the task, task name:"+task.getName()+"task id: "+task.getId());
    //Get the task node behind the current task
    List<Task> nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
    if(nextTask!=null && nextTask.size() > 0){
        System.out.println();
        System.out.println("Next task name:"+nextTask.get(0).getName()+"Next task id: "+nextTask.get(0).getId());
    }else {
        System.out.println();
        System.out.println("End of process");
    }
}

2. Integrated online design

Online design component Download

Download link: https://github.com/Activiti/Activiti/releases/tag/activiti-5.22.0

Import components

Download activiti-5.22.0 and unzip it
Imported Java classes: unzip activiti-modeler-5.22.0-sources Jar (in activiti-5.22.0\activiti-5.22.0\libs directory). After decompression, copy the three classes under activiti-modeler-5.22.0-sources\org\activiti\rest\editor into the project! [insert picture description here]( https://img-blog.csdnimg.cn/20201117112203390.png#pic_center


Import static resources: unzip activiti explorer War (in activiti-5.22.0\activiti-5.22.0\wars directory), unzip it and ask for the price folder and modeler of diagram viewer, editor app html´╝îstencilest. Copy JSON to the project static directory. It is necessary to modify stencelest JSON, baidu by version.




Confirm app CFG The value of the contextRoot in JS is the same as that of the @ RequestMapping of the three classes in the first step of importing java classes. These three default @ RequestMapping(value = "services"). If you modify this url, APP CFG The contextRoot in JS also needs to be modified to the same value.

Access online design

Visit online design and directly visit modeler Html is OK. Note: in direct access to modeler HTML
You must bring the parameter modelId=xxxx (example: http://localhost:8080/modeler.html?modelId=7501 ). Otherwise, the open page will be blank, because the online design will only know to modify the model after passing in the modelid

When online design is opened without modelId, a blank will appear, and the model can be created through java code

public ModelAndView newModel() throws UnsupportedEncodingException {
        //Initialize an empty model
        Model model = repositoryService.newModel();

        //Set some default information, which can be received with parameters
        int revision = 1;
        String key = "process";
        String name = "new-process";
        String description = "";

        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);

        model.setName(name);
        model.setKey(key);
        model.setMetaInfo(modelNode.toString());

        repositoryService.saveModel(model);
        String id = model.getId();

        //ModelEditorSource
        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace","http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.put("stencilset" , stencilSetNode);
        repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
        return new ModelAndView("redirect:/modeler.html?modelId=" + id);
}

In this way, if you need to modify the model, you need to find the modelId manually, which is not very convenient. You can write a model list yourself html. Show all models, provide new buttons, etc.
model-list. The HTML code is as follows:

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>model list</title>
</head>
<body>
<div class="info"><span th:text="${info}"></span></div>
<a href="/activiti/page/create">newly build</a>

<table class="table">
    <thead>
    <tr>
        <th>ID</th>
        <th>Model name</th>
        <th>key</th>
        <th>edition</th>
        <th>deploy ID</th>
        <th>Creation time</th>
        <th>Last update time</th>
        <th>operation</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="data : ${models}">
        <td th:text="${data.id}"></td>
        <td><a th:href="@{/modeler.html(modelId=${data.id})}" class="font-blue" th:text="${data.name}"></a>
        </td>
        <td th:text="${data.key}"></td>
        <td th:text="${data.version}"></td>
        <td th:text="${data.deploymentId}"></td>
        <td th:text="${data.createTime}"> 2018-02-25 17:28:35</td>
        <td th:text="${data.lastUpdateTime}"> 2018-02-25 17:28:35</td>
        <td>
            <a th:href="${'/activiti/deploy/'+data.key}" th:attrappend="objectId=${data.id}" lass="font-blue deployBtn">release</a>
            <a th:href="${'/activiti/exportXML/'+data.id}" class="font-blue">export</a>
        </td>
    </tr>
    </tbody>
</table>
</body>
</html>
@Controller
@RequestMapping("activiti/page")
public class PageController {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * Query all models and return to the default model list view
     * @param model
     * @return
     */
    @GetMapping
    public String toModelListPage(org.springframework.ui.Model model){
        List<Model> models = repositoryService.createModelQuery().orderByCreateTime().desc().list();
        model.addAttribute("models",models);
        return "page/model/model-list";
    }

    /**
     * Create an empty model and redirect to modeler html
     * @return
     * @throws UnsupportedEncodingException
     */
    @GetMapping("/create")
    public ModelAndView newModel() throws UnsupportedEncodingException {
        //Initialize an empty model
        Model model = repositoryService.newModel();

        //Set some default information, which can be received with parameters
        int revision = 1;
        String key = "process";
        String name = "new-process";
        String description = "";

        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);

        model.setName(name);
        model.setKey(key);
        model.setMetaInfo(modelNode.toString());

        repositoryService.saveModel(model);
        String id = model.getId();

        //ModelEditorSource
        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace","http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.put("stencilset" , stencilSetNode);
        repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
        return new ModelAndView("redirect:/modeler.html?modelId=" + id);
    }

}

Export model as xml method

public void export(@PathVariable("modelId") String modelId, HttpServletResponse response) {
        response.setContentType("text/html; charset=UTF-8"); //transcoding 

        try {
            Model modelData = repositoryService.getModel(modelId);
            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
            JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
            BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
            BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
            byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);

            ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);

            String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";
            response.setContentType("application/xml");
            response.setHeader("Content-Disposition", "attachment; filename=" + filename);
            IOUtils.copy(in, response.getOutputStream());  //Otherwise, the above sentence of set xml cannot be exported,
            response.flushBuffer();
        } catch (Exception e) {
            throw new BaseException("activiti model export xml abnormal");

        }
    }

Error saving model

Save model calls the saveModel method in the ModelSaveRestResource class. Serialize @ RequestBody in method. Therefore, if there is a problem that the parameters cannot be accepted when saving the model, you need the code here

test

Save after drawing process


You can see the modelId in the model list, and you can also edit and create a new model

The deployment process code is as follows. Start the process and complete the task, just like the actiBPM plug-in

/**
 * Deploy process according to modelId
 */
public String deploy(String id){
        //Get model
        Model modelData = repositoryService.getModel(id);
        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
        if (bytes == null) {
            return "The model data is empty. Please design the process and save it successfully before publishing.";
        }
        JsonNode modelNode = null;
        try {
            modelNode = new ObjectMapper().readTree(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
        BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
        if(model.getProcesses().size()==0){
            return "The data model does not meet the requirements, please design at least one main process.";
        }
        byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);

        //Release process
        String processName = modelData.getName() + ".bpmn20.xml";
        Deployment deployment = null;
        try {
            deployment = repositoryService.createDeployment()
                    .name(modelData.getName())
                    .addString(processName, new String(bpmnBytes, "UTF-8"))
                    .deploy();
        } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
        }
        modelData.setDeploymentId(deployment.getId());
        repositoryService.saveModel(modelData);
        return "Process published successfully";
    }

Tags: Java Activiti

Posted by prashanth on Sat, 07 May 2022 07:45:47 +0300