在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>
四、编写程序的配置类,在配置类里设定两个用户。
@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(); } }
五、编写一个启动流程实例的控制类,启动一个流程实例,指定了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();
}
六、编写一个审批通过类,审批通过当前用户任务列表中的第一个任务
@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+"拒绝申请";
}
浙公网安备 33010602011771号