springboot集成工作流引擎(Springboot整合Flowable实现工作流在线编辑)
springboot集成工作流引擎(Springboot整合Flowable实现工作流在线编辑)flowable-engine-flowable-6.4.0\modules\flowable-ui-modeler\flowable-ui-modeler-rest\src\main\java\org\flowable\ui\modeler\rest\app\StencilSetResource.java复制下面文件到Springboot项目中的自定义的conf目录,这个文件是Modeler汉化的组件,由于该类的实例会注入到Spring的容器中去,所以为了避免和原来的文件产生的bean冲突,需要重新命名,这里命名为FlowableStencilSetResource.java。复制下面两个文件到Springboot项目中的自定义的conf目录,这两个文件是启动中必要的配置文件,需要做修改,具体的修改在下面会有描述。flowable-engine-flowable-6.4.0\module
1 项目准备1.1 新建一个Springboot项目Springboot采用的版本是2.1.5.RELEASE;
Flowable采用的版本是6.4.0。
1.2 项目的pom文件<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dream21th</groupId>
<artifactId>flowable-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>flowable-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<mysql.version>5.1.38</mysql.version>
<flowable.version>6.4.0</flowable.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.flowable/flowable-ui-modeler-logic -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-modeler-logic</artifactId>
<version>6.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.flowable/flowable-ui-modeler-conf -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-ui-modeler-conf</artifactId>
<version>6.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.3 Flowable Modeler UI下载
登录网址github,找到6.4.0版本,https://github.com/flowable/flowable-engine/tree/flowable-6.4.0,下载文件。
文件下载完成后,进入到flowable-engine-flowable-6.4.0\modules\flowable-ui-modeler\flowable-ui-modeler-app\src\main\resources\目录,将static文件夹下面的内容复制到Springboot项目resources资源下面的static目录下面。
2 后端代码2.1 复制代码复制下面两个文件到Springboot项目中的自定义的conf目录,这两个文件是启动中必要的配置文件,需要做修改,具体的修改在下面会有描述。
flowable-engine-flowable-6.4.0\modules\flowable-ui-modeler\flowable-ui-modeler-conf\src\main\java\org\flowable\ui\modeler\conf\ApplicationConfiguration.java
flowable-engine-flowable-6.4.0\modules\flowable-ui-modeler\flowable-ui-modeler-conf\src\main\java\org\flowable\ui\modeler\servlet\AppDispatcherServletConfiguration.java
复制下面文件到Springboot项目中的自定义的conf目录,这个文件是Modeler汉化的组件,由于该类的实例会注入到Spring的容器中去,所以为了避免和原来的文件产生的bean冲突,需要重新命名,这里命名为FlowableStencilSetResource.java。
flowable-engine-flowable-6.4.0\modules\flowable-ui-modeler\flowable-ui-modeler-rest\src\main\java\org\flowable\ui\modeler\rest\app\StencilSetResource.java
同时有两个配置文件需要复制到Springboot项目的resources路径下面,在resources下面新建目录stencilset。
这两个配置文件是stencilset_bpmn.json,stencilset_cmmn.json。
复制flowable-engine-flowable-6.4.0\modules\flowable-ui-common\src\main\java\org\flowable\ui\common\security\SecurityUtils.java到Springboot项目下面的org.flowable.ui.common.security包下面,注意这个文件必须放到和源文件相同的包目录下,所以在Springboot项目下会建一个org.flowable.ui.common.security包。
2.2 代码修改ApplicationConfiguration修改为:
/* 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 com.dream21th.flowable.demo.conf;
import org.flowable.ui.common.service.idm.RemoteIdmService;
import org.flowable.ui.modeler.properties.FlowableModelerAppProperties;
import org.flowable.ui.modeler.servlet.ApiDispatcherServletConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
@Configuration
@EnableConfigurationProperties(FlowableModelerAppProperties.class)
@ComponentScan(basePackages = {
// "org.flowable.ui.modeler.conf"
"org.flowable.ui.modeler.repository"
"org.flowable.ui.modeler.service"
// "org.flowable.ui.modeler.security" //授权方面的都不需要
// "org.flowable.ui.common.conf" // flowable 开发环境内置的数据库连接
// "org.flowable.ui.common.filter" // IDM 方面的过滤器
"org.flowable.ui.common.service"
"org.flowable.ui.common.repository"
//
// "org.flowable.ui.common.security" //授权方面的都不需要
"org.flowable.ui.common.tenant" } excludeFilters = {
// 移除 RemoteIdmService
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE value = RemoteIdmService.class)
}
)
public class ApplicationConfiguration {
@Bean
public ServletRegistrationBean modelerApiServlet(ApplicationContext applicationContext) {
AnnotationConfigWebApplicationContext dispatcherServletConfiguration = new AnnotationConfigWebApplicationContext();
dispatcherServletConfiguration.setParent(applicationContext);
dispatcherServletConfiguration.register(ApiDispatcherServletConfiguration.class);
DispatcherServlet servlet = new DispatcherServlet(dispatcherServletConfiguration);
ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet "/api/*");
registrationBean.setName("Flowable Modeler App API Servlet");
registrationBean.setLoadOnStartup(1);
registrationBean.setAsyncSupported(true);
return registrationBean;
}
}
AppDispatcherServletConfiguration修改为:
/* 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 com.dream21th.flowable.demo.conf;
import org.flowable.ui.modeler.rest.app.EditorGroupsResource;
import org.flowable.ui.modeler.rest.app.EditorUsersResource;
import org.flowable.ui.modeler.rest.app.StencilSetResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
@ComponentScan(value = { "org.flowable.ui.modeler.rest.app"
// 不加载 rest,因为 getAccount 接口需要我们自己实现
// "org.flowable.ui.common.rest"
} excludeFilters = {
// 移除 EditorUsersResource 与 EditorGroupsResource,因为不使用 IDM 部分
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE value = EditorUsersResource.class)
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE value = EditorGroupsResource.class)
// 配置文件用自己的
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE value = StencilSetResource.class)
}
)
@EnableAsync
public class AppDispatcherServletConfiguration implements WebMvcRegistrations {
private static final Logger LOGGER = LoggerFactory.getLogger(AppDispatcherServletConfiguration.class);
@Bean
public SessionLocaleResolver localeResolver() {
return new SessionLocaleResolver();
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LOGGER.debug("Configuring localeChangeInterceptor");
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("language");
return localeChangeInterceptor;
}
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
LOGGER.debug("Creating requestMappingHandlerMapping");
RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();
requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
requestMappingHandlerMapping.setRemoveSemicolonContent(false);
Object[] interceptors = { localeChangeInterceptor() };
requestMappingHandlerMapping.setInterceptors(interceptors);
return requestMappingHandlerMapping;
}
}
SecurityUtils修改为,目前是通过getCurrentUserObject方法获得一个固定用户。
/* 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 org.flowable.ui.common.security;
import org.flowable.idm.api.User;
import org.flowable.ui.common.model.RemoteUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class for Spring Security.
*/
public class SecurityUtils {
private static User assumeUser;
private SecurityUtils() {
}
/**
* Get the login of the current user.
*/
public static String getCurrentUserId() {
User user = getCurrentUserObject();
if (user != null) {
return user.getId();
}
return null;
}
/**
* @return the {@link User} object associated with the current logged in user.
*/
public static User getCurrentUserObject() {
if (assumeUser != null) {
return assumeUser;
}
RemoteUser user = new RemoteUser();
user.setId("admin");
user.setDisplayName("Administrator");
user.setFirstName("Administrator");
user.setLastName("Administrator");
user.setEmail("admin@flowable.com");
user.setPassword("123456");
List<String> pris = new ArrayList<>();
pris.add(DefaultPrivileges.ACCESS_MODELER);
pris.add(DefaultPrivileges.ACCESS_IDM);
pris.add(DefaultPrivileges.ACCESS_ADMIN);
pris.add(DefaultPrivileges.ACCESS_TASK);
pris.add(DefaultPrivileges.ACCESS_REST_API);
user.setPrivileges(pris);
return user;
}
public static FlowableAppUser getCurrentFlowableAppUser() {
FlowableAppUser user = null;
SecurityContext securityContext = SecurityContextHolder.getContext();
if (securityContext != null && securityContext.getAuthentication() != null) {
Object principal = securityContext.getAuthentication().getPrincipal();
if (principal instanceof FlowableAppUser) {
user = (FlowableAppUser) principal;
}
}
return user;
}
public static boolean currentUserHasCapability(String capability) {
FlowableAppUser user = getCurrentFlowableAppUser();
for (GrantedAuthority grantedAuthority : user.getAuthorities()) {
if (capability.equals(grantedAuthority.getAuthority())) {
return true;
}
}
return false;
}
public static void assumeUser(User user) {
assumeUser = user;
}
public static void clearAssumeUser() {
assumeUser = null;
}
}
2.3 新增代码
新增一个FlowableController 里面有一个接口/login/rest/account 目的是在加载页面时候会调用这个接口获取用户信息,由于我们绕过了登陆,因此给个默认的用户 admin。
package com.dream21th.flowable.demo.controller;
import org.flowable.ui.common.model.UserRepresentation;
import org.flowable.ui.common.security.DefaultPrivileges;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/login")
public class FlowableController {
/**
* 获取默认的管理员信息
* @return
*/
@RequestMapping(value = "/rest/account" method = RequestMethod.GET produces = "application/json")
public UserRepresentation getAccount() {
UserRepresentation userRepresentation = new UserRepresentation();
userRepresentation.setId("admin");
userRepresentation.setEmail("admin@flowable.org");
userRepresentation.setFullName("Administrator");
// userRepresentation.setLastName("Administrator");
userRepresentation.setFirstName("Administrator");
List<String> privileges = new ArrayList<>();
privileges.add(DefaultPrivileges.ACCESS_MODELER);
privileges.add(DefaultPrivileges.ACCESS_IDM);
privileges.add(DefaultPrivileges.ACCESS_ADMIN);
privileges.add(DefaultPrivileges.ACCESS_TASK);
privileges.add(DefaultPrivileges.ACCESS_REST_API);
userRepresentation.setPrivileges(privileges);
return userRepresentation;
}
}
修改resource\static\scripts\configuration\url-conf.js中的getAccountUrl中的地址修改为:
getAccountUrl: function () {
return FLOWABLE.CONFIG.contextRoot '/login/rest/account';
}
修改Springboot启动类为:
package com.dream21th.flowable.demo;
import com.dream21th.flowable.demo.conf.AppDispatcherServletConfiguration;
import com.dream21th.flowable.demo.conf.ApplicationConfiguration;
import org.flowable.ui.modeler.conf.DatabaseConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration;
import org.springframework.context.annotation.Import;
//启用全局异常拦截器
@Import(value={
// 引入修改的配置
ApplicationConfiguration.class
AppDispatcherServletConfiguration.class
// 引入 DatabaseConfiguration 表更新转换
DatabaseConfiguration.class})
// 移除 Security 自动配置
// Spring Cloud 为 Finchley 版本
// @SpringBootApplication(exclude={SecurityAutoConfiguration.class})
// Spring Cloud 为 Greenwich 版本
@SpringBootApplication(exclude={SecurityAutoConfiguration.class ManagementWebSecurityAutoConfiguration.class SecurityFilterAutoConfiguration.class})
public class FlowableDemoApplication{
public static void main(String[] args) {
SpringApplication.run(FlowableDemoApplication.class args);
}
}
application.yml配置文件为:
server:
port: 8989
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/test02?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&nullCatalogMeansCurrent=true
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
flowable:
async-executor-activate: false
database-schema-update: false
3 启动项目
看到的流程图是导入进去的,xml文件为:
<?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/test">
<collaboration id="Collaboration">
<participant id="pool1" name="披萨网络订单流程" processRef="pizza-online"></participant>
</collaboration>
<process id="PIZZA" name="披萨订单流程" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
</process>
<process id="pizza-online" name="披萨电话订单流程" isExecutable="true">
<laneSet id="laneSet_pizza-online">
<lane id="lane1" name="接受订单">
<flowNodeRef>startevent1</flowNodeRef>
<flowNodeRef>phone-resever</flowNodeRef>
<flowNodeRef>assign-order</flowNodeRef>
</lane>
<lane id="lane2" name="制作披萨">
<flowNodeRef>prepare-pizza</flowNodeRef>
<flowNodeRef>cook-pizza</flowNodeRef>
<flowNodeRef>package-pizza</flowNodeRef>
</lane>
<lane id="lane3" name="快递收款">
<flowNodeRef>deliver-pizza</flowNodeRef>
<flowNodeRef>recive-pay</flowNodeRef>
<flowNodeRef>endevent1</flowNodeRef>
</lane>
</laneSet>
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="phone-resever" name="电话预定"></userTask>
<userTask id="assign-order" name="分配订单"></userTask>
<userTask id="prepare-pizza" name="准备披萨"></userTask>
<userTask id="cook-pizza" name="烹饪披萨"></userTask>
<userTask id="package-pizza" name="打包披萨"></userTask>
<userTask id="deliver-pizza" name="快递披萨"></userTask>
<serviceTask id="recive-pay" name="收到付款" activiti:class="com.study.demo.demo28.ServiceTaskClass"></serviceTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="phone-resever"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="phone-resever" targetRef="assign-order"></sequenceFlow>
<sequenceFlow id="flow3" sourceRef="assign-order" targetRef="prepare-pizza"></sequenceFlow>
<sequenceFlow id="flow4" sourceRef="prepare-pizza" targetRef="cook-pizza"></sequenceFlow>
<sequenceFlow id="flow5" sourceRef="cook-pizza" targetRef="package-pizza"></sequenceFlow>
<sequenceFlow id="flow6" sourceRef="package-pizza" targetRef="deliver-pizza"></sequenceFlow>
<sequenceFlow id="flow7" sourceRef="deliver-pizza" targetRef="recive-pay"></sequenceFlow>
<sequenceFlow id="flow8" sourceRef="recive-pay" targetRef="endevent1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_Collaboration">
<bpmndi:BPMNPlane bpmnElement="Collaboration" id="BPMNPlane_Collaboration">
<bpmndi:BPMNShape bpmnElement="pool1" id="BPMNShape_pool1">
<omgdc:Bounds height="470.0" width="680.0" x="30.0" y="100.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane1" id="BPMNShape_lane1">
<omgdc:Bounds height="156.0" width="660.0" x="50.0" y="100.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane2" id="BPMNShape_lane2">
<omgdc:Bounds height="156.0" width="660.0" x="50.0" y="256.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="lane3" id="BPMNShape_lane3">
<omgdc:Bounds height="156.0" width="660.0" x="50.0" y="412.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="70.0" y="140.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="phone-resever" id="BPMNShape_phone-resever">
<omgdc:Bounds height="55.0" width="105.0" x="140.0" y="130.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="assign-order" id="BPMNShape_assign-order">
<omgdc:Bounds height="55.0" width="105.0" x="290.0" y="130.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="prepare-pizza" id="BPMNShape_prepare-pizza">
<omgdc:Bounds height="55.0" width="105.0" x="290.0" y="306.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="cook-pizza" id="BPMNShape_cook-pizza">
<omgdc:Bounds height="55.0" width="105.0" x="420.0" y="306.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="package-pizza" id="BPMNShape_package-pizza">
<omgdc:Bounds height="55.0" width="105.0" x="560.0" y="306.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="deliver-pizza" id="BPMNShape_deliver-pizza">
<omgdc:Bounds height="55.0" width="105.0" x="560.0" y="462.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="recive-pay" id="BPMNShape_recive-pay">
<omgdc:Bounds height="55.0" width="105.0" x="430.0" y="462.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="140.0" y="472.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="105.0" y="157.0"></omgdi:waypoint>
<omgdi:waypoint x="140.0" y="157.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="245.0" y="157.0"></omgdi:waypoint>
<omgdi:waypoint x="290.0" y="157.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="342.0" y="185.0"></omgdi:waypoint>
<omgdi:waypoint x="342.0" y="306.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
<omgdi:waypoint x="395.0" y="333.0"></omgdi:waypoint>
<omgdi:waypoint x="420.0" y="333.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
<omgdi:waypoint x="525.0" y="333.0"></omgdi:waypoint>
<omgdi:waypoint x="560.0" y="333.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
<omgdi:waypoint x="612.0" y="361.0"></omgdi:waypoint>
<omgdi:waypoint x="612.0" y="462.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
<omgdi:waypoint x="560.0" y="489.0"></omgdi:waypoint>
<omgdi:waypoint x="535.0" y="489.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
<omgdi:waypoint x="430.0" y="489.0"></omgdi:waypoint>
<omgdi:waypoint x="175.0" y="489.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
项目结构:
项目结构
码云地址:https://gitee.com/dream21th/flowbale-demo