srpign boot + activiti7 + 在线编辑器整合

先看效果

 

 

 

 

 

 

 

 

参考地址:https://blog.csdn.net/huashenghn/article/details/103088775

1.导入静态资源 diagram-viewer、editor-app

2.配置  editor-app 的 app-cfg.js 中的 contextRoot

3.新增编辑流程所需要的resource

 

ModelEditorJsonRestResource.java

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ***.***.activiti.resource;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author
 */
@RestController
@RequestMapping("/service")
@Api(value = "aciviti-app model editor json", tags = {"保存模型"})
public class ModelEditorJsonRestResource implements ModelDataJsonConstants {
  
  protected static final Logger LOGGER = LoggerFactory.getLogger(ModelEditorJsonRestResource.class);
  
  @Autowired
  private RepositoryService repositoryService;
  
  @Autowired
  private ObjectMapper objectMapper;
  
  @RequestMapping(value="/model/{modelId}/json", method = RequestMethod.GET, produces = "application/json")
  public ObjectNode getEditorJson(@PathVariable String modelId) {
    ObjectNode modelNode = null;
    
    Model model = repositoryService.getModel(modelId);
      
    if (model != null) {
      try {
        if (StringUtils.isNotEmpty(model.getMetaInfo())) {
          modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
        } else {
          modelNode = objectMapper.createObjectNode();
          modelNode.put(MODEL_NAME, model.getName());
        }
        modelNode.put(MODEL_ID, model.getId());
        ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
            new String(repositoryService.getModelEditorSource(model.getId()), "utf-8"));
        modelNode.put("model", editorJsonNode);
        
      } catch (Exception e) {
        LOGGER.error("Error creating model JSON", e);
        throw new ActivitiException("Error creating model JSON", e);
      }
    }
    return modelNode;
  }
}

  

ModelSaveRestResource.java

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ***.***.activiti.resource;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.List;

/**
 * @author
 */
@RestController
@RequestMapping("/service")
@Api(value = "aciviti-app model", tags = {"保存模型"})
public class ModelSaveRestResource implements ModelDataJsonConstants {
  
  protected static final Logger LOGGER = LoggerFactory.getLogger(ModelSaveRestResource.class);

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



  @RequestMapping(value="/model/{modelId}/save", method = RequestMethod.PUT)
  @ResponseStatus(value = HttpStatus.OK)
  public void saveModel(@PathVariable String modelId,HttpServletRequest request) {
    String name =request.getParameter("name");
    String description =request.getParameter("description");
    String json_xml =request.getParameter("json_xml");
    String svg_xml =request.getParameter("svg_xml");

      try {

      Model model = repositoryService.getModel(modelId);

      ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());

      modelJson.put(MODEL_NAME, name);
      modelJson.put(MODEL_DESCRIPTION, description);
      model.setMetaInfo(modelJson.toString());
      model.setName(name);

      repositoryService.saveModel(model);

      repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes("utf-8"));

      InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));
      TranscoderInput input = new TranscoderInput(svgStream);

      PNGTranscoder transcoder = new PNGTranscoder();
      // Setup output
      ByteArrayOutputStream outStream = new ByteArrayOutputStream();
      TranscoderOutput output = new TranscoderOutput(outStream);

      // Do the transformation
      transcoder.transcode(input, output);
      final byte[] result = outStream.toByteArray();
      repositoryService.addModelEditorSourceExtra(model.getId(), result);
      outStream.close();

    } catch (Exception e) {
      LOGGER.error("Error saving model", e);
      throw new ActivitiException("Error saving model", e);
    }
  }
}

  

StencilsetRestResource.java

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ***.***.activiti.resource;

import io.swagger.annotations.Api;
import org.activiti.engine.ActivitiException;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.*;

import java.io.InputStream;

/**
 * @author
 */
@RestController
@RequestMapping("/service")
@Api(value = "aciviti-app stencilset", tags = {"获取 stencilset.json"})
@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PUT})
public class StencilsetRestResource {
  
