在spring boot中应用activiti 7设计流程的简单示例

一、首先要准备bpmn20流程图文件,网上有许多教程,通过eclipse或IDEA里安装插件后绘制bpmn20流程图文件,但是尝试后都不成功,绘制出来的图不适用于activiti。我的做法是去github下载老版本的activiti 6的本地运行包,放入tomcat 8服务器中运行(只能用tomcat 8和JDK 8,不能用tomcat 9或更高版本的JDK),然后在网页上绘制bpmn20流程图,这里示例绘制的图形如下。最左边的圆圈是起始点,中间两个方框是流程任务,带叉叉的小方框是排他网关,最后一个粗线圆圈是终点。流程的过程是发起者提交申请,由审批者审批,如果审批通过,则此次流程结束,如果审批未通过,则返回申请者处理后再重新审批……

二、上面的流程图对应的XML文件如下。文件中两个userTask都有对应的activiti:assignee,分别user1和user2,这需要在后续程序文件中动态指定处理人。两条带有pass参数的流程线路,在后续程序中设定pass的值,以确定程序流向,当pass==true时,表示同意,流程走向结束。当pass==false时,表示否决,流程返回申请人处理。

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
  <process id="a001" name="Secflow" isExecutable="true">
    <documentation>testflow</documentation>
    <startEvent id="startEvent1"></startEvent>
    <userTask id="sid-4E5653ED-FF4F-4FDB-9C4B-835BD40439BA" name="申请" activiti:assignee="${user1}"></userTask>
    <userTask id="sid-E4082E2D-5165-4592-85C9-095ECE3B4D0B" name="审批" activiti:assignee="${user2}">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[true]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <exclusiveGateway id="sid-C9B1043E-9EA2-47C6-89BC-52B382032169"></exclusiveGateway>
    <endEvent id="sid-0BA9A21E-7468-418A-B2FE-6EDC3DF291A6"></endEvent>
    <sequenceFlow id="sid-17294149-37C9-4B77-A4CC-2105E5BE1570" sourceRef="startEvent1" targetRef="sid-4E5653ED-FF4F-4FDB-9C4B-835BD40439BA"></sequenceFlow>
    <sequenceFlow id="sid-A1C9E05F-85A2-4248-BCB4-236A88CC1E32" sourceRef="sid-E4082E2D-5165-4592-85C9-095ECE3B4D0B" targetRef="sid-C9B1043E-9EA2-47C6-89BC-52B382032169"></sequenceFlow>
    <sequenceFlow id="sid-A52B6933-64F9-425F-AF54-52581AF49882" sourceRef="sid-4E5653ED-FF4F-4FDB-9C4B-835BD40439BA" targetRef="sid-E4082E2D-5165-4592-85C9-095ECE3B4D0B"></sequenceFlow>
    <sequenceFlow id="sid-10C1260A-8A36-4481-8FB2-C9B8912B6696" name="同意" sourceRef="sid-C9B1043E-9EA2-47C6-89BC-52B382032169" targetRef="sid-0BA9A21E-7468-418A-B2FE-6EDC3DF291A6">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="sid-B23CC9E8-3BC2-4411-ABF1-1974DD175BAD" name="拒绝" sourceRef="sid-C9B1043E-9EA2-47C6-89BC-52B382032169" targetRef="sid-4E5653ED-FF4F-4FDB-9C4B-835BD40439BA">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_a001">
    <bpmndi:BPMNPlane bpmnElement="a001" id="BPMNPlane_a001">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="75.0" y="105.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-4E5653ED-FF4F-4FDB-9C4B-835BD40439BA" id="BPMNShape_sid-4E5653ED-FF4F-4FDB-9C4B-835BD40439BA">
        <omgdc:Bounds height="80.0" width="100.0" x="195.0" y="80.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-E4082E2D-5165-4592-85C9-095ECE3B4D0B" id="BPMNShape_sid-E4082E2D-5165-4592-85C9-095ECE3B4D0B">
        <omgdc:Bounds height="80.0" width="100.0" x="435.0" y="80.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-C9B1043E-9EA2-47C6-89BC-52B382032169" id="BPMNShape_sid-C9B1043E-9EA2-47C6-89BC-52B382032169">
        <omgdc:Bounds height="40.0" width="40.0" x="675.0" y="100.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-0BA9A21E-7468-418A-B2FE-6EDC3DF291A6" id="BPMNShape_sid-0BA9A21E-7468-418A-B2FE-6EDC3DF291A6">
        <omgdc:Bounds height="28.0" width="28.0" x="866.5" y="102.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-B23CC9E8-3BC2-4411-ABF1-1974DD175BAD" id="BPMNEdge_sid-B23CC9E8-3BC2-4411-ABF1-1974DD175BAD">
        <omgdi:waypoint x="695.5" y="139.5"></omgdi:waypoint>
        <omgdi:waypoint x="695.5" y="223.0"></omgdi:waypoint>
        <omgdi:waypoint x="245.0" y="223.0"></omgdi:waypoint>
        <omgdi:waypoint x="245.0" y="160.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-17294149-37C9-4B77-A4CC-2105E5BE1570" id="BPMNEdge_sid-17294149-37C9-4B77-A4CC-2105E5BE1570">
        <omgdi:waypoint x="105.0" y="120.0"></omgdi:waypoint>
        <omgdi:waypoint x="195.0" y="120.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-10C1260A-8A36-4481-8FB2-C9B8912B6696" id="BPMNEdge_sid-10C1260A-8A36-4481-8FB2-C9B8912B6696">
        <omgdi:waypoint x="714.9736842105264" y="120.02631578947368"></omgdi:waypoint>
        <omgdi:waypoint x="866.5041398722801" y="116.34043984094454"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-A1C9E05F-85A2-4248-BCB4-236A88CC1E32" id="BPMNEdge_sid-A1C9E05F-85A2-4248-BCB4-236A88CC1E32">
        <omgdi:waypoint x="535.0" y="120.0"></omgdi:waypoint>
        <omgdi:waypoint x="675.0" y="120.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-A52B6933-64F9-425F-AF54-52581AF49882" id="BPMNEdge_sid-A52B6933-64F9-425F-AF54-52581AF49882">
        <omgdi:waypoint x="295.0" y="120.0"></omgdi:waypoint>
        <omgdi:waypoint x="435.0" y="120.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

