springboot整合flowable工作流初体验

1.添加两个依赖:

   <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-spring-boot-starter</artifactId>
        <version>6.7.2</version>
    </dependency>

  <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

2.application.yml 文件添加数据库链接配置

3.启动项目
启动完成后会生成工作流相关的表

4.idea安装工作流插件-Flowable BPMN visualizer

5.画流程图

首先在resources资源目录下新建 processes目录,然后新建一个.bpmn20的xml文件

然后在xml文件右键选择 View BPMN(Flowable) Diagram 画流程图。
在 View BPMN(Flowable) Diagram 界面右键选择对应的实践,流程,角色等。我完成的一个请假流程图如下:

流程走向判断的地方需要输入变量判断条件:

注意: 现在启动可能回报如下错误:
[Validation set: 'flowable-executable-process' | Problem: 'flowable-servicetask-missing-implementation'] : One of the attributes 'class', 'delegateExpression', 'type', 'operation', or 'expression' is mandatory on serviceTask. - [Extra info : processDefinitionId = ask_for_leave | processDefinitionName = ask_for_leave | | id = sid-84a802b7-3136-43f3-b076-b2cb83639175 | | activityName = 发送失败提示 | ] ( line: 26, column: 131)

这是因为serviceTask节点需要 'class', 'delegateExpression', 'type', 'operation', or 'expression'其中一个属性,我这里添加了class属性:flowable:class="com.example.demo.listener.FailHandler"。
当审核拒绝或驳回的时候会回调或者说触发这个类。

public class FailHandler implements JavaDelegate {

    @Override
    public void execute(DelegateExecution delegateExecution) {
        String name = delegateExecution.getVariable("name").toString();
        String rejectReason = delegateExecution.getVariable("rejectReason").toString();
        System.out.println(name+"你的请假申请被驳回了,原因是:"+rejectReason);
  

}
}
我这里只是简单的打印一下请假人名称和和驳回的原因。这里面的variable属性在整个流程没有结束期间都可以设置和获取。``
6.开启一个流程
我这里写一个单元测试来启动一个请假流程:

  @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;

    private String headman = "8888";

    private String manager = "9999";

    /**
     * 开启一个请假流程
     * @param userId
     * @return
     */
    @RequestMapping("startProcess")
    public String startProcess(String userId){
        Map<String,Object> params = new HashMap<>();
        params.put("user",userId);
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("askforleave", params);
        runtimeService.setVariable(instance.getProcessInstanceId(),"name","张大炮");
        runtimeService.setVariable(instance.getProcessInstanceId(),"reason","去医院看病");
        runtimeService.setVariable(instance.getProcessInstanceId(),"days","10");
        return instance.getProcessInstanceId();
    }

创建请假流程 ,返回流程id: 868704fb-0317-11ed-a8eb-4c796e57fe35

ProcessInstance instance = runtimeService.startProcessInstanceByKey("askforleave", params); 这里的流程实例"askforleave" 是生成的流程图xml文件的process 的id

7.查看当前流程进度

  @GetMapping("/pic")
   public void showPic(HttpServletResponse response,String processId){
       ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
       if(null == instance){
           return;
       }
       List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(processId).list();
       List<String> activeIds = new ArrayList<>();
       List<String> flows = new ArrayList<>();
       for (Execution execution : executions) {
           List<String> activeActivityIds = runtimeService.getActiveActivityIds(execution.getId());
           activeIds.addAll(activeActivityIds);
       }
       /**
        * 生成流程图
        */
       BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
       ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
       ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
       InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activeIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, false);
       OutputStream out = null;
       byte[] buf = new byte[1024];
       int legth = 0;
       try {
           out = response.getOutputStream();
           while ((legth = in.read(buf)) != -1) {
               out.write(buf, 0, legth);
           }
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           if (in != null) {
               try {
                   in.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
           if (out != null) {
               try {
                   out.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
   }

接着调用这个接口会看到生成的流程图

可以看到流程当前处于员工请假阶段
可能会出现流程图中文乱码情况,需要在项目中增加如下配置:

@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {

    @Override
    public void configure(SpringProcessEngineConfiguration con) {
        //防止生成的流程图中中文乱码
        con.setActivityFontName("宋体");
        con.setLabelFontName("宋体");
        con.setAnnotationFontName("宋体");
    }

}

8.提交请假申请到下一步给组长审批

 /**
     * 提交给组长审批
     * @param processId
     * @return
     */
    @RequestMapping(value = "submit")
    public String submit(String userId,String processId) {
        Task task  = taskService.createTaskQuery().taskAssignee(userId).processInstanceId(processId).singleResult();
        if (task == null) {
            return "流程不存在";
        }
        //通过审核
        HashMap<String, Object> map = new HashMap<>();
        map.put("headman",headman);
        taskService.complete(task.getId(), map);
        return "processed ok!";
    }

map里的headman是在流程图的时候设置的:

意思是提交给下一步谁来审核处理,关于 assignee,Candidate Users和 Candidate Groups可以百度一下。
9.查看代办任务

/**
   * 获取审批管理列表
   */
  @RequestMapping(value = "/list")
  public String list(String assignee) {
      List<Task> tasks = taskService.createTaskQuery().taskAssignee(assignee).orderByTaskCreateTime().desc().list();
      String  result = "";
      for (Task task : tasks) {
          result += "processId:"+task.getProcessInstanceId()+" taskId: "+task.getId()+" name: "+task.getName()+" assignee: "+task.getAssignee()+" owner:"+task.getOwner()+"\n";
      }
      return result;
  }


组长 8888 有两条代办任务,选择其中一条任务id 进行审核,下一步组长审核,通过或者拒绝。
10.组长审核

   /**
     * 组长审核通过
     * @param taskId
     * @return
     */
    @RequestMapping(value = "leaderApply")
    public String leaderApply(String taskId) {
        Task task  = taskService.createTaskQuery().taskAssignee(headman).taskId(taskId).singleResult();
        if(task == null){
            task = taskService.createTaskQuery().taskId(taskId).singleResult();
        }
        //   Task
        if (task == null) {
           return "流程不存在";
        }
        //通过审核
        HashMap<String, Object> map = new HashMap<>();
        map.put("audit", "通过");
        map.put("manager",manager);
        taskService.complete(task.getId(), map);
        return "processed ok!";
    }

map里有两个值, audit == 通过,表示审核通过,在步骤5中有过说明。 manager == manager表示下一步提交给manger审核。

这里的表示受理人是谁。
然后可以调用步骤7的查看流程图接口看到当前流程已经走到了经理审核阶段。
11.经理审核
先调用步骤9接口传入上一步设置的manager的值可以查看经理代办任务,可以看到经理的代办任务id(taskId),然后进行审核。

    /**
     * 经理审核驳回
     * @param taskId
     * @return
     */
    @RequestMapping(value = "managerReject")
    public String managerReject(String taskId) {
        Task task  = taskService.createTaskQuery().taskAssignee(manager).taskId(taskId).singleResult();
        //   Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            return "流程不存在";
        }
        //通过审核
        HashMap<String, Object> map = new HashMap<>();
        map.put("audit", "驳回");
        taskService.setVariable(task.getId(),"rejectReason","理由不充分");
        taskService.complete(task.getId(), map);
        return "processed ok!";
    }

拒绝之后会发送系统消息。也就是步骤5最后的说明。最后流程结束。

posted @   threadThread  阅读(1961)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示