  @RequestMapping(value="/editor/stencilset", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
  public @ResponseBody String getStencilset() {
    InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json");
    try {
      return IOUtils.toString(stencilsetStream, "utf-8");
    } catch (Exception e) {
      throw new ActivitiException("Error while loading stencil set", e);
    }
  }
}

  

4.新增维护模型、流程的接口

SimpleUserTaskApiController.java

package ***.***.activiti7.controller;

import static ***.***.constant.AllocationConstant.APPLICATION_JSON_UTF8;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import javax.annotation.Resource;

import org.activiti.api.task.model.builders.CompleteTaskPayloadBuilder;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import ***.***.activiti7.bean.AssigneeVO;
import ***.***.activiti7.bean.BackReq;
import ***.***.activiti7.bean.BackRsp;
import ***.***.activiti7.bean.BatchBackReq;
import ***.***.activiti7.bean.BatchBackRsp;
import ***.***.activiti7.bean.BatchComplateReq;
import ***.***.activiti7.bean.BatchComplateRsp;
import ***.***.activiti7.bean.BatchStartReq;
import ***.***.activiti7.bean.BatchStartRsp;
import ***.***.activiti7.bean.BatchStopReq;
import ***.***.activiti7.bean.BatchStopRsp;
import ***.***.activiti7.bean.ClaimReq;
import ***.***.activiti7.bean.ClaimRsp;
import ***.***.activiti7.bean.ComplateReq;
import ***.***.activiti7.bean.ComplateRsp;
import ***.***.activiti7.bean.DiagramReq;
import ***.***.activiti7.bean.DiagramRsp;
import ***.***.activiti7.bean.GetInstanceReq;
import ***.***.activiti7.bean.GetInstanceRsp;
import ***.***.activiti7.bean.GetReq;
import ***.***.activiti7.bean.GetRsp;
import ***.***.activiti7.bean.StartReq;
import ***.***.activiti7.bean.StartRsp;
import ***.***.activiti7.bean.StopReq;
import ***.***.activiti7.bean.StopRsp;
import ***.***.activiti7.listeners.ProcessListener;
import ***.***.activiti7.mapper.CommActivityMapper;
import ***.***.activiti7.util.ActivitiUtils;
import ***.***.intf.service.CallService;
import ***.***.security.SecurityUtils;
import ***.***.system.exception.MyExceptionEnum;
import ***.***.user.mapper.UserMapper;
import ***.***.util.Assert;

import lombok.extern.slf4j.Slf4j;
import net.platform.center.exception.BusinessException;

@Slf4j
@RestController
@RequestMapping(path = "/task/", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
public class SimpleUserTaskApiController {
    // #region 属性注入
    private String consUsername = "username";

    /**
     * 流程定义和部署相关的存储服务
     */
    @Autowired
    private RepositoryService repositoryService;

    /**
     * 流程运行时相关的服务
     */
    @Resource
    private RuntimeService runtimeService;

    /**
     * 节点任务相关操作接口
     */
    @Resource
    private TaskService taskService;

    @Resource
    private TaskRuntime taskRuntime;

    /**
     * 历史记录相关服务接口
     */
    @Resource
    private HistoryService historyService;

    @Autowired
    private SecurityUtils securityUtils;

    @Autowired
    private CommActivityMapper commActivityMapper;

    @Autowired
    private CallService callService;

    @Autowired
    private UserMapper userMapper;

    // #endregion

    /**
     * 启动流程实例
     *
     * @param req
     * @return
     */
    @PostMapping(path = "/start", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public StartRsp start(@RequestBody StartReq req) {
        Assert.notNull(req, MyExceptionEnum.INVALID_PARAMETER);
        Assert.notNull(req.getBody().getDeploymentKey(), MyExceptionEnum.INVALID_PARAMETER);
        Assert.notNull(req.getBody().getBusinessKey(), MyExceptionEnum.INVALID_PARAMETER);

        ProcessListener tempProcessListener =
            getProcessListenerByKey(req.getBody().getDeploymentKey(), req.getBody().getBusinessKey());
        Assert.notNull(tempProcessListener, MyExceptionEnum.NULL_ACT_PROCESS_MAPPING);
        Assert.notNull(tempProcessListener.getCommActivity(), MyExceptionEnum.NULL_ACT_PROCESS_MAPPING);

        tempProcessListener.getCommActivity();
        tempProcessListener.setBusinessKey(req.getBody().getBusinessKey());
        if (!tempProcessListener.checkCanStart()) {
            throw new BusinessException(MyExceptionEnum.INVALID_ACT_PROCESS_STATE);
        }

        String username = req.getHeader().get(consUsername);
        securityUtils.logInAs(username);

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .deploymentId(tempProcessListener.getCommActivity().getDeploymentId())
            .singleResult();
        Assert.notNull(processDefinition, MyExceptionEnum.NULL_ACT_PROCESS_DEFINITION);

        ProcessInstance instance = runtimeService.startProcessInstanceById(processDefinition.getId(),
            req.getBody().getBusinessKey(), resetVariables(req.getBody().getVariables()));

        // org.activiti.engine.task.Task tempTask = taskService.createTaskQuery()
        // .processInstanceId(instance.getId())
        // .orderByTaskCreateTime()
        // .desc()
        // .singleResult();

        runtimeService.setProcessInstanceName(instance.getId(), req.getBody().getName());

        // 获取表单属性
        org.activiti.engine.task.Task task = taskService.createTaskQuery()
            .processInstanceId(instance.getId())
            .orderByTaskCreateTime()
            .desc()
            .singleResult();
        // #TODO 待确认是否需要此步骤
        // 是否是没有具体指派人的时候,才需要 setAssignee
        // taskService.setAssignee(task.getId(),username);

        StartRsp rsp = StartRsp.builder()
            .body(StartRsp.StartRspBody.builder()
                .taskId(task.getId())
                .processInstanceId(instance.getId())
                .businessKey(req.getBody().getBusinessKey())
                .build())
            .build();
        return rsp;
    }

    @PostMapping(path = "/batchStart", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public BatchStartRsp batchStart(@RequestBody BatchStartReq req) {
        BatchStartRsp rsp = new BatchStartRsp();

        BatchStartReq.BatchStartReqBody body = req.getBody();
        for (String businessKey : body.getBusinessKeys()) {
            StartReq tempReq = StartReq.builder()
                .body(StartReq.StartReqBody.builder()
                    .businessKey(businessKey)
                    .deploymentKey(body.getDeploymentKey())
                    .name(body.getName())
                    .variables(body.getVariables())
                    .build())
                .build();
            tempReq.setHeader(req.getHeader());
            try {
                StartRsp tempRsp = start(tempReq);
                rsp.getBody().add(tempRsp.getBody());
            } catch (Exception ex) {
                rsp.getBody().add(StartRsp.StartRspBody.builder().businessKey(businessKey).build());
                log.error("循环 start 异常", ex);
            }
        }
        return rsp;
    }

    private HashMap<String, Object> resetVariables(HashMap<String, Object> variables) {
        HashMap<String, Object> newVariables = new HashMap<>();

        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            String key = entry.getKey().replace("-", "_");
            newVariables.put(key, entry.getValue());
        }
        return newVariables;
    }

    /**
     * 根据流程部署Id获取流程信息
     *
     * @param req
     * @return
     */
    @PostMapping(path = "/get", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public GetRsp get(@RequestBody GetReq req) {
        Assert.notNull(req, MyExceptionEnum.INVALID_PARAMETER);

        ProcessListener tempProcessListener = getProcessListenerByKey(req.getBody().getDeploymentKey(), null);
        Assert.notNull(tempProcessListener, MyExceptionEnum.NULL_ACT_PROCESS_MAPPING);
        Assert.notNull(tempProcessListener.getCommActivity(), MyExceptionEnum.NULL_ACT_PROCESS_MAPPING);

        Deployment deployment = repositoryService.createDeploymentQuery()
            .deploymentId(tempProcessListener.getCommActivity().getDeploymentId())
            .singleResult();
        Assert.notNull(deployment, MyExceptionEnum.NULL_ACT_PROCESS_DEFINITION);

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .deploymentId(tempProcessListener.getCommActivity().getDeploymentId())
            .singleResult();
        Assert.notNull(req, MyExceptionEnum.NULL_ACT_PROCESS_DEFINITION);

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        Assert.notNull(req, MyExceptionEnum.NULL_ACT_BPMN_MODEL);

        List<UserTask> allUserTasks = ActivitiUtils.getAllUserTasks(bpmnModel);
        Assert.notNull(allUserTasks, MyExceptionEnum.NULL_ACT_USER_TASK_DEFINITION);

        GetRsp rsp = GetRsp.builder()
            .body(GetRsp.GetRspBody.builder()
                .tasks(new ArrayList<>())
                .formProperties(new ArrayList<>())
                .deploymentId(deployment.getId())
                .deploymentName(deployment.getName())
                .build())
            .build();

        // 设置第一环节审批表单格式
        UserTask firstUserTask = allUserTasks.get(0);
        rsp.getBody().setFormProperties(firstUserTask.getFormProperties());

        for (UserTask userTask : allUserTasks) {
            GetRsp.Task tempTask = GetRsp.Task.builder().id(userTask.getId()).name(userTask.getName()).build();
            if (!CollectionUtils.isEmpty(userTask.getCandidateGroups())) {
                tempTask.setCandidateGroups(userTask.getCandidateGroups());
            } else if (!CollectionUtils.isEmpty(userTask.getCandidateUsers())) {
                // region 设置候选人
                for (String candidateUserName : userTask.getCandidateUsers()) {
                    log.trace("模拟查询用户user,待实现");
                    String name = userMapper.getNameByUserName(candidateUserName);
                    if (!StringUtils.isEmpty(name)) {
                        AssigneeVO candidateAssignee =
                            AssigneeVO.builder().username(candidateUserName).name(name).build();
                        tempTask.getCandidateUsers().add(candidateAssignee);
                    }
                }
                // endregion
            } else if (!StringUtils.isEmpty(userTask.getAssignee()) && !ActivitiUtils.isEl(userTask.getAssignee())) {
                String name = userMapper.getNameByUserName(userTask.getAssignee());
                if (!StringUtils.isEmpty(name)) {
                    AssigneeVO assigneeVO = AssigneeVO.builder().username(userTask.getAssignee()).name(name).build();

                    tempTask.setAssignee(assigneeVO);
                }
            }

            rsp.getBody().getTasks().add(tempTask);
        }

        // String url = String.format(tempProcessListener.getCommActivity().getFormUrl(),
        // req.getBody().getBusinessKey());
        // rsp.getBody().setFormUrl(url);

        return rsp;
    }

    /**
     * 签收
     *
     * @param req
     * @return
     */
    @PostMapping(path = "/claim", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public ClaimRsp claim(@RequestBody ClaimReq req) {
        Assert.notNull(req, MyExceptionEnum.INVALID_PARAMETER);

        String username = req.getHeader().get(consUsername);
        securityUtils.logInAs(username);

        org.activiti.engine.task.Task task =
            taskService.createTaskQuery().taskId(req.getBody().getTaskId()).singleResult();
        Assert.notNull(task, MyExceptionEnum.NULL_ACT_USER_TASK);

        taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(req.getBody().getTaskId()).build());

        return ClaimRsp.builder().body(ClaimRsp.ClaimRspBody.builder().success(true).build()).build();
    }

    /**
     * 驳回
     *
     * @param req
     * @return
     */
    @PostMapping(path = "/back", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public BackRsp back(@RequestBody BackReq req) {
        Assert.notNull(req, MyExceptionEnum.INVALID_PARAMETER);

        org.activiti.engine.task.Task task =
            taskService.createTaskQuery().taskId(req.getBody().getTaskId()).singleResult();
        Assert.notNull(task, MyExceptionEnum.NULL_ACT_USER_TASK);

        String username = req.getHeader().get(consUsername);

        if (!task.getAssignee().equals(username)) {
            throw new BusinessException(MyExceptionEnum.INVALID_PERMISSION);
        }

        securityUtils.logInAs(username);

        String processInstanceId = task.getProcessInstanceId();

        // 取得所有历史任务按时间降序排序
        List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
            .processInstanceId(processInstanceId)
            .orderByTaskCreateTime()
            .desc()
            .list();

        if (ObjectUtils.isEmpty(htiList) || htiList.size() < 2) {
            throw new BusinessException(MyExceptionEnum.ERR_ACT_CAT_NOT_BACK);
        }

        // list里的第二条代表上一个任务
        HistoricTaskInstance lastTask = htiList.get(1);

        // list里第二条代表当前任务
        HistoricTaskInstance curTask = htiList.get(0);

        // 当前节点的executionId
        String curExecutionId = curTask.getExecutionId();

        // 上个节点的taskId
        String lastTaskId = lastTask.getId();
        // 上个节点的executionId
        String lastExecutionId = lastTask.getExecutionId();

        if (StringUtils.isEmpty(lastTaskId)) {
            throw new BusinessException(MyExceptionEnum.ERR_ACT_CAT_NOT_BACK);
        }

        String processDefinitionId = lastTask.getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        String lastActivityId = null;
        List<HistoricActivityInstance> haiFinishedList =
            historyService.createHistoricActivityInstanceQuery().executionId(lastExecutionId).finished().list();

        for (HistoricActivityInstance hai : haiFinishedList) {
            if (lastTaskId.equals(hai.getTaskId())) {
                // 得到ActivityId,只有HistoricActivityInstance对象里才有此方法
                // lastActivityId = hai.getActivityId();
                break;
            }
        }

        // 取得当前节点的信息
        Execution execution = runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult();
        String curActivityId = execution.getActivityId();
        FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId);

        SequenceFlow targetSequenceFlow = curFlowNode.getIncomingFlows().get(0);
        FlowNode targetFlowNode = (FlowNode) curFlowNode.getIncomingFlows().get(0).getSourceFlowElement();
        FlowNode sourceFlowNode = (FlowNode) targetSequenceFlow.getSourceFlowElement();

        // 记录当前节点的原活动方向
        List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
        oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows());

        // 清理活动方向
        curFlowNode.getOutgoingFlows().clear();

        // 建立新方向
        List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("nid_" + UUID.randomUUID().toString().replace("-", "_"));
        newSequenceFlow.setSourceFlowElement(sourceFlowNode);
        newSequenceFlow.setTargetFlowElement(targetFlowNode);
        newSequenceFlowList.add(newSequenceFlow);
        curFlowNode.setOutgoingFlows(newSequenceFlowList);

        // 完成任务
        CompleteTaskPayloadBuilder completeTaskPayloadBuilder = TaskPayloadBuilder.complete().withTaskId(task.getId());

        // 每个环节对应的审批状态,是独立的
        taskService.addComment(task.getId(), task.getProcessInstanceId(), ActivitiUtils.getCommentKey(),
            req.getBody().getComment());

        taskService.addComment(task.getId(), task.getProcessInstanceId(), ActivitiUtils.getApproveKey(),
            String.valueOf(ActivitiUtils.APPROVE_BACK));

        taskRuntime.complete(completeTaskPayloadBuilder.build());

        // 恢复原方向
        curFlowNode.setOutgoingFlows(oriSequenceFlows);

        org.activiti.engine.task.Task nextTask =
            taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();

        // 设置执行人
        if (nextTask != null) {
            taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
        }
        return BackRsp.builder().body(BackRsp.BackRspBody.builder().success(true).build()).build();
    }

    @PostMapping(path = "/batchBack", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public BatchBackRsp batchBack(@RequestBody BatchBackReq req) {
        BatchBackRsp rsp = BatchBackRsp.builder().build();
        for (BatchBackReq.BatchBackBody backReqBody : req.getBody()) {

            org.activiti.engine.task.Task task =
                taskService.createTaskQuery().processInstanceId(backReqBody.getInstanceId()).singleResult();
            if (task == null) {
                rsp.getBody()
                    .add(BatchBackRsp.BatchBackRspBody.builder()
                        .success(false)
                        .instanceId(backReqBody.getInstanceId())
                        .build());
                log.info("流程实例 {} 获取不到 task", backReqBody.getInstanceId());
                continue;
            }

            BackReq tempReq = BackReq.builder()
                .body(BackReq.BackReqBody.builder().taskId(task.getId()).comment(backReqBody.getComment()).build())
                .build();
            tempReq.setHeader(req.getHeader());

            try {
                BackRsp tempRsp = back(tempReq);

                rsp.getBody()
                    .add(BatchBackRsp.BatchBackRspBody.builder()
                        .success(tempRsp.getBody().isSuccess())
                        .instanceId(backReqBody.getInstanceId())
                        .build());
            } catch (Exception ex) {
                rsp.getBody()
                    .add(BatchBackRsp.BatchBackRspBody.builder()
                        .success(false)
                        .instanceId(backReqBody.getInstanceId())
                        .build());
                log.error("循环 complete 异常", ex);
            }
        }
        return rsp;
    }

    /**
     * 終止
     *
     * @param req
     * @return
     */
    @PostMapping(path = "/stop", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public StopRsp stop(@RequestBody StopReq req) {
        Assert.notNull(req, MyExceptionEnum.INVALID_PARAMETER);

        org.activiti.engine.task.Task task =
            taskService.createTaskQuery().processInstanceId(req.getBody().getProcessInstanceId()).singleResult();
        Assert.notNull(task, MyExceptionEnum.NULL_ACT_USER_TASK);

        // String username = req.getHeader().get(consUsername);
        //
        // if (!task.getAssignee().equals(username)) {
        // throw new BusinessException(MyExceptionEnum.INVALID_PERMISSION);
        // }
        String username = task.getAssignee();
        if (StringUtils.isEmpty(username)) {
            Map<String, Object> variables = taskService.getVariables(task.getId());
            String assigneeKey = ActivitiUtils.getAssigneeKey(task.getTaskDefinitionKey());
            if (StringUtils.isEmpty(task.getAssignee()) && variables.containsKey(assigneeKey)) {
                username = variables.get(assigneeKey).toString();
            }
        }
        securityUtils.logInAs(username);

        String processInstanceId = task.getProcessInstanceId();

        // 取得所有历史任务按时间降序排序
        List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
            .processInstanceId(processInstanceId)
            .orderByTaskCreateTime()
            .desc()
            .list();

        // list里第一条代表当前任务
        HistoricTaskInstance curTask = htiList.get(0);
        // 当前节点的executionId
        String curExecutionId = curTask.getExecutionId();

        String processDefinitionId = curTask.getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        // 获取结束的节点信息
        FlowNode endFlowNode = (FlowNode) ActivitiUtils.getEndEventFlowElement(bpmnModel);

        // 取得当前节点的信息
        Execution execution = runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult();
        String curActivityId = execution.getActivityId();
        FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId);

        // 记录当前节点的原活动方向
        List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
        oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows());

        // 清理活动方向
        curFlowNode.getOutgoingFlows().clear();

        // 建立新方向
        List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(curFlowNode);
        newSequenceFlow.setTargetFlowElement(endFlowNode);
        newSequenceFlowList.add(newSequenceFlow);
        curFlowNode.setOutgoingFlows(newSequenceFlowList);

        // 完成任务
        CompleteTaskPayloadBuilder completeTaskPayloadBuilder = TaskPayloadBuilder.complete()
            .withVariable(ActivitiUtils.getApproveKey(), ActivitiUtils.APPROVE_END)
            .withTaskId(task.getId());
        taskRuntime.complete(completeTaskPayloadBuilder.build());

        // 恢复原方向
        curFlowNode.setOutgoingFlows(oriSequenceFlows);

        return StopRsp.builder().body(StopRsp.StopRspBody.builder().success(true).build()).build();
    }

    @PostMapping(path = "/batchStop", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public BatchStopRsp batchStop(@RequestBody BatchStopReq req) {
        BatchStopRsp rsp = BatchStopRsp.builder().build();
        for (StopReq.StopReqBody stopReqBody : req.getBody()) {
            StopReq tempReq = StopReq.builder().body(stopReqBody).build();
            tempReq.setHeader(req.getHeader());

            try {
                StopRsp tempRsp = stop(tempReq);

                rsp.getBody()
                    .add(BatchStopRsp.BatchStopRspBody.builder()
                        .success(tempRsp.getBody().isSuccess())
                        .processInstanceId(stopReqBody.getProcessInstanceId())
                        .build());
            } catch (Exception ex) {
                rsp.getBody()
                    .add(BatchStopRsp.BatchStopRspBody.builder()
                        .success(false)
                        .processInstanceId(stopReqBody.getProcessInstanceId())
                        .build());
                log.error("循环 stop 异常", ex);
            }
        }
        return rsp;
    }

    /**
     * 处理环节
     *
     * @param req
     * @return
     */
    @PostMapping(path = "/batchComplete", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public BatchComplateRsp batchComplete(@RequestBody BatchComplateReq req) {
        BatchComplateRsp rsp = BatchComplateRsp.builder().build();
        for (BatchComplateReq.BatchComplateReqBody complateReqBody : req.getBody()) {

            org.activiti.engine.task.Task task =
                taskService.createTaskQuery().processInstanceId(complateReqBody.getInstanceId()).singleResult();
            if (task == null) {
                rsp.getBody()
                    .add(BatchComplateRsp.BatchComplateRspBody.builder()
                        .success(false)
                        .instanceId(complateReqBody.getInstanceId())
                        .build());
                log.info("流程实例 {} 获取不到 task", complateReqBody.getInstanceId());
                continue;
            }

            ComplateReq tempReq = ComplateReq.builder()
                .body(ComplateReq.ComplateReqBody.builder()
                    .taskId(task.getId())
                    .comment(complateReqBody.getComment())
                    .approve(complateReqBody.getApprove())
                    .build())
                .build();
            tempReq.setHeader(req.getHeader());

            try {
                ComplateRsp tempRsp = complete(tempReq);

                rsp.getBody()
                    .add(BatchComplateRsp.BatchComplateRspBody.builder()
                        .success(tempRsp.getBody().isSuccess())
                        .instanceId(complateReqBody.getInstanceId())
                        .build());
            } catch (Exception ex) {
                rsp.getBody()
                    .add(BatchComplateRsp.BatchComplateRspBody.builder()
                        .success(false)
                        .instanceId(complateReqBody.getInstanceId())
                        .build());
                log.error("循环 complete 异常", ex);
            }
        }
        return rsp;
    }

    /**
     * 处理环节
     *
     * @param req
     * @return
     */
    @PostMapping(path = "/complete", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public ComplateRsp complete(@RequestBody ComplateReq req) {
        Assert.notNull(req, MyExceptionEnum.INVALID_PARAMETER);

        String username = req.getHeader().get(consUsername);
        securityUtils.logInAs(username);

        // TaskImpl task = (TaskImpl)taskRuntime.task(req.getBody().getTaskId());
        TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(req.getBody().getTaskId()).singleResult();
        Assert.notNull(task, MyExceptionEnum.NULL_ACT_USER_TASK);

        Map<String, Object> variables = taskService.getVariables(task.getId());

        String assigneeKey = ActivitiUtils.getAssigneeKey(task.getTaskDefinitionKey());
        if (StringUtils.isEmpty(task.getAssignee()) && variables.containsKey(assigneeKey)) {
            task.setAssignee(variables.get(assigneeKey).toString());
            taskService.setAssignee(task.getId(), variables.get(assigneeKey).toString());
            // taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(req.getBody().getTaskId()).build());
        }

        if (!username.equals(task.getAssignee())) {
            throw new BusinessException(MyExceptionEnum.INVALID_PERMISSION);
        }

        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        Assert.notNull(bpmnModel, MyExceptionEnum.NULL_ACT_BPMN_MODEL);

        CompleteTaskPayloadBuilder completeTaskPayloadBuilder =
            TaskPayloadBuilder.complete().withTaskId(req.getBody().getTaskId());

        // region 表单数据处理
        UserTask userTask = (UserTask) bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        if (userTask.getFormProperties().size() > 0) {
            if (!CollectionUtils.isEmpty(req.getBody().getVariables())) {
                completeTaskPayloadBuilder =
                    completeTaskPayloadBuilder.withVariable(ActivitiUtils.getFormsKey(), req.getBody().getVariables());
            }
        }
        // endregion

        // region 审批意见处理
        if (ActivitiUtils.APPROVE_UN_KNOW != req.getBody().getApprove()) {
            // 此处审批状态和下面审批状态作用不一样,主要给流程的el条件判断使用
            completeTaskPayloadBuilder =
                completeTaskPayloadBuilder.withVariable(ActivitiUtils.getApproveKey(), req.getBody().getApprove());

            if (!StringUtils.isEmpty(req.getBody().getComment())) {
                taskService.addComment(task.getId(), task.getProcessInstanceId(), ActivitiUtils.getCommentKey(),
                    req.getBody().getComment());
            }

            // 每个环节对应的审批状态,是独立的
            taskService.addComment(task.getId(), task.getProcessInstanceId(), ActivitiUtils.getApproveKey(),
                String.valueOf(req.getBody().getApprove()));
        }
        // endregion

        // #TODO 需要看看是否可以将这个写在审批意见处理上面
        taskRuntime.complete(completeTaskPayloadBuilder.build());

        // 不同意时,退回到第一步可能没指派人时处理逻辑
        org.activiti.engine.task.Task newTask =
            taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        if (ActivitiUtils.APPROVE_UN_PASS == req.getBody().getApprove() && StringUtils.isEmpty(newTask.getAssignee())) {
            org.activiti.engine.task.Task task1 = taskService.createTaskQuery().taskId(newTask.getId()).singleResult();
            String assignees = taskService.getVariable(task1.getId(),
                ActivitiUtils.getAssigneeKey(task.getTaskDefinitionKey()), String.class);
            if (!StringUtils.isEmpty(assignees)) {
                taskService.setAssignee(task1.getId(), assignees);
            }
        }

        return ComplateRsp.builder().body(ComplateRsp.ComplateRspBody.builder().success(true).build()).build();
    }

    /**
     * 画流程图
     *
     * @param req
     * @return
     * @throws IOException
     */
    @PostMapping(path = "/diagram", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public DiagramRsp diagram(@RequestBody DiagramReq req) throws IOException {
        Assert.notNull(req, MyExceptionEnum.INVALID_PARAMETER);

        String processDefinitionId = null;
        if (!StringUtils.isEmpty(req.getBody().getDeploymentId())) {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(req.getBody().getDeploymentId())
                .singleResult();
            Assert.notNull(processDefinition, MyExceptionEnum.NULL_ACT_PROCESS_DEFINITION);

            processDefinitionId = processDefinition.getId();
        } else {
            org.activiti.engine.task.Task task =
                taskService.createTaskQuery().processInstanceId(req.getBody().getProcessInstanceId()).singleResult();
            Assert.notNull(task, MyExceptionEnum.NULL_ACT_PROCESS_INSTANCE);

            processDefinitionId = task.getProcessDefinitionId();
        }
        Assert.notNull(processDefinitionId, MyExceptionEnum.NULL_ACT_PROCESS_DEFINITION);

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        Assert.notNull(processDefinitionId, MyExceptionEnum.NULL_ACT_BPMN_MODEL);

        List<HistoricActivityInstance> historicActivityInstanceList = null;
        if (!StringUtils.isEmpty(req.getBody().getProcessInstanceId())) {
            // 构造历史流程查询
            HistoricActivityInstanceQuery historyInstanceQuery = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(req.getBody().getProcessInstanceId());
            // 查询历史节点
            historicActivityInstanceList = historyInstanceQuery.orderByHistoricActivityInstanceStartTime().asc().list();
        }
        InputStream fileOssRecordInputStream = null;
        try {
            fileOssRecordInputStream = ActivitiUtils.getProcessDiagram(bpmnModel, historicActivityInstanceList);
            if (fileOssRecordInputStream != null) {
                String content = IOUtils.toString(fileOssRecordInputStream, StandardCharsets.UTF_8);

                return DiagramRsp.builder().body(DiagramRsp.DiagramRspBody.builder().content(content).build()).build();
            } else {
                throw new BusinessException(MyExceptionEnum.ERR_OPT_FAIL);
            }
        } finally {
            if (fileOssRecordInputStream != null) {
                fileOssRecordInputStream.close();
            }
        }
    }

    /**
     * 查看流程实例信息
     *
     * @param req
     * @return
     */
    @PostMapping(path = "/getInstance", consumes = APPLICATION_JSON_UTF8, produces = APPLICATION_JSON_UTF8)
    @ResponseBody
    public GetInstanceRsp getInstance(@RequestBody GetInstanceReq req) {
        Assert.notNull(req, MyExceptionEnum.INVALID_PARAMETER);

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
            .processInstanceId(req.getBody().getProcessInstanceId())
            .singleResult();
        Assert.notNull(processInstance, MyExceptionEnum.NULL_ACT_PROCESS_INSTANCE);

        org.activiti.engine.task.Task task =
            taskService.createTaskQuery().processInstanceId(req.getBody().getProcessInstanceId()).singleResult();
        Assert.notNull(task, MyExceptionEnum.NULL_ACT_USER_TASK);

        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        Assert.notNull(bpmnModel, MyExceptionEnum.NULL_ACT_BPMN_MODEL);
        UserTask firstUserTask = ActivitiUtils.getFirstUserTasks(bpmnModel);
        Assert.notNull(firstUserTask, MyExceptionEnum.NULL_ACT_USER_TASK);

        List<UserTask> allUserTasks = ActivitiUtils.getAllUserTasks(bpmnModel);
        Assert.notNull(allUserTasks, MyExceptionEnum.NULL_ACT_USER_TASK_DEFINITION);

        GetInstanceRsp.GetInstanceRspBody rspBody = GetInstanceRsp.GetInstanceRspBody.builder()
            .processInstanceId(processInstance.getId())
            .processInstanceName(processInstance.getName())
            .taskId(task.getId())
            .taskName(task.getName())
            .businessKey(task.getBusinessKey())
            .historyTasks(new ArrayList<>())
            .formProperties(firstUserTask.getFormProperties())
            .build();

        Collection<String> vals = new ArrayList<>();
        vals.add(ActivitiUtils.getFormsKey());
        rspBody.setVariables(runtimeService.getVariables(task.getExecutionId()));

        GetInstanceRsp rsp = GetInstanceRsp.builder().body(rspBody).build();

        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
            // 查询结果包括 local变量
            .includeTaskLocalVariables()
            .processInstanceId(processInstance.getId())
            .orderByHistoricTaskInstanceStartTime()
            .asc()
            .list();
        if (!CollectionUtils.isEmpty(historicTaskInstances)) {
            for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) {
                GetInstanceRsp.HistoricTask tempHistoricTask = GetInstanceRsp.HistoricTask.builder()
                    .taskId(historicTaskInstance.getId())
                    .name(historicTaskInstance.getName())
                    .createTime(historicTaskInstance.getCreateTime())
                    .build();

                AssigneeVO tempAssigness = new AssigneeVO();
                if (StringUtils.isEmpty(historicTaskInstance.getAssignee())) {
                    String assigneeKey = ActivitiUtils.getAssigneeKey(historicTaskInstance.getTaskDefinitionKey());
                    tempAssigness.setUsername((String) historicTaskInstance.getTaskLocalVariables().get(assigneeKey));
                } else {
                    tempAssigness.setUsername(historicTaskInstance.getAssignee());
                }
                String name = userMapper.getNameByUserName(tempAssigness.getUsername());
                if (!StringUtils.isEmpty(name)) {
                    tempAssigness.setName(name);
                }

                tempHistoricTask.setAssignee(tempAssigness);

                // 获取comment
                Optional<org.activiti.engine.task.Comment> commentOptional =
                    taskService.getTaskComments(historicTaskInstance.getId(), ActivitiUtils.getCommentKey())
                        .stream()
                        .findFirst();
                if (commentOptional.isPresent()) {
                    tempHistoricTask.setComment(commentOptional.get().getFullMessage());
                }

                // 获取approve
                Optional<org.activiti.engine.task.Comment> approveOptional =
                    taskService.getTaskComments(historicTaskInstance.getId(), ActivitiUtils.getApproveKey())
                        .stream()
                        .findFirst();
                if (approveOptional.isPresent()) {
                    tempHistoricTask.setApprove(Integer.parseInt(approveOptional.get().getFullMessage()));
                }

                rspBody.getHistoryTasks().add(tempHistoricTask);
            }
        }
        Deployment deployment =
            repositoryService.createDeploymentQuery().deploymentId(processInstance.getDeploymentId()).singleResult();
        Assert.notNull(deployment, MyExceptionEnum.NULL_ACT_USER_TASK);

        // ProcessListener tempProcessListener =
        // getProcessListenerByKey(deployment.getKey(), req.getBody().getBusinessKey());
        // if (tempProcessListener != null) {
        // String url =
        // String.format(tempProcessListener.getCommActivity().getFormUrl(), req.getBody().getBusinessKey());
        // rsp.getBody().setFormUrl(url);
        // }
        return rsp;
    }

    private ProcessListener getProcessListenerByKey(String deploymentKey, String businessKey) {
        ProcessListener customProcessListener = ProcessListener.builder()
            .deploymentKey(deploymentKey)
            .businessKey(businessKey)
            .commActivityMapper(commActivityMapper)
            .callService(callService)
            .build();
        return customProcessListener;
    }
}

  

ProcessesApiController.java

package ***.***.activiti.controller;


import com.bootdo.activiti.command.DeleteDeploymentCommand;
import com.bootdo.activiti.command.DeploymentByResourceCommand;
import com.bootdo.activiti.command.DeploymentByZipCommand;
import com.bootdo.activiti.command.SearchProcesseCommand;
import com.bootdo.activiti.enums.CommonResponseEnum;
import com.bootdo.activiti.interfaces.model.JsonResult;
import com.bootdo.activiti.interfaces.model.JsonResultPage;
import com.bootdo.activiti.model.CopyDeploymentToModel;
import com.bootdo.activiti.model.DeploymentResponseModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipInputStream;

@RestController
@RequestMapping(value = "/activiti/processes/api/",method = RequestMethod.POST)
@Api(value = "processes", tags = {"流程接口"})
@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PUT})
public class ProcessesApiController {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProcessesApiController.class);

    /**
     * 流程定义和部署相关的存储服务
     */
    @Resource
    RepositoryService repositoryService;

    @RequestMapping("/deploymentByResource")
    @ApiOperation(value = "发布流程",notes = "项目内部资源文件部署")
    public JsonResult deploymentByResource(@RequestBody DeploymentByResourceCommand command)
    {
        if(command==null || StringUtils.isEmpty(command.getName()) || StringUtils.isEmpty(command.getBpmpResourcePath()))
            return JsonResult.error(CommonResponseEnum.Invalid_Parameter);
        
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();

        //创建Deployment对象
        deploymentBuilder = deploymentBuilder.addClasspathResource(command.getBpmpResourcePath());

        //添加png文件
        if(!StringUtils.isEmpty(command.getPngResourcePath()))
            deploymentBuilder = deploymentBuilder.addClasspathResource(command.getPngResourcePath());

        //部署
        Deployment deployment = deploymentBuilder.name(command.getName()).key(command.getKey()).deploy();
        return JsonResult.success(deployment);
    }

    @RequestMapping("/categories")
    @ApiOperation(value = "流程分类",notes = "获取所有流程分类")
    public JsonResult categories()
    {
        List<String> categories = new ArrayList<String>(){
            {
                add("事假");
                add("病假");
                add("会议");
                add("出差");
            }
        };
        return JsonResult.success(categories);
    }

    @RequestMapping("/deploymentByZipFile")
    @ApiOperation(value = "发布流程",notes = "外部 zip 文件部署")
    public JsonResult deploymentByZipFile(@RequestBody DeploymentByZipCommand command) throws IOException {
        if(command==null || StringUtils.isEmpty(command.getName()) || StringUtils.isEmpty(command.getZipFilePath()))
            return JsonResult.error(CommonResponseEnum.Invalid_Parameter);
        
        InputStream in=null;
        ZipInputStream zipInputStream=null;
        try {
            in = new FileInputStream(new File(command.getZipFilePath()));
            zipInputStream = new ZipInputStream(in);
            Deployment deployment = repositoryService.createDeployment().name(command.getName())
                    // 指定zip格式的文件完成部署
                    .addZipInputStream(zipInputStream).deploy();// 完成部署
            return JsonResult.success(deployment);
        }
        finally {
            if(in!=null)
            {
                zipInputStream.close();
            }
        }
    }

    /**
     * 删除已经部署的流程定义
     * 影响的activiti表有哪些
     *   act_re_deployment 部署信息
     *   act_re_procdef    流程定义的一些信息
     *   act_ge_bytearray  流程定义的bpmn文件以及png文件
     **/
    @RequestMapping("/delete")
    @ApiOperation(value = "删除已经部署的流程定义")
    public JsonResult delete(@RequestBody DeleteDeploymentCommand command)
    {
        if(command==null || StringUtils.isEmpty(command.getDeploymentId()))
            return JsonResult.error(CommonResponseEnum.Invalid_Parameter);
        

        //删除流程定义 参数表述流程部署id 可以通过查询部署的信息得到流程部署id
        repositoryService.deleteDeployment(command.getDeploymentId(),command.isCascade());
        return JsonResult.success();
    }

    @RequestMapping("/list")
    @ApiOperation(value = "查询已部署的流程",notes = "List<Deployment>")
    public JsonResultPage list(@RequestBody SearchProcesseCommand command)
    {
        if(command==null)
            return JsonResultPage.error(CommonResponseEnum.Invalid_Parameter);

        DeploymentQuery query = repositoryService.createDeploymentQuery().orderByDeploymentName().desc();

        if(!StringUtils.isEmpty(command.getName()))
            query = query.deploymentName(command.getName());
        if(!StringUtils.isEmpty(command.getKey()))
            query = query.processDefinitionKey(command.getKey());
        if(!StringUtils.isEmpty(command.getCategory()))
            query = query.deploymentCategory(command.getCategory());

        long total = query.count();

        List<Deployment> deployments = query.orderByDeploymentName().asc()
                .listPage((command.getPage()-1)*command.getLimit(),command.getLimit());

        List<DeploymentResponseModel> processResponseModels = new ArrayList<>();
        for (Deployment deployment : deployments) {
            processResponseModels.add(
                    new DeploymentResponseModel(){
                        {
                            setDeploymentId(deployment.getId());
                            setName(deployment.getName());
                            setDeploymentTime(deployment.getDeploymentTime());
                            setCategory(deployment.getCategory());
                            setKey(deployment.getKey());
                            setTenantId(deployment.getTenantId());
                        }
                    }
            );
        }

        return new JsonResultPage<>(processResponseModels,total,command.getLimit());
    }

    @RequestMapping("/copyToModel")
    @ApiOperation(value = "复制已部署的流程模型")
    public JsonResult copToModel(@RequestBody CopyDeploymentToModel command) throws IOException {
        Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(command.getDeploymentId()).singleResult();
        if(deployment==null)
        {
            return JsonResult.error(CommonResponseEnum.Deployment_NotFind);
        }
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(command.getDeploymentId()).singleResult();
        if(processDefinition==null)
        {
            return JsonResult.error(CommonResponseEnum.ProcessDefinition_NotFind);
        }
        BpmnModel bpmnModel =repositoryService.getBpmnModel(processDefinition.getId());
        if(processDefinition==null)
        {
            return JsonResult.error(CommonResponseEnum.BpmnModel_NotFind);
        }

        Model modelData = repositoryService.newModel();
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode modelObjectNode =  objectMapper.createObjectNode();
        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, deployment.getName());
        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
        modelData.setMetaInfo(modelObjectNode.toString());
        modelData.setName( deployment.getName());
        modelData.setKey(deployment.getKey());
        modelData.setCategory(deployment.getCategory());
        modelData.setVersion(1);
        //保存模型
        repositoryService.saveModel(modelData);

        //保存模型对应的流程图json
        BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
        ObjectNode objectNode = bpmnJsonConverter.convertToJson(bpmnModel);
        repositoryService.addModelEditorSource(modelData.getId(), objectNode.toString().getBytes("utf-8"));
        return JsonResult.success(modelData.getId());
    }
}

  

5.服务接口

SimpleUserTaskApiController.java

package ***.***.activiti.controller;

import com.bootdo.activiti.command.*;
import com.bootdo.activiti.enums.CommonResponseEnum;
import com.bootdo.activiti.enums.GlobalExceptionResponseEnum;
import com.bootdo.activiti.interfaces.model.JsonResult;
import com.bootdo.activiti.interfaces.model.JsonResultPage;
import com.bootdo.system.domain.DeptDO;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.EventListener;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;

@RestController
@RequestMapping(value = "/activiti/model/api/",method = RequestMethod.POST)
@Api(value = "model", tags = {"模型接口"})
@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PUT})
public class ModelApiController {
    /**
     * 流程定义和部署相关的存储服务
     */
    @Resource
    RepositoryService repositoryService;