三、pom.xml里引入activit相关依赖、spring boot相关依赖、mysql相关依赖以及mybatis相关依赖

<!--spring boot基础依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mysql依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--mysql相关依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--activiti基本依赖-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.1.0.M3.1</version>
        </dependency>
        <!--activiti生成流程图的依赖-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-image-generator</artifactId>
            <version>5.22.0</version>
        </dependency>
        <!--spring内置tomcat依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!--spring测试依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--mybatis相关依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <!--xml文件解释(mybatis需要)相关依赖-->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
        </dependency>
View Code

四、编写程序的配置类,在配置类里设定两个用户。

@org.springframework.context.annotation.Configuration
@EnableWebSecurity
public class Configuration extends WebSecurityConfigurerAdapter {

    @Autowired
    RoleInterface role;

    @Override
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService());
    }

    @Bean
    public UserDetailsService myUserDetailsService(){
        InMemoryUserDetailsManager inMemoryUserDetailsManager=new InMemoryUserDetailsManager();
        String[][] usersGroupsAndRoles={
                {"zgy","123","ROLE_ACTIVITI_USER","GROUP_activitiTraining"},
                {"testuser","123","ROLE_ACTIVITI_USER","GROUP_activitiTraining"},
                {"system","123","ROLE_ACTIVITI_USER"},
                {"admin","123","ROLE_ACTIVITI_ADMIN"},
        };
        for(String[] user: usersGroupsAndRoles){
            List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user,2,user.length));

            inMemoryUserDetailsManager.createUser(new User(user[0],passwordEncoder().encode(user[1]),authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
        }
        return inMemoryUserDetailsManager;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic();
    }
}
View Code

五、编写一个启动流程实例的控制类,启动一个流程实例,指定了user1和user2的审批人分别为testuser和zgy。

@RequestMapping("/activiti") //以登陆的用户名启动新的流程实例,并输出流程id
    public String getprocess(){
        String instanceKey = "a001";

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();

        Map<String, Object> map = new HashMap<String, Object>();
 
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        map.put("userId", user.getUsername());
        map.put("user1","testuser");
        map.put("user2","zgy");
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceKey, map);
        System.out.println("启动流程实例成功:{}"+instance.getId());
 instance.getProcessDefinitionId());
        return "流程新实例启动成功,实例id:"+instance.getId();
        }
View Code

六、编写一个审批通过类,审批通过当前用户任务列表中的第一个任务

@RequestMapping("/completetask") //根据任务id完成指定任务,通过
        public String completetask(){
            User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            String name=user.getUsername();
            List<Task> assigneeList = processEngine.getTaskService()
                    .createTaskQuery()//指定个人任务查询
                    .taskAssignee(name)
                    .list();
            Map<String, Object> map=new HashMap<>();
            map.put("pass",true); //任务完成指定参数,审批通过是true
            TaskService taskService=processEngine.getTaskService();
           taskService.complete(assigneeList.get(0).getId(),map);
        return name+"完成任务,审批通过:"+assigneeList.get(0).getId();
    }

七、编写一个审批拒绝类,拒绝当前用户列表中的第一个任务

 @RequestMapping("/deny") //根据任务id完成指定任务,拒绝
    public String complete(){
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String name=user.getUsername();
        List<Task> assigneeList = processEngine.getTaskService()
                .createTaskQuery()//指定个人任务查询
                .taskAssignee(name)
                .list();
        Map<String, Object> map=new HashMap<>();
        map.put("pass",false); //任务完成指定参数,审批不通过是false
        TaskService taskService=processEngine.getTaskService();
        taskService.complete(assigneeList.get(0).getId(),map);
        return name+"拒绝申请";
    }

 

posted @ 2021-11-16 16:47  wwwzgy  阅读(725)  评论(0)    收藏  举报