    private static final Logger LOGGER = LoggerFactory.getLogger(ModelApiController.class);

    /**
     * 创建模型
     */
    @RequestMapping("/create")
    public JsonResult apiCreate(@RequestBody CreateModelCommand command) {
        if(command==null || StringUtils.isEmpty(command.getName()) || StringUtils.isEmpty(command.getKey()))
            return JsonResult.error(CommonResponseEnum.Invalid_Parameter);
//        securityUtils.logInAs(command.getOperatedByUserName());
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            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);
            Model modelData = repositoryService.newModel();

            ObjectNode modelObjectNode = objectMapper.createObjectNode();
            modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, command.getName());
            modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
            modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, command.getDescription());
            modelData.setMetaInfo(modelObjectNode.toString());
            modelData.setName( command.getName());
            modelData.setKey(command.getKey());
            modelData.setCategory(command.getCategory());

            //保存模型
            repositoryService.saveModel(modelData);
            repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));
            return JsonResult.success(modelData.getId());
        } catch (Exception e) {
            LOGGER.error("创建模型错误",e);
            return JsonResult.error(GlobalExceptionResponseEnum.RuntimeException);
        }
    }

    /**
     * 查询模型列表
     * @param command
     * @return
     */
    @RequestMapping("/list")
    public JsonResultPage<Model> apiList(@RequestBody SearchModelCommand command)
    {
        if(command==null)
            return JsonResultPage.error(CommonResponseEnum.Invalid_Parameter);

        ModelQuery modelQuery =repositoryService.createModelQuery().orderByModelCategory().desc();
        if(!StringUtils.isEmpty(command.getName()))
            modelQuery = modelQuery.modelName(command.getName());
        if(!StringUtils.isEmpty(command.getKey()))
            modelQuery = modelQuery.modelKey(command.getKey());
        if(!StringUtils.isEmpty(command.getCategory()))
            modelQuery = modelQuery.modelCategory(command.getCategory());
        long total = modelQuery.count();
        List<Model> modelList = modelQuery.listPage((command.getPage()-1)*command.getLimit(),command.getLimit());
        return new JsonResultPage(modelList,total,command.getLimit());
    }

    /**
     * 删除模型
     * @param command
     * @return
     */
    @RequestMapping("/delete")
    public JsonResult apiDelete(@RequestBody DeleteModelCommand command)
    {
        if(command==null || StringUtils.isEmpty(command.getModelId()))
            return JsonResult.error(CommonResponseEnum.Invalid_Parameter);
//        securityUtils.logInAs(command.getOperatedByUserName());
        repositoryService.deleteModel(command.getModelId());
        return JsonResult.success();
    }

    /**
     * 发布模型
     * @param command
     * @return
     */
    @RequestMapping("/deployment")
    public JsonResult apiDeployment(@RequestBody DeploymentModelCommand command) throws Exception
    {
        if(command==null || StringUtils.isEmpty(command.getModelId()))
            return JsonResult.error(CommonResponseEnum.Invalid_Parameter);
//        securityUtils.logInAs(command.getOperatedByUserName());

        //获取模型
        Model modelData = repositoryService.getModel(command.getModelId());
        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
        if (bytes == null) {
            LOGGER.info("模型数据为空,请先设计流程并成功保存,再进行发布。");
            return JsonResult.error(CommonResponseEnum.Model_NotFind);
        }

        JsonNode modelNode = new ObjectMapper().readTree(bytes);

        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(modelNode);
        List<Process> processes = bpmnModel.getProcesses();
        if (CollectionUtils.isEmpty(processes)) {
            LOGGER.info("数据模型不符要求,请至少设计一条主线流程。");
            return JsonResult.error(CommonResponseEnum.Model_LeastOneMainProcess);
        }
        for (Process process: processes) {

        }

        byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(bpmnModel);

        if(!command.isIgnoreDuplicates())
        {
            int rows = repositoryService.createProcessDefinitionQuery().processDefinitionKey(modelData.getKey()).list().size();
            if(rows>0)
            {
                return JsonResult.error(CommonResponseEnum.Duplicate_key);
            }
        }

        //发布流程
        String processName = modelData.getName() + ".bpmn20.xml";
       Deployment deployment = repositoryService.createDeployment()
                .name(modelData.getName())
                .key(modelData.getKey())
                .category(StringUtils.isEmpty(modelData.getCategory())?"其它":modelData.getCategory())
                .addString(processName, new String(bpmnBytes, "UTF-8"))
                .deploy();

        //发布完毕,删除模型
        if(command.isDeleteModel())
            repositoryService.deleteModel(command.getModelId());

        return JsonResult.success(deployment);
    }
}

  

6.自定义全局侦听器

CustomGlobalActivitiEventListener.java

package ***.***.activiti7.listeners;

import java.util.Date;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.delegate.event.ActivitiEntityEvent;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventListener;
import org.activiti.engine.delegate.event.ActivitiProcessStartedEvent;
import org.activiti.engine.delegate.event.impl.ActivitiEntityEventImpl;
import org.activiti.engine.delegate.event.impl.ActivitiEntityWithVariablesEventImpl;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import ***.***.activiti7.mapper.CommActivityMapper;
import ***.***.activiti7.util.ActivitiUtils;
import ***.***.intf.service.CallService;

import net.platform.center.util.ApplicationContextHolder;

/**
 * @ClassName WsjActivitiEventListener
 * @Description: 全局
 * @Author wsj
 * @Date 2020/8/19
 **/
@Component
public class CustomGlobalActivitiEventListener implements ActivitiEventListener {
    /**
     * 流程定义和部署相关的存储服务
     * 不自动注入,是应为油循环依赖问题
     */

    @Override
    public void onEvent(ActivitiEvent activitiEvent) {
        ProcessListener processListener;
        switch (activitiEvent.getType()) {
            // 流程开始
            case PROCESS_STARTED:

                if (activitiEvent instanceof ActivitiProcessStartedEvent) {
                    ExecutionEntity executionEntity =
                        (ExecutionEntity) ((ActivitiProcessStartedEvent) activitiEvent).getEntity();

                    processListener = getProcessListener(activitiEvent);
                    if (processListener == null) {
                        break;
                    }

                    if (executionEntity.getTasks().size() != 1) {
                        break;
                    }

                    processListener.instanceId = activitiEvent.getProcessInstanceId();
                    processListener.businessKey = executionEntity.getTasks().get(0).getBusinessKey();
                    processListener.taskName = "发起审批";
                    processListener.state = 1;

                    TaskEntity taskEntity = executionEntity.getTasks().get(0);
                    if (StringUtils.isEmpty(taskEntity.getAssignee())) {
                        String key = ActivitiUtils.getAssigneeKey(taskEntity.getTaskDefinitionKey());
                        processListener.by = processListener.nextBy = (String) taskEntity.getVariable(key);
                        taskEntity.setAssignee(processListener.by);
                    } else {
                        processListener.by = processListener.nextBy = executionEntity.getTasks().get(0).getAssignee();
                    }
                    processListener.at = new Date();
                    processListener.processStarted(executionEntity);
                }

                break;
            case PROCESS_COMPLETED:
                processListener = getProcessListener(activitiEvent);
                if (processListener == null) {
                    break;
                }

                if (activitiEvent instanceof ActivitiEntityEvent) {
                    ActivitiEntityEvent activitiEntityEvent = (ActivitiEntityEvent) activitiEvent;
                    ExecutionEntity executionEntity = (ExecutionEntity) activitiEntityEvent.getEntity();

                    processListener.instanceId = activitiEvent.getProcessInstanceId();
                    processListener.businessKey = executionEntity.getBusinessKey();
                    processListener.at = executionEntity.getStartTime();
                    // .get(executionEntity.getIdentityLinks().size() - 1)
                    // .getUserId();
                    int approve = (int) executionEntity.getVariable(ActivitiUtils.getApproveKey());
                    if (approve == ActivitiUtils.APPROVE_PASS) {
                        // #TODO 需要判断是通过还是不通过,不过目前是单线程,到达终止节点,就表示通过
                        processListener.taskName = "审批通过";
                        processListener.state = 2;
                    } else if (approve == ActivitiUtils.APPROVE_UN_PASS) {
                        // #TODO 需要判断是通过还是不通过,不过目前是单线程,到达终止节点,就表示通过
                        processListener.taskName = "审批不通过";
                        processListener.state = 3;
                    } else if (approve == ActivitiUtils.APPROVE_END) {
                        // #TODO 需要判断是通过还是不通过,不过目前是单线程,到达终止节点,就表示通过
                        processListener.taskName = "审批终止";
                        processListener.state = 4;
                        processListener.nextBy = null;
                    } else {
                        processListener.taskName = "未知";
                        processListener.state = 5;
                    }
                    // 一定要 getCommActivity(),不然没值
                    processListener.getCommActivity();
                    processListener.processCompleted(executionEntity);
                }
                break;
            case TASK_CREATED:
                if (activitiEvent instanceof ActivitiEntityEventImpl) {
                    processListener = getProcessListener(activitiEvent);
                    if (processListener == null) {
                        break;
                    }

                    ActivitiEntityEventImpl entityEvent = (ActivitiEntityEventImpl) activitiEvent;
                    TaskEntityImpl taskEntity = (TaskEntityImpl) entityEvent.getEntity();
                    processListener.instanceId = activitiEvent.getProcessInstanceId();
                    processListener.businessKey = taskEntity.getBusinessKey();

                    if (StringUtils.isEmpty(taskEntity.getAssignee())) {
                        String key = ActivitiUtils.getAssigneeKey(taskEntity.getTaskDefinitionKey());
                        processListener.nextBy = (String) taskEntity.getVariable(key);
                        taskEntity.setAssignee(processListener.nextBy);
                    } else {
                        processListener.nextBy = taskEntity.getAssignee();
                    }
                    processListener.taskCreated(taskEntity);
                }
                break;
            case TASK_COMPLETED:
                if (activitiEvent instanceof ActivitiEntityWithVariablesEventImpl) {
                    processListener = getProcessListener(activitiEvent);
                    if (processListener == null) {
                        break;
                    }

                    ActivitiEntityWithVariablesEventImpl entityEvent =
                        (ActivitiEntityWithVariablesEventImpl) activitiEvent;
                    TaskEntity taskEntity = (TaskEntity) entityEvent.getEntity();

                    processListener.instanceId = activitiEvent.getProcessInstanceId();
                    processListener.businessKey = taskEntity.getBusinessKey();
                    processListener.at = taskEntity.getCreateTime();
                    if (StringUtils.isEmpty(taskEntity.getAssignee())) {
                        processListener.by = ActivitiUtils.getAssigneeKey(taskEntity.getTaskDefinitionKey());
                    } else {
                        processListener.by = taskEntity.getAssignee();
                    }
                    processListener.taskName = taskEntity.getName();
                    int approve = (int) taskEntity.getVariable(ActivitiUtils.getApproveKey());
                    switch (approve) {
                        case ActivitiUtils.APPROVE_BACK:
                            processListener.state = 5;
                            break;
                        case ActivitiUtils.APPROVE_END:
                            processListener.state = 4;
                            processListener.nextBy = null;
                            processListener.taskName = "审批终止";
                            break;
                        default:
                            processListener.state = 1;
                            break;
                    }

                    processListener.taskCompleted(taskEntity);
                }
                break;
            default:
                break;
        }
    }

    private RepositoryService getRepositoryService() {
        return ApplicationContextHolder.getBean(RepositoryService.class);
    }

    private CommActivityMapper getCommActivityMapper() {
        return ApplicationContextHolder.getBean(CommActivityMapper.class);
    }

    private CallService getCallService() {
        return ApplicationContextHolder.getBean(CallService.class);
    }

    private ProcessListener getProcessListener(ActivitiEvent activitiEvent) {
        RepositoryService repositoryService = getRepositoryService();
        if (repositoryService == null) {
            return null;
        }

        // 获取流程定义
        ProcessDefinition processDefinition =
            repositoryService.getProcessDefinition(activitiEvent.getProcessDefinitionId());
        if (processDefinition == null) {
            return null;
        }

        Deployment deployment =
            repositoryService.createDeploymentQuery().deploymentId(processDefinition.getDeploymentId()).singleResult();
        if (deployment == null) {
            return null;
        }
        ProcessListener processListener = new ProcessListener();
        processListener.setCommActivityMapper(getCommActivityMapper());
        processListener.setCallService(getCallService());
        processListener.setDeploymentKey(deployment.getKey());
        return processListener;
    }

    /**
     * 这个是必须要的,监听异常处理策略
     *
     * @return
     */
    @Override
    public boolean isFailOnException() {
        return false;
    }
}

  

业务列表中,需要显示目前是在哪个审批环节,各位根据自己实际业务看看是否需要

 

CustomerActivitiConfig.java

package ***.***.activiti7;

import java.util.ArrayList;
import java.util.List;

import org.activiti.engine.delegate.event.ActivitiEventListener;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ***.***.activiti7.listeners.CustomGlobalActivitiEventListener;

@Component
public class CustomerActivitiConfig implements ProcessEngineConfigurationConfigurer {
    @Autowired
    private CustomGlobalActivitiEventListener customGlobalActivitiEventListener;

    @Override
    public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {

        List<ActivitiEventListener> eventListeners = new ArrayList<>();
        eventListeners.add(customGlobalActivitiEventListener);
        springProcessEngineConfiguration.setEventListeners(eventListeners);
    }
}

  

IProcessListener.java

package ***.***.activiti7.listeners;

import java.text.ParseException;
import java.util.Date;

import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;

import ***.***.activiti7.bean.CommActivityPO;
import ***.***.intf.service.CallService;

public interface IProcessListener {
    // #region 属性、变量
    // String getKeyFileName();
    String getInstanceId();

    String getBusinessKey();

    Integer getState();

    String getTaskName();

    String getBy();

    String getNextBy();

    Date getAt();

    CommActivityPO getCommActivity();

    String getDeploymentKey();
    // #endregion

    // #region 方法
    CallService getCallService();

    /**
     * 流程开始
     */
    void processStarted(ExecutionEntity executionEntity);

    /**
     * 流程结束
     */
    void processCompleted(ExecutionEntity executionEntity) throws ParseException;

    /**
     * 任务完成
     */
    void taskCompleted(TaskEntity taskEntity);

    /**
     * 任务创建
     */
    void taskCreated(TaskEntity taskEntity);

    /**
     * 检查是否允许开启流程
     *
     * @return
     */
    boolean checkCanStart();
    // #endregion
}

  

ProcessListener.java

package ***.***.activiti7.listeners;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.persistence.entity.VariableInstance;
import org.springframework.context.annotation.Scope;
import org.springframework.http.ResponseEntity;

import ***.***.activiti7.bean.CallBackReq;
import ***.***.activiti7.bean.CallBackRsp;
import ***.***.activiti7.bean.CommActivityPO;
import ***.***.activiti7.mapper.CommActivityMapper;
import ***.***.intf.service.CallService;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.platform.center.util.JsonUtil;

@Slf4j
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Scope("prototype")
public class ProcessListener implements IProcessListener {

    // /**
    // * 主键字段名
    // */
    // protected String keyFileName;

    /**
     * 流程实例ID
     */
    protected String instanceId;

    /**
     * 业务数据主键
     */
    protected String businessKey;

    /**
     * 审批状态
     * 1:发起审批
     * 2:审批通过
     * 3:审批不通过
     * 4:审批终止
     * 5:退回
     * 6:未知
     */
    protected Integer state;

    /**
     * 当前环节
     */
    protected String taskName;

    /**
     * 本环节审批人
     */
    protected String by;

    /**
     * 下一个环节审批人
     */
    protected String nextBy;

    /**
     * 审批时间
     */
    protected Date at;

    private String deploymentKey;

    private CommActivityPO commActivity;

    private CommActivityMapper commActivityMapper;

    private CallService callService;

    @Override
    public CommActivityPO getCommActivity() {
        if (commActivity == null) {
            commActivity = commActivityMapper.get(deploymentKey);
        }
        return commActivity;
    }

    @Override
    public void processStarted(ExecutionEntity executionEntity) {
        commActivityMapper.processStarted(this);
        if (getCommActivity() != null && getCommActivity().isProcessStartedCallBack()) {
            CallBackRsp callBackRsp = callBack("processStartedCallBackUrl", executionEntity.getProcessVariables());
            // #TODO 判断 CallBackRsp,输出日志
            log.info("processStarted processStartedCallBackUrl: {}", callBackRsp.toString());
        }
    }

    @Override
    public void processCompleted(ExecutionEntity executionEntity) {
        commActivityMapper.processCompleted(this);

        if (getCommActivity() != null && getCommActivity().isProcessCompletedCallBack()) {

            Map<String, VariableInstance> variableInstances = executionEntity.getVariableInstances();

            Map<String, Object> data = new HashMap<>();
            // 1. entrySet遍历,在键和值都需要时使用(最常用)
            for (Map.Entry<String, VariableInstance> entry : variableInstances.entrySet()) {
                data.put(entry.getKey(), entry.getValue().getValue());
            }

            CallBackRsp callBackRsp = callBack("processCompletedCallBackUrl", data);

            log.info("processCompleted processCompletedCallBackUrl: {}", JsonUtil.toJsonString(callBackRsp));
        }
    }

    @Override
    public void taskCompleted(TaskEntity taskEntity) {
        commActivityMapper.taskCompleted(this);
        if (getCommActivity() != null && getCommActivity().isTaskCompletedCallBack()) {
            CallBackRsp callBackRsp = callBack("taskCompletedCallBackUrl", taskEntity.getVariables());
            // #TODO 判断 CallBackRsp,输出日志
            log.info("taskCompleted taskCompletedCallBackUrl: {}", JsonUtil.toJsonString(callBackRsp));
        }
    }

    @Override
    public void taskCreated(TaskEntity taskEntity) {
        commActivityMapper.taskCreated(this);
    }

    @Override
    public boolean checkCanStart() {
        // 检查后是否已经发起了审批
        int result = commActivityMapper.getProcessStarted(this);
        if (result == 1) {
            return false;
        }

        CallBackReq callBackReq = CallBackReq.builder()
            .body(CallBackReq.CallBackReqBody.builder()
                .deploymentKey(this.deploymentKey)
                .businessKey(this.businessKey)
                .build())
            .build();

        if (getCommActivity() != null && getCommActivity().isCheckCanStartCallBack()) {
            CallBackRsp callBackRsp = callBack("checkCanStartCallBackUrl", callBackReq);
            return "1".equals(callBackRsp.getCode());
        } else {
            return true;
        }
    }

    private CallBackRsp callBack(String serviceName, Object data) {
        CallBackReq req = CallBackReq.builder()
            .body(CallBackReq.CallBackReqBody.builder()
                .businessKey(businessKey)
                .deploymentKey(deploymentKey)
                .data(data)
                .build())
            .build();

        ResponseEntity<CallBackRsp> responseEntity = callService.callService(serviceName, req, CallBackRsp.class);
        log.info("callService req: {}", req.toString());
        log.info("callService rsp: {}", JsonUtil.toJsonString(responseEntity));
        return responseEntity.getBody();
    }

    @Override
    public String toString() {
        return "ProcessListener(instanceId=" + instanceId + ", businessKey=" + businessKey + ", state=" + state
            + ", taskName=" + taskName + ", by=" + by + ", nextBy=" + nextBy + ", at=" + at + ", deploymentKey="
            + deploymentKey + ")";
    }
}

 

 

工作流配置表

 

posted @ 2022-03-22 17:09  hujunmin  阅读(712)  评论(0编辑  收藏  举报