Commit 7bfead66 by stylefeng

移除flowable,升级spring boot 2.0

parent bd04afe2
# Guns V3.2 # Guns V3.2
## 介绍 ## 介绍
Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + mybatis-plus + beetl + flowable!Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作为一个后台管理系统的脚手架! 2018目标 `更简洁`,`更规范`! Guns基于SpringBoot,致力于做更简洁的后台管理系统,完美整合springmvc + shiro + mybatis-plus + beetl!Guns项目代码简洁,注释丰富,上手容易,同时Guns包含许多基础模块(用户管理,角色管理,部门管理,字典管理等10个模块),可以直接作为一个后台管理系统的脚手架! 2018目标 `更简洁`,`更规范`!
Guns v3.0新增rest api服务,提供对接服务端接口的支持,并利用jwt token鉴权机制给予客户端的访问权限,传输数据进行md5签名保证传输过程数据的安全性! Guns v3.0新增rest api服务,提供对接服务端接口的支持,并利用jwt token鉴权机制给予客户端的访问权限,传输数据进行md5签名保证传输过程数据的安全性!
Guns v3.1新增集成工作流引擎flowable6.2.0!
## 最新Guns技术文档 ## 最新Guns技术文档
Guns框架有作者在业余时间整理的技术文档,详情点击[查看详情](https://gitee.com/naan1993/guns/wikis/pages?title=Guns%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3&parent=) Guns框架有作者在业余时间整理的技术文档,详情点击[查看详情](https://gitee.com/naan1993/guns/wikis/pages?title=Guns%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3&parent=)
......
...@@ -19,22 +19,6 @@ ...@@ -19,22 +19,6 @@
<dependencies> <dependencies>
<!--flowable-->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-basic</artifactId>
<exclusions>
<exclusion>
<artifactId>mybatis</artifactId>
<groupId>org.mybatis</groupId>
</exclusion>
<exclusion>
<artifactId>activation</artifactId>
<groupId>javax.activation</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency> <dependency>
<groupId>com.stylefeng</groupId> <groupId>com.stylefeng</groupId>
<artifactId>guns-core</artifactId> <artifactId>guns-core</artifactId>
...@@ -145,14 +129,6 @@ ...@@ -145,14 +129,6 @@
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <configuration>
...@@ -166,6 +142,7 @@ ...@@ -166,6 +142,7 @@
</resource> </resource>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<filtering>true</filtering>
</resource> </resource>
<resource> <resource>
<directory>src/main/java</directory> <directory>src/main/java</directory>
......
/* /*
Navicat MySQL Data Transfer Navicat MySQL Data Transfer
Source Server : 本地 Source Server : localhost
Source Server Version : 50621 Source Server Version : 50721
Source Host : localhost:3306 Source Host : localhost:3306
Source Database : guns Source Database : guns
Target Server Type : MYSQL Target Server Type : MYSQL
Target Server Version : 50621 Target Server Version : 50721
File Encoding : 65001 File Encoding : 65001
Date: 2017-12-10 11:34:35 Date: 2018-06-26 23:10:40
*/ */
DROP DATABASE IF EXISTS guns_flowable; DROP DATABASE IF EXISTS guns_flowable;
...@@ -48,34 +48,32 @@ INSERT INTO `sys_dept` VALUES ('26', '3', '24', '[0],[24],', '运营部', '运 ...@@ -48,34 +48,32 @@ INSERT INTO `sys_dept` VALUES ('26', '3', '24', '[0],[24],', '运营部', '运
INSERT INTO `sys_dept` VALUES ('27', '4', '24', '[0],[24],', '战略部', '战略部', '', null); INSERT INTO `sys_dept` VALUES ('27', '4', '24', '[0],[24],', '战略部', '战略部', '', null);
-- ---------------------------- -- ----------------------------
-- ----------------------------
-- Table structure for sys_dict -- Table structure for sys_dict
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `sys_dict`; DROP TABLE IF EXISTS `sys_dict`;
CREATE TABLE `sys_dict` ( CREATE TABLE `sys_dict` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键id', `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
`num` int(11) NULL DEFAULT NULL COMMENT '排序', `num` int(11) DEFAULT NULL COMMENT '排序',
`pid` int(11) NULL DEFAULT NULL COMMENT '父级字典', `pid` int(11) DEFAULT NULL COMMENT '父级字典',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称', `name` varchar(255) DEFAULT NULL COMMENT '名称',
`tips` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '提示', `tips` varchar(255) DEFAULT NULL COMMENT '提示',
`code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '值', `code` varchar(255) DEFAULT NULL COMMENT '值',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 69 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '字典表' ROW_FORMAT = Dynamic; ) ENGINE=InnoDB AUTO_INCREMENT=69 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='字典表';
-- ---------------------------- -- ----------------------------
-- Records of sys_dict -- Records of sys_dict
-- ---------------------------- -- ----------------------------
INSERT INTO `sys_dict` VALUES (50, 0, 0, '性别', NULL, 'sys_sex'); INSERT INTO `sys_dict` VALUES ('50', '0', '0', '性别', null, 'sys_sex');
INSERT INTO `sys_dict` VALUES (51, 1, 50, '男', NULL, '1'); INSERT INTO `sys_dict` VALUES ('51', '1', '50', '男', null, '1');
INSERT INTO `sys_dict` VALUES (52, 2, 50, '女', NULL, '2'); INSERT INTO `sys_dict` VALUES ('52', '2', '50', '女', null, '2');
INSERT INTO `sys_dict` VALUES (53, 0, 0, '状态', NULL, 'sys_state'); INSERT INTO `sys_dict` VALUES ('53', '0', '0', '状态', null, 'sys_state');
INSERT INTO `sys_dict` VALUES (54, 1, 53, '启用', NULL, '1'); INSERT INTO `sys_dict` VALUES ('54', '1', '53', '启用', null, '1');
INSERT INTO `sys_dict` VALUES (55, 2, 53, '禁用', NULL, '2'); INSERT INTO `sys_dict` VALUES ('55', '2', '53', '禁用', null, '2');
INSERT INTO `sys_dict` VALUES (56, 0, 0, '账号状态', NULL, 'account_state'); INSERT INTO `sys_dict` VALUES ('56', '0', '0', '账号状态', null, 'account_state');
INSERT INTO `sys_dict` VALUES (57, 1, 56, '启用', NULL, '1'); INSERT INTO `sys_dict` VALUES ('57', '1', '56', '启用', null, '1');
INSERT INTO `sys_dict` VALUES (58, 2, 56, '冻结', NULL, '2'); INSERT INTO `sys_dict` VALUES ('58', '2', '56', '冻结', null, '2');
INSERT INTO `sys_dict` VALUES (59, 3, 56, '已删除', NULL, '3'); INSERT INTO `sys_dict` VALUES ('59', '3', '56', '已删除', null, '3');
-- ---------------------------- -- ----------------------------
-- Table structure for sys_expense -- Table structure for sys_expense
...@@ -109,7 +107,7 @@ CREATE TABLE `sys_login_log` ( ...@@ -109,7 +107,7 @@ CREATE TABLE `sys_login_log` (
`message` text COMMENT '具体消息', `message` text COMMENT '具体消息',
`ip` varchar(255) DEFAULT NULL COMMENT '登录ip', `ip` varchar(255) DEFAULT NULL COMMENT '登录ip',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=216 DEFAULT CHARSET=utf8 COMMENT='登录记录'; ) ENGINE=InnoDB AUTO_INCREMENT=217 DEFAULT CHARSET=utf8 COMMENT='登录记录';
-- ---------------------------- -- ----------------------------
-- Records of sys_login_log -- Records of sys_login_log
...@@ -194,9 +192,6 @@ INSERT INTO `sys_menu` VALUES ('164', 'role_list', 'role', '[0],[system],[role], ...@@ -194,9 +192,6 @@ INSERT INTO `sys_menu` VALUES ('164', 'role_list', 'role', '[0],[system],[role],
INSERT INTO `sys_menu` VALUES ('165', 'to_assign_role', 'mgr', '[0],[system],[mgr],', '分配角色跳转', '', '/mgr/role_assign', '8', '3', '0', null, '1', null); INSERT INTO `sys_menu` VALUES ('165', 'to_assign_role', 'mgr', '[0],[system],[mgr],', '分配角色跳转', '', '/mgr/role_assign', '8', '3', '0', null, '1', null);
INSERT INTO `sys_menu` VALUES ('166', 'to_user_edit', 'mgr', '[0],[system],[mgr],', '编辑用户跳转', '', '/mgr/user_edit', '9', '3', '0', null, '1', null); INSERT INTO `sys_menu` VALUES ('166', 'to_user_edit', 'mgr', '[0],[system],[mgr],', '编辑用户跳转', '', '/mgr/user_edit', '9', '3', '0', null, '1', null);
INSERT INTO `sys_menu` VALUES ('167', 'mgr_list', 'mgr', '[0],[system],[mgr],', '用户列表', '', '/mgr/list', '10', '3', '0', null, '1', null); INSERT INTO `sys_menu` VALUES ('167', 'mgr_list', 'mgr', '[0],[system],[mgr],', '用户列表', '', '/mgr/list', '10', '3', '0', null, '1', null);
INSERT INTO `sys_menu` VALUES ('168', 'expense', '0', '[0],', '报销管理', 'fa-clone', '#', '5', '1', '1', null, '1', null);
INSERT INTO `sys_menu` VALUES ('169', 'expense_fill', 'expense', '[0],[expense],', '报销申请', '', '/expense', '1', '2', '1', null, '1', null);
INSERT INTO `sys_menu` VALUES ('170', 'expense_progress', 'expense', '[0],[expense],', '报销审批', '', '/process', '2', '2', '1', null, '1', null);
-- ---------------------------- -- ----------------------------
-- Table structure for sys_notice -- Table structure for sys_notice
...@@ -233,7 +228,7 @@ CREATE TABLE `sys_operation_log` ( ...@@ -233,7 +228,7 @@ CREATE TABLE `sys_operation_log` (
`succeed` varchar(255) DEFAULT NULL COMMENT '是否成功', `succeed` varchar(255) DEFAULT NULL COMMENT '是否成功',
`message` text COMMENT '备注', `message` text COMMENT '备注',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=550 DEFAULT CHARSET=utf8 COMMENT='操作日志'; ) ENGINE=InnoDB AUTO_INCREMENT=554 DEFAULT CHARSET=utf8 COMMENT='操作日志';
-- ---------------------------- -- ----------------------------
-- Records of sys_operation_log -- Records of sys_operation_log
...@@ -248,7 +243,7 @@ CREATE TABLE `sys_relation` ( ...@@ -248,7 +243,7 @@ CREATE TABLE `sys_relation` (
`menuid` bigint(11) DEFAULT NULL COMMENT '菜单id', `menuid` bigint(11) DEFAULT NULL COMMENT '菜单id',
`roleid` int(11) DEFAULT NULL COMMENT '角色id', `roleid` int(11) DEFAULT NULL COMMENT '角色id',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3737 DEFAULT CHARSET=utf8 COMMENT='角色和菜单关联表'; ) ENGINE=InnoDB AUTO_INCREMENT=3792 DEFAULT CHARSET=utf8 COMMENT='角色和菜单关联表';
-- ---------------------------- -- ----------------------------
-- Records of sys_relation -- Records of sys_relation
...@@ -273,64 +268,61 @@ INSERT INTO `sys_relation` VALUES ('3393', '121', '5'); ...@@ -273,64 +268,61 @@ INSERT INTO `sys_relation` VALUES ('3393', '121', '5');
INSERT INTO `sys_relation` VALUES ('3394', '122', '5'); INSERT INTO `sys_relation` VALUES ('3394', '122', '5');
INSERT INTO `sys_relation` VALUES ('3395', '150', '5'); INSERT INTO `sys_relation` VALUES ('3395', '150', '5');
INSERT INTO `sys_relation` VALUES ('3396', '151', '5'); INSERT INTO `sys_relation` VALUES ('3396', '151', '5');
INSERT INTO `sys_relation` VALUES ('3679', '105', '1'); INSERT INTO `sys_relation` VALUES ('3737', '105', '1');
INSERT INTO `sys_relation` VALUES ('3680', '106', '1'); INSERT INTO `sys_relation` VALUES ('3738', '106', '1');
INSERT INTO `sys_relation` VALUES ('3681', '107', '1'); INSERT INTO `sys_relation` VALUES ('3739', '107', '1');
INSERT INTO `sys_relation` VALUES ('3682', '108', '1'); INSERT INTO `sys_relation` VALUES ('3740', '108', '1');
INSERT INTO `sys_relation` VALUES ('3683', '109', '1'); INSERT INTO `sys_relation` VALUES ('3741', '109', '1');
INSERT INTO `sys_relation` VALUES ('3684', '110', '1'); INSERT INTO `sys_relation` VALUES ('3742', '110', '1');
INSERT INTO `sys_relation` VALUES ('3685', '111', '1'); INSERT INTO `sys_relation` VALUES ('3743', '111', '1');
INSERT INTO `sys_relation` VALUES ('3686', '112', '1'); INSERT INTO `sys_relation` VALUES ('3744', '112', '1');
INSERT INTO `sys_relation` VALUES ('3687', '113', '1'); INSERT INTO `sys_relation` VALUES ('3745', '113', '1');
INSERT INTO `sys_relation` VALUES ('3688', '165', '1'); INSERT INTO `sys_relation` VALUES ('3746', '165', '1');
INSERT INTO `sys_relation` VALUES ('3689', '166', '1'); INSERT INTO `sys_relation` VALUES ('3747', '166', '1');
INSERT INTO `sys_relation` VALUES ('3690', '167', '1'); INSERT INTO `sys_relation` VALUES ('3748', '167', '1');
INSERT INTO `sys_relation` VALUES ('3691', '114', '1'); INSERT INTO `sys_relation` VALUES ('3749', '114', '1');
INSERT INTO `sys_relation` VALUES ('3692', '115', '1'); INSERT INTO `sys_relation` VALUES ('3750', '115', '1');
INSERT INTO `sys_relation` VALUES ('3693', '116', '1'); INSERT INTO `sys_relation` VALUES ('3751', '116', '1');
INSERT INTO `sys_relation` VALUES ('3694', '117', '1'); INSERT INTO `sys_relation` VALUES ('3752', '117', '1');
INSERT INTO `sys_relation` VALUES ('3695', '118', '1'); INSERT INTO `sys_relation` VALUES ('3753', '118', '1');
INSERT INTO `sys_relation` VALUES ('3696', '162', '1'); INSERT INTO `sys_relation` VALUES ('3754', '162', '1');
INSERT INTO `sys_relation` VALUES ('3697', '163', '1'); INSERT INTO `sys_relation` VALUES ('3755', '163', '1');
INSERT INTO `sys_relation` VALUES ('3698', '164', '1'); INSERT INTO `sys_relation` VALUES ('3756', '164', '1');
INSERT INTO `sys_relation` VALUES ('3699', '119', '1'); INSERT INTO `sys_relation` VALUES ('3757', '119', '1');
INSERT INTO `sys_relation` VALUES ('3700', '120', '1'); INSERT INTO `sys_relation` VALUES ('3758', '120', '1');
INSERT INTO `sys_relation` VALUES ('3701', '121', '1'); INSERT INTO `sys_relation` VALUES ('3759', '121', '1');
INSERT INTO `sys_relation` VALUES ('3702', '122', '1'); INSERT INTO `sys_relation` VALUES ('3760', '122', '1');
INSERT INTO `sys_relation` VALUES ('3703', '150', '1'); INSERT INTO `sys_relation` VALUES ('3761', '150', '1');
INSERT INTO `sys_relation` VALUES ('3704', '151', '1'); INSERT INTO `sys_relation` VALUES ('3762', '151', '1');
INSERT INTO `sys_relation` VALUES ('3705', '128', '1'); INSERT INTO `sys_relation` VALUES ('3763', '128', '1');
INSERT INTO `sys_relation` VALUES ('3706', '134', '1'); INSERT INTO `sys_relation` VALUES ('3764', '134', '1');
INSERT INTO `sys_relation` VALUES ('3707', '158', '1'); INSERT INTO `sys_relation` VALUES ('3765', '158', '1');
INSERT INTO `sys_relation` VALUES ('3708', '159', '1'); INSERT INTO `sys_relation` VALUES ('3766', '159', '1');
INSERT INTO `sys_relation` VALUES ('3709', '130', '1'); INSERT INTO `sys_relation` VALUES ('3767', '130', '1');
INSERT INTO `sys_relation` VALUES ('3710', '131', '1'); INSERT INTO `sys_relation` VALUES ('3768', '131', '1');
INSERT INTO `sys_relation` VALUES ('3711', '135', '1'); INSERT INTO `sys_relation` VALUES ('3769', '135', '1');
INSERT INTO `sys_relation` VALUES ('3712', '136', '1'); INSERT INTO `sys_relation` VALUES ('3770', '136', '1');
INSERT INTO `sys_relation` VALUES ('3713', '137', '1'); INSERT INTO `sys_relation` VALUES ('3771', '137', '1');
INSERT INTO `sys_relation` VALUES ('3714', '152', '1'); INSERT INTO `sys_relation` VALUES ('3772', '152', '1');
INSERT INTO `sys_relation` VALUES ('3715', '153', '1'); INSERT INTO `sys_relation` VALUES ('3773', '153', '1');
INSERT INTO `sys_relation` VALUES ('3716', '154', '1'); INSERT INTO `sys_relation` VALUES ('3774', '154', '1');
INSERT INTO `sys_relation` VALUES ('3717', '132', '1'); INSERT INTO `sys_relation` VALUES ('3775', '132', '1');
INSERT INTO `sys_relation` VALUES ('3718', '138', '1'); INSERT INTO `sys_relation` VALUES ('3776', '138', '1');
INSERT INTO `sys_relation` VALUES ('3719', '139', '1'); INSERT INTO `sys_relation` VALUES ('3777', '139', '1');
INSERT INTO `sys_relation` VALUES ('3720', '140', '1'); INSERT INTO `sys_relation` VALUES ('3778', '140', '1');
INSERT INTO `sys_relation` VALUES ('3721', '155', '1'); INSERT INTO `sys_relation` VALUES ('3779', '155', '1');
INSERT INTO `sys_relation` VALUES ('3722', '156', '1'); INSERT INTO `sys_relation` VALUES ('3780', '156', '1');
INSERT INTO `sys_relation` VALUES ('3723', '157', '1'); INSERT INTO `sys_relation` VALUES ('3781', '157', '1');
INSERT INTO `sys_relation` VALUES ('3724', '133', '1'); INSERT INTO `sys_relation` VALUES ('3782', '133', '1');
INSERT INTO `sys_relation` VALUES ('3725', '160', '1'); INSERT INTO `sys_relation` VALUES ('3783', '160', '1');
INSERT INTO `sys_relation` VALUES ('3726', '161', '1'); INSERT INTO `sys_relation` VALUES ('3784', '161', '1');
INSERT INTO `sys_relation` VALUES ('3727', '141', '1'); INSERT INTO `sys_relation` VALUES ('3785', '141', '1');
INSERT INTO `sys_relation` VALUES ('3728', '142', '1'); INSERT INTO `sys_relation` VALUES ('3786', '142', '1');
INSERT INTO `sys_relation` VALUES ('3729', '143', '1'); INSERT INTO `sys_relation` VALUES ('3787', '143', '1');
INSERT INTO `sys_relation` VALUES ('3730', '144', '1'); INSERT INTO `sys_relation` VALUES ('3788', '144', '1');
INSERT INTO `sys_relation` VALUES ('3731', '148', '1'); INSERT INTO `sys_relation` VALUES ('3789', '145', '1');
INSERT INTO `sys_relation` VALUES ('3732', '145', '1'); INSERT INTO `sys_relation` VALUES ('3790', '148', '1');
INSERT INTO `sys_relation` VALUES ('3733', '149', '1'); INSERT INTO `sys_relation` VALUES ('3791', '149', '1');
INSERT INTO `sys_relation` VALUES ('3734', '168', '1');
INSERT INTO `sys_relation` VALUES ('3735', '169', '1');
INSERT INTO `sys_relation` VALUES ('3736', '170', '1');
-- ---------------------------- -- ----------------------------
-- Table structure for sys_role -- Table structure for sys_role
......
package com.stylefeng.guns; package com.stylefeng.guns;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/** /**
* Guns Web程序启动类 * Guns Web程序启动类
......
package com.stylefeng.guns.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.stylefeng.guns.config.properties.GunsFlowableProperties;
import com.stylefeng.guns.core.datasource.DruidProperties;
import com.stylefeng.guns.core.flowable.GunsDefaultProcessDiagramGenerator;
import org.flowable.spring.SpringAsyncExecutor;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.AbstractProcessEngineAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import java.io.IOException;
/**
* 工作流配置
*
* @author fengshuonan
* @date 2017-12-02 22:28
*/
@Configuration
public class FlowableConfig extends AbstractProcessEngineAutoConfiguration {
@Autowired
DruidProperties druidProperties;
@Autowired
GunsFlowableProperties gunsFlowableProperties;
/**
* flowable单独的数据源
*/
private DruidDataSource flowableDataSource() {
DruidDataSource dataSource = new DruidDataSource();
druidProperties.config(dataSource);
gunsFlowableProperties.config(dataSource);
return dataSource;
}
/**
* spring-flowable拓展配置
*/
@Bean
public SpringProcessEngineConfiguration springProcessEngineConfiguration(
PlatformTransactionManager transactionManager,
SpringAsyncExecutor springAsyncExecutor) throws IOException {
SpringProcessEngineConfiguration configuration = this.baseSpringProcessEngineConfiguration(flowableDataSource(), transactionManager, springAsyncExecutor);
configuration.setActivityFontName("宋体");
configuration.setLabelFontName("宋体");
configuration.setProcessDiagramGenerator(new GunsDefaultProcessDiagramGenerator());
return configuration;
}
}
package com.stylefeng.guns.config.properties;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* flowable工作流的的配置
*
* @author fengshuonan
* @date 2017-12-02 23:18
*/
@Configuration
@ConfigurationProperties(prefix = GunsFlowableProperties.GUNS_FLOWABLE_DATASOURCE)
public class GunsFlowableProperties {
public static final String GUNS_FLOWABLE_DATASOURCE = "guns.flowable.datasource";
/**
* 默认多数据源的链接
*/
private String url = "jdbc:mysql://127.0.0.1:3306/guns_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull";
/**
* 默认多数据源的数据库账号
*/
private String username = "root";
/**
* 默认多数据源的数据库密码
*/
private String password = "root";
public void config(DruidDataSource dataSource) {
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
/* 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.stylefeng.guns.core.flowable;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.image.impl.DefaultProcessDiagramCanvas;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.*;
/**
* 修复线的文字显示
*
* @author Joram Barrez
* @author Tijs Rademakers
*/
public class GunsDefaultProcessDiagramGenerator implements ProcessDiagramGenerator {
protected Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions = new HashMap<>();
protected Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap<>();
public GunsDefaultProcessDiagramGenerator() {
this(1.0);
}
// The instructions on how to draw a certain construct is
// created statically and stored in a map for performance.
public GunsDefaultProcessDiagramGenerator(final double scaleFactor) {
// start event
activityDrawInstructions.put(StartEvent.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
StartEvent startEvent = (StartEvent) flowNode;
if (startEvent.getEventDefinitions() != null && !startEvent.getEventDefinitions().isEmpty()) {
EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0);
if (eventDefinition instanceof TimerEventDefinition) {
processDiagramCanvas.drawTimerStartEvent(graphicInfo, scaleFactor);
} else if (eventDefinition instanceof ErrorEventDefinition) {
processDiagramCanvas.drawErrorStartEvent(graphicInfo, scaleFactor);
} else if (eventDefinition instanceof SignalEventDefinition) {
processDiagramCanvas.drawSignalStartEvent(graphicInfo, scaleFactor);
} else if (eventDefinition instanceof MessageEventDefinition) {
processDiagramCanvas.drawMessageStartEvent(graphicInfo, scaleFactor);
} else {
processDiagramCanvas.drawNoneStartEvent(graphicInfo);
}
} else {
processDiagramCanvas.drawNoneStartEvent(graphicInfo);
}
}
});
// signal catch
activityDrawInstructions.put(IntermediateCatchEvent.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowNode;
if (intermediateCatchEvent.getEventDefinitions() != null && !intermediateCatchEvent.getEventDefinitions()
.isEmpty()) {
if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
} else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) {
processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
} else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {
processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
}
}
}
});
// signal throw
activityDrawInstructions.put(ThrowEvent.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
ThrowEvent throwEvent = (ThrowEvent) flowNode;
if (throwEvent.getEventDefinitions() != null && !throwEvent.getEventDefinitions().isEmpty()) {
if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
processDiagramCanvas.drawThrowingSignalEvent(graphicInfo, scaleFactor);
} else if (throwEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) {
processDiagramCanvas.drawThrowingCompensateEvent(graphicInfo, scaleFactor);
} else {
processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
}
} else {
processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
}
}
});
// end event
activityDrawInstructions.put(EndEvent.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
EndEvent endEvent = (EndEvent) flowNode;
if (endEvent.getEventDefinitions() != null && !endEvent.getEventDefinitions().isEmpty()) {
if (endEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) {
processDiagramCanvas.drawErrorEndEvent(flowNode.getName(), graphicInfo, scaleFactor);
} else {
processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
}
} else {
processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
}
}
});
// task
activityDrawInstructions.put(Task.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawTask(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// user task
activityDrawInstructions.put(UserTask.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawUserTask(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// script task
activityDrawInstructions.put(ScriptTask.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawScriptTask(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// service task
activityDrawInstructions.put(ServiceTask.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
ServiceTask serviceTask = (ServiceTask) flowNode;
if ("camel".equalsIgnoreCase(serviceTask.getType())) {
processDiagramCanvas.drawCamelTask(serviceTask.getName(), graphicInfo, scaleFactor);
} else if ("mule".equalsIgnoreCase(serviceTask.getType())) {
processDiagramCanvas.drawMuleTask(serviceTask.getName(), graphicInfo, scaleFactor);
} else if ("http".equalsIgnoreCase(serviceTask.getType())) {
processDiagramCanvas.drawHttpTask(serviceTask.getName(), graphicInfo, scaleFactor);
} else {
processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor);
}
}
});
// http service task
activityDrawInstructions.put(HttpServiceTask.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawHttpTask(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// receive task
activityDrawInstructions.put(ReceiveTask.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawReceiveTask(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// send task
activityDrawInstructions.put(SendTask.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawSendTask(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// manual task
activityDrawInstructions.put(ManualTask.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawManualTask(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// businessRuleTask task
activityDrawInstructions.put(BusinessRuleTask.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawBusinessRuleTask(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// exclusive gateway
activityDrawInstructions.put(ExclusiveGateway.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawExclusiveGateway(graphicInfo, scaleFactor);
}
});
// inclusive gateway
activityDrawInstructions.put(InclusiveGateway.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawInclusiveGateway(graphicInfo, scaleFactor);
}
});
// parallel gateway
activityDrawInstructions.put(ParallelGateway.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawParallelGateway(graphicInfo, scaleFactor);
}
});
// event based gateway
activityDrawInstructions.put(EventGateway.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawEventBasedGateway(graphicInfo, scaleFactor);
}
});
// Boundary timer
activityDrawInstructions.put(BoundaryEvent.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
BoundaryEvent boundaryEvent = (BoundaryEvent) flowNode;
if (boundaryEvent.getEventDefinitions() != null && !boundaryEvent.getEventDefinitions().isEmpty()) {
if (boundaryEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) {
processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
} else if (boundaryEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) {
processDiagramCanvas.drawCatchingErrorEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
} else if (boundaryEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
} else if (boundaryEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {
processDiagramCanvas.drawCatchingMessageEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
} else if (boundaryEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) {
processDiagramCanvas.drawCatchingCompensateEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
}
}
}
});
// subprocess
activityDrawInstructions.put(SubProcess.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
} else {
processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
}
}
});
// Event subprocess
activityDrawInstructions.put(EventSubProcess.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor);
} else {
processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor);
}
}
});
// Adhoc subprocess
activityDrawInstructions.put(AdhocSubProcess.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
} else {
processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
}
}
});
// call activity
activityDrawInstructions.put(CallActivity.class, new ActivityDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
processDiagramCanvas.drawCollapsedCallActivity(flowNode.getName(), graphicInfo, scaleFactor);
}
});
// text annotation
artifactDrawInstructions.put(TextAnnotation.class, new ArtifactDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
TextAnnotation textAnnotation = (TextAnnotation) artifact;
processDiagramCanvas.drawTextAnnotation(textAnnotation.getText(), graphicInfo, scaleFactor);
}
});
// association
artifactDrawInstructions.put(Association.class, new ArtifactDrawInstruction() {
@Override
public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
Association association = (Association) artifact;
String sourceRef = association.getSourceRef();
String targetRef = association.getTargetRef();
// source and target can be instance of FlowElement or Artifact
BaseElement sourceElement = bpmnModel.getFlowElement(sourceRef);
BaseElement targetElement = bpmnModel.getFlowElement(targetRef);
if (sourceElement == null) {
sourceElement = bpmnModel.getArtifact(sourceRef);
}
if (targetElement == null) {
targetElement = bpmnModel.getArtifact(targetRef);
}
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
int xPoints[] = new int[graphicInfoList.size()];
int yPoints[] = new int[graphicInfoList.size()];
for (int i = 1; i < graphicInfoList.size(); i++) {
GraphicInfo graphicInfo = graphicInfoList.get(i);
GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
if (i == 1) {
xPoints[0] = (int) previousGraphicInfo.getX();
yPoints[0] = (int) previousGraphicInfo.getY();
}
xPoints[i] = (int) graphicInfo.getX();
yPoints[i] = (int) graphicInfo.getY();
}
AssociationDirection associationDirection = association.getAssociationDirection();
processDiagramCanvas.drawAssociation(xPoints, yPoints, associationDirection, false, scaleFactor);
}
});
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor).generateImage(imageType);
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows) {
return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, 1.0);
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType,
List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor);
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities) {
return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.<String>emptyList());
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, double scaleFactor) {
return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.<String>emptyList(), scaleFactor);
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName,
String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
return generateDiagram(bpmnModel, imageType, Collections.<String>emptyList(), Collections.<String>emptyList(),
activityFontName, labelFontName, annotationFontName, customClassLoader, 1.0);
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName,
String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
return generateDiagram(bpmnModel, imageType, Collections.<String>emptyList(), Collections.<String>emptyList(),
activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor);
}
@Override
public InputStream generatePngDiagram(BpmnModel bpmnModel) {
return generatePngDiagram(bpmnModel, 1.0);
}
@Override
public InputStream generatePngDiagram(BpmnModel bpmnModel, double scaleFactor) {
return generateDiagram(bpmnModel, "png", Collections.<String>emptyList(), Collections.<String>emptyList(), scaleFactor);
}
@Override
public InputStream generateJpgDiagram(BpmnModel bpmnModel) {
return generateJpgDiagram(bpmnModel, 1.0);
}
@Override
public InputStream generateJpgDiagram(BpmnModel bpmnModel, double scaleFactor) {
return generateDiagram(bpmnModel, "jpg", Collections.<String>emptyList(), Collections.<String>emptyList());
}
public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor).generateBufferedImage(imageType);
}
public BufferedImage generateImage(BpmnModel bpmnModel, String imageType,
List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
return generateImage(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, null, scaleFactor);
}
@Override
public BufferedImage generatePngImage(BpmnModel bpmnModel, double scaleFactor) {
return generateImage(bpmnModel, "png", Collections.<String>emptyList(), Collections.<String>emptyList(), scaleFactor);
}
protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,
List<String> highLightedActivities, List<String> highLightedFlows,
String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
prepareBpmnModel(bpmnModel);
DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
// Draw pool shape, if process is participant in collaboration
for (Pool pool : bpmnModel.getPools()) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo, scaleFactor);
}
// Draw lanes
for (Process process : bpmnModel.getProcesses()) {
for (Lane lane : process.getLanes()) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo, scaleFactor);
}
}
// Draw activities and their sequence-flows
for (Process process : bpmnModel.getProcesses()) {
for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) {
if (!isPartOfCollapsedSubProcess(flowNode, bpmnModel)) {
drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor);
}
}
}
// Draw artifacts
for (Process process : bpmnModel.getProcesses()) {
for (Artifact artifact : process.getArtifacts()) {
drawArtifact(processDiagramCanvas, bpmnModel, artifact);
}
List<SubProcess> subProcesses = process.findFlowElementsOfType(SubProcess.class, true);
if (subProcesses != null) {
for (SubProcess subProcess : subProcesses) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(subProcess.getId());
if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
continue;
}
if (!isPartOfCollapsedSubProcess(subProcess, bpmnModel)) {
for (Artifact subProcessArtifact : subProcess.getArtifacts()) {
drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
}
}
}
}
}
return processDiagramCanvas;
}
protected void prepareBpmnModel(BpmnModel bpmnModel) {
// Need to make sure all elements have positive x and y.
// Check all graphicInfo and update the elements accordingly
List<GraphicInfo> allGraphicInfos = new ArrayList<>();
if (bpmnModel.getLocationMap() != null) {
allGraphicInfos.addAll(bpmnModel.getLocationMap().values());
}
if (bpmnModel.getLabelLocationMap() != null) {
allGraphicInfos.addAll(bpmnModel.getLabelLocationMap().values());
}
if (bpmnModel.getFlowLocationMap() != null) {
for (List<GraphicInfo> flowGraphicInfos : bpmnModel.getFlowLocationMap().values()) {
allGraphicInfos.addAll(flowGraphicInfos);
}
}
if (allGraphicInfos.size() > 0) {
boolean needsTranslationX = false;
boolean needsTranslationY = false;
double lowestX = 0.0;
double lowestY = 0.0;
// Collect lowest x and y
for (GraphicInfo graphicInfo : allGraphicInfos) {
double x = graphicInfo.getX();
double y = graphicInfo.getY();
if (x < lowestX) {
needsTranslationX = true;
lowestX = x;
}
if (y < lowestY) {
needsTranslationY = true;
lowestY = y;
}
}
// Update all graphicInfo objects
if (needsTranslationX || needsTranslationY) {
double translationX = Math.abs(lowestX);
double translationY = Math.abs(lowestY);
for (GraphicInfo graphicInfo : allGraphicInfos) {
if (needsTranslationX) {
graphicInfo.setX(graphicInfo.getX() + translationX);
}
if (needsTranslationY) {
graphicInfo.setY(graphicInfo.getY() + translationY);
}
}
}
}
}
protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
if (drawInstruction != null) {
drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);
// Gather info on the multi instance marker
boolean multiInstanceSequential = false;
boolean multiInstanceParallel = false;
boolean collapsed = false;
if (flowNode instanceof Activity) {
Activity activity = (Activity) flowNode;
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
if (multiInstanceLoopCharacteristics != null) {
multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
multiInstanceParallel = !multiInstanceSequential;
}
}
// Gather info on the collapsed marker
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
if (flowNode instanceof SubProcess) {
collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
} else if (flowNode instanceof CallActivity) {
collapsed = true;
}
if (scaleFactor == 1.0) {
// Actually draw the markers
processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(),
multiInstanceSequential, multiInstanceParallel, collapsed);
}
// Draw highlighted activities
if (highLightedActivities.contains(flowNode.getId())) {
drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()));
}
}
// Outgoing transitions of activity
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId()));
String defaultFlow = null;
if (flowNode instanceof Activity) {
defaultFlow = ((Activity) flowNode).getDefaultFlow();
} else if (flowNode instanceof Gateway) {
defaultFlow = ((Gateway) flowNode).getDefaultFlow();
}
boolean isDefault = false;
if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) {
isDefault = true;
}
boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway);
String sourceRef = sequenceFlow.getSourceRef();
String targetRef = sequenceFlow.getTargetRef();
FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
if (graphicInfoList != null && graphicInfoList.size() > 0) {
graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
int xPoints[] = new int[graphicInfoList.size()];
int yPoints[] = new int[graphicInfoList.size()];
for (int i = 1; i < graphicInfoList.size(); i++) {
GraphicInfo graphicInfo = graphicInfoList.get(i);
GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
if (i == 1) {
xPoints[0] = (int) previousGraphicInfo.getX();
yPoints[0] = (int) previousGraphicInfo.getY();
}
xPoints[i] = (int) graphicInfo.getX();
yPoints[i] = (int) graphicInfo.getY();
}
processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor);
// Draw sequenceflow label
GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
if (labelGraphicInfo != null) {
processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
} else {
GraphicInfo lineCenter = getLineCenter(graphicInfoList);
processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false);
}
}
}
// Nested elements
if (flowNode instanceof FlowElementsContainer) {
for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
if (nestedFlowElement instanceof FlowNode && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) {
drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
highLightedActivities, highLightedFlows, scaleFactor);
}
}
}
}
/**
* This method makes coordinates of connection flow better.
*
* @param processDiagramCanvas
* @param bpmnModel
* @param sourceElement
* @param targetElement
* @param graphicInfoList
* @return
*/
protected static List<GraphicInfo> connectionPerfectionizer(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, BaseElement sourceElement, BaseElement targetElement, List<GraphicInfo> graphicInfoList) {
GraphicInfo sourceGraphicInfo = bpmnModel.getGraphicInfo(sourceElement.getId());
GraphicInfo targetGraphicInfo = bpmnModel.getGraphicInfo(targetElement.getId());
DefaultProcessDiagramCanvas.SHAPE_TYPE sourceShapeType = getShapeType(sourceElement);
DefaultProcessDiagramCanvas.SHAPE_TYPE targetShapeType = getShapeType(targetElement);
return processDiagramCanvas.connectionPerfectionizer(sourceShapeType, targetShapeType, sourceGraphicInfo, targetGraphicInfo, graphicInfoList);
}
/**
* This method returns shape type of base element.<br>
* Each element can be presented as rectangle, rhombus, or ellipse.
*
* @param baseElement
* @return DefaultProcessDiagramCanvas.SHAPE_TYPE
*/
protected static DefaultProcessDiagramCanvas.SHAPE_TYPE getShapeType(BaseElement baseElement) {
if (baseElement instanceof Task || baseElement instanceof Activity || baseElement instanceof TextAnnotation) {
return DefaultProcessDiagramCanvas.SHAPE_TYPE.Rectangle;
} else if (baseElement instanceof Gateway) {
return DefaultProcessDiagramCanvas.SHAPE_TYPE.Rhombus;
} else if (baseElement instanceof Event) {
return DefaultProcessDiagramCanvas.SHAPE_TYPE.Ellipse;
} else {
// unknown source element, just do not correct coordinates
}
return null;
}
protected static GraphicInfo getLineCenter(List<GraphicInfo> graphicInfoList) {
GraphicInfo gi = new GraphicInfo();
int xPoints[] = new int[graphicInfoList.size()];
int yPoints[] = new int[graphicInfoList.size()];
double length = 0;
double[] lengths = new double[graphicInfoList.size()];
lengths[0] = 0;
double m;
for (int i = 1; i < graphicInfoList.size(); i++) {
GraphicInfo graphicInfo = graphicInfoList.get(i);
GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1);
if (i == 1) {
xPoints[0] = (int) previousGraphicInfo.getX();
yPoints[0] = (int) previousGraphicInfo.getY();
}
xPoints[i] = (int) graphicInfo.getX();
yPoints[i] = (int) graphicInfo.getY();
length += Math.sqrt(
Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), 2) +
Math.pow((int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), 2));
lengths[i] = length;
}
m = length / 2;
int p1 = 0;
int p2 = 1;
for (int i = 1; i < lengths.length; i++) {
double len = lengths[i];
p1 = i - 1;
p2 = i;
if (len > m) {
break;
}
}
GraphicInfo graphicInfo1 = graphicInfoList.get(p1);
GraphicInfo graphicInfo2 = graphicInfoList.get(p2);
double AB = (int) graphicInfo2.getX() - (int) graphicInfo1.getX();
double OA = (int) graphicInfo2.getY() - (int) graphicInfo1.getY();
double OB = lengths[p2] - lengths[p1];
double ob = m - lengths[p1];
double ab = AB * ob / OB;
double oa = OA * ob / OB;
double mx = graphicInfo1.getX() + ab;
double my = graphicInfo1.getY() + oa;
gi.setX(mx);
gi.setY(my);
return gi;
}
protected void drawArtifact(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
ArtifactDrawInstruction drawInstruction = artifactDrawInstructions.get(artifact.getClass());
if (drawInstruction != null) {
drawInstruction.draw(processDiagramCanvas, bpmnModel, artifact);
}
}
private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) {
processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
}
protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
// We need to calculate maximum values to know how big the image will be in its entirety
double minX = Double.MAX_VALUE;
double maxX = 0;
double minY = Double.MAX_VALUE;
double maxY = 0;
for (Pool pool : bpmnModel.getPools()) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
minX = graphicInfo.getX();
maxX = graphicInfo.getX() + graphicInfo.getWidth();
minY = graphicInfo.getY();
maxY = graphicInfo.getY() + graphicInfo.getHeight();
}
List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
for (FlowNode flowNode : flowNodes) {
GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
// width
if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {
maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();
}
if (flowNodeGraphicInfo.getX() < minX) {
minX = flowNodeGraphicInfo.getX();
}
// height
if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {
maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();
}
if (flowNodeGraphicInfo.getY() < minY) {
minY = flowNodeGraphicInfo.getY();
}
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
if (graphicInfoList != null) {
for (GraphicInfo graphicInfo : graphicInfoList) {
// width
if (graphicInfo.getX() > maxX) {
maxX = graphicInfo.getX();
}
if (graphicInfo.getX() < minX) {
minX = graphicInfo.getX();
}
// height
if (graphicInfo.getY() > maxY) {
maxY = graphicInfo.getY();
}
if (graphicInfo.getY() < minY) {
minY = graphicInfo.getY();
}
}
}
}
}
List<Artifact> artifacts = gatherAllArtifacts(bpmnModel);
for (Artifact artifact : artifacts) {
GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
if (artifactGraphicInfo != null) {
// width
if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) {
maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth();
}
if (artifactGraphicInfo.getX() < minX) {
minX = artifactGraphicInfo.getX();
}
// height
if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) {
maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight();
}
if (artifactGraphicInfo.getY() < minY) {
minY = artifactGraphicInfo.getY();
}
}
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
if (graphicInfoList != null) {
for (GraphicInfo graphicInfo : graphicInfoList) {
// width
if (graphicInfo.getX() > maxX) {
maxX = graphicInfo.getX();
}
if (graphicInfo.getX() < minX) {
minX = graphicInfo.getX();
}
// height
if (graphicInfo.getY() > maxY) {
maxY = graphicInfo.getY();
}
if (graphicInfo.getY() < minY) {
minY = graphicInfo.getY();
}
}
}
}
int nrOfLanes = 0;
for (Process process : bpmnModel.getProcesses()) {
for (Lane l : process.getLanes()) {
nrOfLanes++;
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());
// // width
if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {
maxX = graphicInfo.getX() + graphicInfo.getWidth();
}
if (graphicInfo.getX() < minX) {
minX = graphicInfo.getX();
}
// height
if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {
maxY = graphicInfo.getY() + graphicInfo.getHeight();
}
if (graphicInfo.getY() < minY) {
minY = graphicInfo.getY();
}
}
}
// Special case, see https://activiti.atlassian.net/browse/ACT-1431
if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) {
// Nothing to show
minX = 0;
minY = 0;
}
return new DefaultProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY,
imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
}
protected static List<Artifact> gatherAllArtifacts(BpmnModel bpmnModel) {
List<Artifact> artifacts = new ArrayList<>();
for (Process process : bpmnModel.getProcesses()) {
artifacts.addAll(process.getArtifacts());
}
return artifacts;
}
protected static List<FlowNode> gatherAllFlowNodes(BpmnModel bpmnModel) {
List<FlowNode> flowNodes = new ArrayList<>();
for (Process process : bpmnModel.getProcesses()) {
flowNodes.addAll(gatherAllFlowNodes(process));
}
return flowNodes;
}
protected static List<FlowNode> gatherAllFlowNodes(FlowElementsContainer flowElementsContainer) {
List<FlowNode> flowNodes = new ArrayList<>();
for (FlowElement flowElement : flowElementsContainer.getFlowElements()) {
if (flowElement instanceof FlowNode) {
flowNodes.add((FlowNode) flowElement);
}
if (flowElement instanceof FlowElementsContainer) {
flowNodes.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement));
}
}
return flowNodes;
}
protected boolean isPartOfCollapsedSubProcess(FlowElement flowElement, BpmnModel model) {
SubProcess subProcess = flowElement.getSubProcess();
if (subProcess != null) {
GraphicInfo graphicInfo = model.getGraphicInfo(subProcess.getId());
if (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
return true;
}
return isPartOfCollapsedSubProcess(subProcess, model);
}
return false;
}
public Map<Class<? extends BaseElement>, ActivityDrawInstruction> getActivityDrawInstructions() {
return activityDrawInstructions;
}
public void setActivityDrawInstructions(
Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions) {
this.activityDrawInstructions = activityDrawInstructions;
}
public Map<Class<? extends BaseElement>, ArtifactDrawInstruction> getArtifactDrawInstructions() {
return artifactDrawInstructions;
}
public void setArtifactDrawInstructions(
Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions) {
this.artifactDrawInstructions = artifactDrawInstructions;
}
protected interface ActivityDrawInstruction {
void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode);
}
protected interface ArtifactDrawInstruction {
void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact);
}
}
package com.stylefeng.guns.modular.flowable.controller;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.stylefeng.guns.modular.system.model.Expense;
import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.core.shiro.ShiroKit;
import com.stylefeng.guns.modular.flowable.service.IExpenseService;
import com.stylefeng.guns.modular.flowable.warpper.ExpenseWarpper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 报销管理控制器
*
* @author fengshuonan
* @Date 2017-12-04 21:11:36
*/
@Controller
@RequestMapping("/expense")
public class ExpenseController extends BaseController {
private String PREFIX = "/flowable/expense/";
@Autowired
private IExpenseService expenseService;
/**
* 跳转到报销管理首页
*/
@RequestMapping("")
public String index() {
return PREFIX + "expense.html";
}
/**
* 跳转到添加报销管理
*/
@RequestMapping("/expense_add")
public String expenseAdd() {
return PREFIX + "expense_add.html";
}
/**
* 查看当前流程图
*/
@RequestMapping("/expense_update/{expenseId}")
public void expenseView(@PathVariable Integer expenseId) {
try {
expenseService.printProcessImage(expenseId);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取报销管理列表
*/
@RequestMapping(value = "/list")
@ResponseBody
public Object list(String condition) {
EntityWrapper<Expense> expenseEntityWrapper = new EntityWrapper<>();
expenseEntityWrapper.eq("userid", ShiroKit.getUser().getId());
List<Map<String, Object>> stringObjectMap = expenseService.selectMaps(expenseEntityWrapper);
return super.warpObject(new ExpenseWarpper(stringObjectMap));
}
/**
* 新增报销管理
*/
@RequestMapping(value = "/add")
@ResponseBody
public Object add(Expense expense) {
expenseService.add(expense);
return SUCCESS_TIP;
}
/**
* 删除报销管理
*/
@RequestMapping(value = "/delete")
@ResponseBody
public Object delete(@RequestParam Integer expenseId) {
expenseService.delete(expenseId);
return SUCCESS_TIP;
}
/**
* 修改报销管理
*/
@RequestMapping(value = "/update")
@ResponseBody
public Object update(Expense expense) {
expenseService.updateById(expense);
return SUCCESS_TIP;
}
/**
* 报销管理详情
*/
@RequestMapping(value = "/detail/{expenseId}")
@ResponseBody
public Object detail(@PathVariable("expenseId") Integer expenseId) {
return expenseService.selectById(expenseId);
}
}
package com.stylefeng.guns.modular.flowable.controller;
import com.stylefeng.guns.core.base.controller.BaseController;
import com.stylefeng.guns.modular.flowable.service.IExpenseService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 审批管理控制器
*
* @author fengshuonan
* @Date 2017-12-04 21:11:36
*/
@Controller
@RequestMapping("/process")
public class ProcessController extends BaseController {
private String PREFIX = "/flowable/process/";
@Autowired
private IExpenseService expenseService;
@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
/**
* 跳转到审批管理首页
*/
@RequestMapping("")
public String index() {
return PREFIX + "process.html";
}
/**
* 获取审批管理列表
*/
@RequestMapping(value = "/list")
@ResponseBody
public Object list(String condition) {
return expenseService.getProcessList();
}
/**
* 审核通过
*/
@RequestMapping(value = "/pass")
@ResponseBody
public Object pass(String taskId) {
expenseService.pass(taskId);
return SUCCESS_TIP;
}
/**
* 审核不通过
*/
@RequestMapping(value = "/unPass")
@ResponseBody
public Object unPass(String taskId) {
expenseService.unPass(taskId);
return SUCCESS_TIP;
}
}
package com.stylefeng.guns.modular.flowable.handler;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
/**
* 员工经理任务分配
*/
public class BossTaskHandler implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
delegateTask.setAssignee("老板");
}
}
package com.stylefeng.guns.modular.flowable.handler;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
/**
* 员工经理任务分配
*/
public class ManagerTaskHandler implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
delegateTask.setAssignee("经理");
}
}
package com.stylefeng.guns.modular.flowable.model;
import java.util.Date;
/**
* 任务列表vo
*
* @author fengshuonan
* @date 2017-12-04 23:18
*/
public class TaskVo {
private String id;
private String name;
private Date createTime;
private String assignee;
private Object money;
private Boolean selfFlag;
public TaskVo() {
}
public TaskVo(String id, String name, Date createTime, String assignee, Object money, Boolean flag) {
this.id = id;
this.name = name;
this.createTime = createTime;
this.assignee = assignee;
this.money = money;
this.selfFlag = flag;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getAssignee() {
return assignee;
}
public void setAssignee(String assignee) {
this.assignee = assignee;
}
public Object getMoney() {
return money;
}
public void setMoney(Object money) {
this.money = money;
}
public Boolean getSelfFlag() {
return selfFlag;
}
public void setSelfFlag(Boolean selfFlag) {
this.selfFlag = selfFlag;
}
}
package com.stylefeng.guns.modular.flowable.service;
import com.baomidou.mybatisplus.service.IService;
import com.stylefeng.guns.modular.system.model.Expense;
import com.stylefeng.guns.modular.flowable.model.TaskVo;
import java.io.IOException;
import java.util.List;
/**
* <p>
* 报销表 服务类
* </p>
*
* @author stylefeng
* @since 2017-12-04
*/
public interface IExpenseService extends IService<Expense> {
/**
* 新增一个报销单
*/
void add(Expense expense);
/**
* 删除一个报销单
*/
void delete(Integer expenseId);
/**
* 通过审批
*/
void pass(String taskId);
/**
* 通过审批
*/
void unPass(String taskId);
/**
* 获取审批列表
*/
List<TaskVo> getProcessList();
/**
* 绘画当前流程图
*/
void printProcessImage(Integer expenseId) throws IOException;
}
package com.stylefeng.guns.modular.flowable.service.impl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.stylefeng.guns.core.common.constant.state.ExpenseState;
import com.stylefeng.guns.modular.system.dao.ExpenseMapper;
import com.stylefeng.guns.modular.system.model.Expense;
import com.stylefeng.guns.core.shiro.ShiroKit;
import com.stylefeng.guns.core.support.HttpKit;
import com.stylefeng.guns.modular.flowable.model.TaskVo;
import com.stylefeng.guns.modular.flowable.service.IExpenseService;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* <p>
* 报销表 服务实现类
* </p>
*
* @author stylefeng
* @since 2017-12-04
*/
@Service
public class ExpenseServiceImpl extends ServiceImpl<ExpenseMapper, Expense> implements IExpenseService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private ProcessEngine processEngine;
@Override
@Transactional(rollbackFor = Exception.class)
public void add(Expense expense) {
//保存业务数据
expense.setUserid(ShiroKit.getUser().getId());
expense.setState(ExpenseState.SUBMITING.getCode());
//启动流程
HashMap<String, Object> map = new HashMap<>();
map.put("taskUser", ShiroKit.getUser().getName());
map.put("money", expense.getMoney());
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Expense", map);
expense.setProcessId(processInstance.getId());
this.insert(expense);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(Integer expenseId) {
Expense expense = this.selectById(expenseId);
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processInstanceId(expense.getProcessId()).list();
for (ProcessInstance processInstance : list) {
if (processInstance.getId().equals(expense.getProcessId())) {
runtimeService.deleteProcessInstance(processInstance.getProcessInstanceId(), "取消报销");
}
}
this.deleteById(expenseId);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void pass(String taskId) {
//使用任务ID,查询任务对象,获取流程流程实例ID
Task task = taskService.createTaskQuery()//
.taskId(taskId)
.singleResult();
//通过审核
HashMap<String, Object> map = new HashMap<>();
map.put("outcome", "通过");
taskService.complete(taskId, map);
//判断流程是否结束,结束之后修改状态
ProcessInstance pi = runtimeService.createProcessInstanceQuery()//
.processInstanceId(task.getProcessInstanceId())//使用流程实例ID查询
.singleResult();
Wrapper<Expense> wrapper = new EntityWrapper<Expense>().eq("processId", task.getProcessInstanceId());
Expense expense = this.selectOne(wrapper);
//审核通过修改为通过状态
if (pi == null) {
expense.setState(ExpenseState.PASS.getCode());
expense.updateById();
} else {
//审核通过如果还有记录则为经理或boss审核中
expense.setState(ExpenseState.CHECKING.getCode());
expense.updateById();
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void unPass(String taskId) {
HashMap<String, Object> map = new HashMap<>();
map.put("outcome", "驳回");
taskService.complete(taskId, map);
}
@Override
public List<TaskVo> getProcessList() {
String name = ShiroKit.getUser().getName();
List<Task> list = taskService.createTaskQuery()
.taskAssignee(name)
.orderByTaskCreateTime().desc()
.list();
ArrayList<TaskVo> taskVos = new ArrayList<>();
for (Task task : list) {
Object money = runtimeService.getVariable(task.getExecutionId(), "money");
String taskUser = (String) taskService.getVariable(task.getId(), "taskUser");
boolean flag = false;
if (name.equals(taskUser)) {
flag = false;
} else {
flag = true;
}
taskVos.add(new TaskVo(task.getId(), task.getName(), task.getCreateTime(), taskUser, money, flag));
}
return taskVos;
}
@Override
public void printProcessImage(Integer expenseId) throws IOException {
Expense expense = this.selectById(expenseId);
String processId = expense.getProcessId();
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
//流程走完的不显示图
if (pi == null) {
return;
}
Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
//使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象
String InstanceId = task.getProcessInstanceId();
List<Execution> executions = runtimeService
.createExecutionQuery()
.processInstanceId(InstanceId)
.list();
//得到正在执行的Activity的Id
List<String> activityIds = new ArrayList<>();
List<String> flows = new ArrayList<>();
for (Execution exe : executions) {
List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
activityIds.addAll(ids);
}
//获取流程图
BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0);
OutputStream out = null;
byte[] buf = new byte[1024];
int legth = 0;
try {
out = HttpKit.getResponse().getOutputStream();
while ((legth = in.read(buf)) != -1) {
out.write(buf, 0, legth);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
package com.stylefeng.guns.modular.flowable.warpper;
import com.stylefeng.guns.core.common.constant.state.ExpenseState;
import com.stylefeng.guns.core.base.warpper.BaseControllerWarpper;
import java.util.Map;
/**
* 报销列表的包装
*
* @author fengshuonan
* @date 2017年12月4日21:56:06
*/
public class ExpenseWarpper extends BaseControllerWarpper {
public ExpenseWarpper(Object list) {
super(list);
}
@Override
public void warpTheMap(Map<String, Object> map) {
Integer state = (Integer) map.get("state");
map.put("stateName", ExpenseState.valueOf(state));
}
}
##########################################################
################## 所有profile共有的配置 #################
##########################################################
################### guns配置 ################### ################### guns配置 ###################
guns: guns:
swagger-open: true #是否开启swagger (true/false) swagger-open: true #是否开启swagger (true/false)
kaptcha-open: false #是否开启登录时验证码 (true/false) kaptcha-open: false #是否开启登录时验证码 (true/false)
#file-upload-path: d:/tmp #文件上传目录(不配置的话为java.io.tmpdir目录) # file-upload-path: d:/tmp #文件上传目录(不配置的话为java.io.tmpdir目录)
muti-datasource-open: false #是否开启多数据源(true/false) muti-datasource-open: false #是否开启多数据源(true/false)
spring-session-open: false #是否开启spring session,如果是多机环境需要开启(true/false) spring-session-open: false #是否开启spring session,如果是多机环境需要开启(true/false)
session-invalidate-time: 1800 #session失效时间(只在单机环境下生效,多机环境在SpringSessionConfig类中配置) 单位:秒 session-invalidate-time: 1800 #session失效时间(只在单机环境下生效,多机环境在SpringSessionConfig类中配置) 单位:秒
session-validation-interval: 900 #多久检测一次失效的session(只在单机环境下生效) 单位:秒 session-validation-interval: 900 #多久检测一次失效的session(只在单机环境下生效) 单位:秒
log:
path: guns-logs
################### 项目启动端口 ################### ################### 项目启动端口 ###################
server: server:
...@@ -27,12 +25,8 @@ beetl: ...@@ -27,12 +25,8 @@ beetl:
################### spring配置 ################### ################### spring配置 ###################
spring: spring:
redis:
host: localhost
port: 6379
password:
profiles: profiles:
active: dev active: @spring.active@
mvc: mvc:
static-path-pattern: /static/** static-path-pattern: /static/**
view: view:
...@@ -40,16 +34,17 @@ spring: ...@@ -40,16 +34,17 @@ spring:
http: http:
converters: converters:
preferred-json-mapper: fastjson preferred-json-mapper: fastjson
multipart:
max-request-size: 100MB #最大请求大小
max-file-size: 100MB #最大文件大小
devtools: devtools:
restart: restart:
enabled: false #是否开启开发者工具(true/false) enabled: false
additional-paths: src/main/java additional-paths: src/main/java
exclude: static/**,WEB-INF/view/** exclude: static/**,WEB-INF/view/**
aop: aop:
proxy-target-class: true #false为启用jdk默认动态代理,true为cglib动态代理 proxy-target-class: true
servlet:
multipart:
max-request-size: 100MB
max-file-size: 100MB
################### mybatis-plus配置 ################### ################### mybatis-plus配置 ###################
mybatis-plus: mybatis-plus:
...@@ -71,52 +66,30 @@ mybatis-plus: ...@@ -71,52 +66,30 @@ mybatis-plus:
--- ---
##########################################################
################### 开发环境的profile ###################
##########################################################
spring: spring:
profiles: dev profiles: local
datasource: datasource:
url: jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false url: jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root username: root
password: root password: root
db-name: guns db-name: guns
filters: log4j,wall,mergeStat filters: wall,mergeStat
#flowable数据源和多数据源配置 #多数据源配置
guns: guns:
flowable:
datasource:
url: jdbc:mysql://127.0.0.1:3306/guns_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: root
muti-datasource: muti-datasource:
default-dataSource-name: dataSourceGuns #默认的数据源名称 url: jdbc:mysql://127.0.0.1:3306/guns2?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
url: jdbc:mysql://127.0.0.1:3306/guns_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root username: root
password: root password: root
defaultDataSourceName: dataSourceGuns #默认的数据源名称
logging:
level.root: info
level.com.stylefeng: debug
path: logs/
file: guns.log
--- ---
##########################################################
################### 正式环境的profile ###################
##########################################################
spring: spring:
profiles: produce profiles: produce
datasource: datasource:
url: jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false url: jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root username: root
password: root password: root
filters: log4j,wall,mergeStat filters: wall,mergeStat
logging:
level.root: warn
path: logs/
file: guns.log
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<!-- 此xml在spring-boot-1.5.3.RELEASE.jar里 --> <!--定义日志存放的位置-->
<include resource="org/springframework/boot/logging/logback/defaults.xml" /> <springProperty scope="context" name="gunsLogPath" source="guns.log.path"
<include resource="org/springframework/boot/logging/logback/console-appender.xml" /> defaultValue="guns-logs"/>
<!-- 开启后可以通过jmx动态控制日志级别(springboot Admin的功能) -->
<!--<jmxConfigurator/>--> <!-- ****************************************************************************************** -->
<!-- ****************************** 本地开发只在控制台打印日志 ************************************ -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- ****************************************************************************************** -->
<File>${LOG_PATH}${LOG_FILE}</File> <springProfile name="local">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--encoder 默认配置为PatternLayoutEncoder-->
<encoder> <encoder>
<pattern>%date [%level] [%thread] %logger{60} [%file : %line] %msg%n</pattern> <pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder> </encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
<logger name="com.stylefeng.guns" level="debug" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
</springProfile>
<!-- ****************************************************************************************** -->
<!-- ********************** 放到服务器上不管在什么环境都只在文件记录日志 **************************** -->
<!-- ****************************************************************************************** -->
<springProfile name="!local">
<!-- 日志记录器,日期滚动记录 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${gunsLogPath}/logs/log_error.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 添加.gz 历史日志会启用压缩 大大缩小日志文件所占空间 --> <!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
<fileNamePattern>${LOG_PATH}daily/${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern> 而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<maxHistory>30</maxHistory><!-- 保留30天日志 --> <fileNamePattern>${gunsLogPath}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
命名日志文件,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy> </rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日志文件只记录error级别的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender> </appender>
<!--<logger name="org.springframework" level="error"/>--> <!-- 日志记录器,日期滚动记录 -->
<!--<logger name="jdbc.connection" level="OFF"/>--> <appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--<logger name="org.apache" level="error"/>--> <!-- 正在记录的日志文件的路径及文件名 -->
<!--<logger name="com.alibaba" level="error"/>--> <file>${gunsLogPath}/logs/log_total.log</file>
<!--<logger name="org.apache.kafka.clients.producer.ProducerConfig" level="warn"/>--> <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${gunsLogPath}/total/log-total-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
命名日志文件,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式记录日志 -->
<append>true</append>
<!-- 日志文件的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<root level="INFO"> <root level="info">
<appender-ref ref="CONSOLE"/> <appender-ref ref="FILE_ERROR"/>
<appender-ref ref="FILE"/> <appender-ref ref="FILE_ALL"/>
</root> </root>
</springProfile>
</configuration> </configuration>
<?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:flowable="http://flowable.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.flowable.org/processdef">
<process id="Expense" name="ExpenseProcess" isExecutable="true">
<documentation>报销流程</documentation>
<startEvent id="start" name="开始
"></startEvent>
<userTask id="fillTask" name="出差报销" flowable:assignee="${taskUser}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<exclusiveGateway id="judgeTask"></exclusiveGateway>
<userTask id="directorTak" name="经理审批">
<extensionElements>
<flowable:taskListener event="create" class="com.stylefeng.guns.modular.flowable.handler.ManagerTaskHandler"></flowable:taskListener>
</extensionElements>
</userTask>
<userTask id="bossTask" name="老板审批">
<extensionElements>
<flowable:taskListener event="create" class="com.stylefeng.guns.modular.flowable.handler.BossTaskHandler"></flowable:taskListener>
</extensionElements>
</userTask>
<endEvent id="end" name="结束"></endEvent>
<sequenceFlow id="directorNotPassFlow" name="驳回" sourceRef="directorTak" targetRef="fillTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="fillTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow1" sourceRef="start" targetRef="fillTask"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="fillTask" targetRef="judgeTask"></sequenceFlow>
<sequenceFlow id="judgeMore" name="大于500元" sourceRef="judgeTask" targetRef="bossTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${money > 500}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="directorPassFlow" name="通过" sourceRef="directorTak" targetRef="end">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="judgeLess" name="小于500元" sourceRef="judgeTask" targetRef="directorTak">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 500}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_Expense">
<bpmndi:BPMNPlane bpmnElement="Expense" id="BPMNPlane_Expense">
<bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
<omgdc:Bounds height="30.0" width="30.0" x="285.0" y="135.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="fillTask" id="BPMNShape_fillTask">
<omgdc:Bounds height="80.0" width="100.0" x="405.0" y="110.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
<omgdc:Bounds height="40.0" width="40.0" x="585.0" y="130.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="directorTak" id="BPMNShape_directorTak">
<omgdc:Bounds height="80.0" width="100.0" x="735.0" y="110.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="bossTask" id="BPMNShape_bossTask">
<omgdc:Bounds height="80.0" width="100.0" x="555.0" y="255.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
<omgdc:Bounds height="28.0" width="28.0" x="771.0" y="281.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="315.0" y="150.0"></omgdi:waypoint>
<omgdi:waypoint x="405.0" y="150.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="505.0" y="150.16611295681062"></omgdi:waypoint>
<omgdi:waypoint x="585.4333333333333" y="150.43333333333334"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
<omgdi:waypoint x="624.5530726256983" y="150.44692737430168"></omgdi:waypoint>
<omgdi:waypoint x="735.0" y="150.1392757660167"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="directorNotPassFlow" id="BPMNEdge_directorNotPassFlow">
<omgdi:waypoint x="785.0" y="110.0"></omgdi:waypoint>
<omgdi:waypoint x="785.0" y="37.0"></omgdi:waypoint>
<omgdi:waypoint x="455.0" y="37.0"></omgdi:waypoint>
<omgdi:waypoint x="455.0" y="110.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="bossPassFlow" id="BPMNEdge_bossPassFlow">
<omgdi:waypoint x="655.0" y="295.0"></omgdi:waypoint>
<omgdi:waypoint x="771.0" y="295.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
<omgdi:waypoint x="605.4340277777778" y="169.56597222222223"></omgdi:waypoint>
<omgdi:waypoint x="605.1384083044983" y="255.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="directorPassFlow" id="BPMNEdge_directorPassFlow">
<omgdi:waypoint x="785.0" y="190.0"></omgdi:waypoint>
<omgdi:waypoint x="785.0" y="281.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="bossNotPassFlow" id="BPMNEdge_bossNotPassFlow">
<omgdi:waypoint x="555.0" y="295.0"></omgdi:waypoint>
<omgdi:waypoint x="455.0" y="295.0"></omgdi:waypoint>
<omgdi:waypoint x="455.0" y="190.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
\ No newline at end of file
@layout("/common/_container.html"){
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>报销管理管理</h5>
</div>
<div class="ibox-content">
<div class="row row-lg">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-3">
<#NameCon id="condition" name="名称" />
</div>
<div class="col-sm-3">
<#button name="搜索" icon="fa-search" clickFun="Expense.search()"/>
</div>
</div>
<div class="hidden-xs" id="ExpenseTableToolbar" role="group">
<#button name="新增报销单" icon="fa-plus" clickFun="Expense.openAddExpense()"/>
</div>
<#table id="ExpenseTable"/>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="${ctxPath}/static/modular/flowable/expense/expense.js"></script>
@}
@layout("/common/_container.html"){
<div class="ibox float-e-margins">
<div class="ibox-content">
<div class="form-horizontal">
<input type="hidden" id="id" value="">
<div class="row">
<div class="col-sm-12">
<#input id="money" name="报销金额" underline="true"/>
<#input id="desc" name="描述"/>
</div>
</div>
<div class="row btn-group-m-t">
<div class="col-sm-12">
<#button btnCss="info" name="提交" id="ensure" icon="fa-check" clickFun="ExpenseInfoDlg.addSubmit()"/>
<#button btnCss="danger" name="取消" id="cancel" icon="fa-eraser" clickFun="ExpenseInfoDlg.close()"/>
</div>
</div>
</div>
</div>
</div>
<script src="${ctxPath}/static/modular/flowable/expense/expense_info.js"></script>
@}
@layout("/common/_container.html"){
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>报销管理管理</h5>
</div>
<div class="ibox-content">
<div class="row row-lg">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-3">
<#NameCon id="condition" name="名称" />
</div>
<div class="col-sm-3">
<#button name="搜索" icon="fa-search" clickFun="Process.search()"/>
</div>
</div>
<#table id="ProcessTable"/>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="${ctxPath}/static/modular/flowable/process/process.js"></script>
@}
package com.stylefeng.guns.flowable;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
/**
* @author fengshuonan
* @date 2017-12-02 20:57
*/
public class CallExternalSystemDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution delegateExecution) {
System.out.println("Calling the external system for employee "
+ delegateExecution.getVariable("employee"));
}
}
package com.stylefeng.guns.flowable;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.junit.Test;
/**
* 初始化flowable数据库(执行前需要先在数据库创建这个数据库,下面以数据库名flowable为例)
*
* @author fengshuonan
* @date 2017-12-02 20:32
*/
public class FlowableDbInitTest {
@Test
public void init() {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull")
.setJdbcUsername("root")
.setJdbcPassword("root")
.setJdbcDriver("com.mysql.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
}
}
package com.stylefeng.guns.flowable;
import com.alibaba.fastjson.JSON;
import org.flowable.engine.*;
import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
/**
* 工作流的业务测试
*
* @author fengshuonan
* @date 2017-12-02 20:37
*/
public class FlowableTest {
ProcessEngine processEngine;
@Before
public void init() {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/guns_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull")
.setJdbcUsername("root")
.setJdbcPassword("root")
.setJdbcDriver("com.mysql.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
processEngine = cfg.buildProcessEngine();
}
/**
* 发布流程
*/
@Test
public void deploy() {
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("ExpenseProcess.bpmn20.xml")
.deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId(deployment.getId())
.singleResult();
System.out.println("Found process definition : " + processDefinition.getName());
}
/**
* 查看发布
*/
@Test
public void findDeploy() {
RepositoryService repositoryService = processEngine.getRepositoryService();
List<Deployment> list = repositoryService.createDeploymentQuery().list();
for (Deployment deployment : list) {
System.out.println(deployment.getCategory());
System.out.println(deployment.getName());
System.out.println("deploy = " + deployment.getId());
System.out.println("key = " + deployment.getKey());
}
}
/**
* 启动流程
*/
@Test
public void start() {
HashMap<String, Object> map = new HashMap<>();
map.put("taskUser", "fsn");
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey("Expense", map);
System.out.println("pid = " + processInstance.getId());
System.out.println("activityId = " + processInstance.getActivityId());
System.out.println("getProcessDefinitionId = " + processInstance.getProcessDefinitionId());
}
/**
* 查看流程定义
*/
@Test
public void queryProcess() {
List<ProcessInstance> list1 = processEngine.getRuntimeService().createProcessInstanceQuery().list();
for (ProcessInstance processDefinition : list1) {
System.out.println("id = " + processDefinition.getId());
System.out.println("getDeploymentId = " + processDefinition.getDeploymentId());
System.out.println("getTenantId = " + processDefinition.getTenantId());
System.out.println("name = " + processDefinition.getName());
}
System.err.println("---------------------------------");
List<ProcessDefinition> list = processEngine.getRepositoryService()
.createProcessDefinitionQuery()
.list();
for (ProcessDefinition processDefinition : list) {
System.out.println("id = " + processDefinition.getId());
System.out.println("getDeploymentId = " + processDefinition.getDeploymentId());
System.out.println("getTenantId = " + processDefinition.getTenantId());
System.out.println("name = " + processDefinition.getName());
System.out.println("key = " + processDefinition.getKey());
System.out.println("version = " + processDefinition.getVersion());
System.out.println("resourceName = " + processDefinition.getResourceName());
}
}
/**
* 删除流程定义
*/
@Test
public void delProcess() {
processEngine.getRuntimeService().deleteProcessInstance("67501","abcd");
//processEngine.getRepositoryService().deleteDeployment("25001", true);
System.out.println("删除成功");
}
/**
* 查看任务
*/
@Test
public void queryMyTask() {
String name = "张三";
TaskQuery taskQuery = processEngine.getTaskService().createTaskQuery().taskAssignee(name);
List<Task> list = taskQuery.list();
for (Task task : list) {
System.out.println("name = " + task.getName());
System.out.println(JSON.toJSON(task.getTaskLocalVariables()));
}
System.out.println("查询完毕!");
}
/**
* 完成任务
*/
@Test
public void complete() {
HashMap<String, Object> map = new HashMap<>();
map.put("money", 600);
TaskService taskService = processEngine.getTaskService();
taskService.complete("47513", map);
}
public static void main(String[] args) {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull")
.setJdbcUsername("root")
.setJdbcPassword("root")
.setJdbcDriver("com.mysql.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("holiday-request.bpmn20.xml")
.deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId(deployment.getId())
.singleResult();
System.out.println("Found process definition : " + processDefinition.getName());
Scanner scanner = new Scanner(System.in);
System.out.println("Who are you?");
String employee = scanner.nextLine();
System.out.println("How many holidays do you want to request?");
Integer nrOfHolidays = Integer.valueOf(scanner.nextLine());
System.out.println("Why do you need them?");
String description = scanner.nextLine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employee", employee);
variables.put("nrOfHolidays", nrOfHolidays);
variables.put("description", description);
ProcessInstance processInstance =
runtimeService.startProcessInstanceByKey("holidayRequest", variables);
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
System.out.println("You have " + tasks.size() + " tasks:");
for (int i = 0; i < tasks.size(); i++) {
System.out.println((i + 1) + ") " + tasks.get(i).getName());
}
System.out.println("Which task would you like to complete?");
int taskIndex = Integer.valueOf(scanner.nextLine());
Task task = tasks.get(taskIndex - 1);
Map<String, Object> processVariables = taskService.getVariables(task.getId());
System.out.println(processVariables.get("employee") + " wants " +
processVariables.get("nrOfHolidays") + " of holidays. Do you approve this?");
boolean approved = scanner.nextLine().toLowerCase().equals("y");
variables = new HashMap<String, Object>();
variables.put("approved", approved);
taskService.complete(task.getId(), variables);
}
}
<?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:flowable="http://flowable.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.flowable.org/processdef">
<process id="Expense" name="ExpenseProcess" isExecutable="true">
<documentation>报销流程</documentation>
<startEvent id="start" name="开始
"></startEvent>
<userTask id="fillTask" name="出差报销" flowable:assignee="${taskUser}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<exclusiveGateway id="judgeTask"></exclusiveGateway>
<userTask id="directorTak" name="经理审批">
<extensionElements>
<flowable:taskListener event="create" class="com.stylefeng.guns.modular.flowable.handler.ManagerTaskHandler"></flowable:taskListener>
</extensionElements>
</userTask>
<userTask id="bossTask" name="老板审批">
<extensionElements>
<flowable:taskListener event="create" class="com.stylefeng.guns.modular.flowable.handler.BossTaskHandler"></flowable:taskListener>
</extensionElements>
</userTask>
<endEvent id="end" name="结束"></endEvent>
<sequenceFlow id="directorNotPassFlow" name="驳回" sourceRef="directorTak" targetRef="fillTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="fillTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow1" sourceRef="start" targetRef="fillTask"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="fillTask" targetRef="judgeTask"></sequenceFlow>
<sequenceFlow id="judgeMore" name="大于500元" sourceRef="judgeTask" targetRef="bossTask">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${money > 500}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="directorPassFlow" name="通过" sourceRef="directorTak" targetRef="end">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="judgeLess" name="小于500元" sourceRef="judgeTask" targetRef="directorTak">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 500}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_Expense">
<bpmndi:BPMNPlane bpmnElement="Expense" id="BPMNPlane_Expense">
<bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
<omgdc:Bounds height="30.0" width="30.0" x="285.0" y="135.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="fillTask" id="BPMNShape_fillTask">
<omgdc:Bounds height="80.0" width="100.0" x="405.0" y="110.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
<omgdc:Bounds height="40.0" width="40.0" x="585.0" y="130.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="directorTak" id="BPMNShape_directorTak">
<omgdc:Bounds height="80.0" width="100.0" x="735.0" y="110.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="bossTask" id="BPMNShape_bossTask">
<omgdc:Bounds height="80.0" width="100.0" x="555.0" y="255.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
<omgdc:Bounds height="28.0" width="28.0" x="771.0" y="281.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="315.0" y="150.0"></omgdi:waypoint>
<omgdi:waypoint x="405.0" y="150.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="505.0" y="150.16611295681062"></omgdi:waypoint>
<omgdi:waypoint x="585.4333333333333" y="150.43333333333334"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
<omgdi:waypoint x="624.5530726256983" y="150.44692737430168"></omgdi:waypoint>
<omgdi:waypoint x="735.0" y="150.1392757660167"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="directorNotPassFlow" id="BPMNEdge_directorNotPassFlow">
<omgdi:waypoint x="785.0" y="110.0"></omgdi:waypoint>
<omgdi:waypoint x="785.0" y="37.0"></omgdi:waypoint>
<omgdi:waypoint x="455.0" y="37.0"></omgdi:waypoint>
<omgdi:waypoint x="455.0" y="110.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="bossPassFlow" id="BPMNEdge_bossPassFlow">
<omgdi:waypoint x="655.0" y="295.0"></omgdi:waypoint>
<omgdi:waypoint x="771.0" y="295.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
<omgdi:waypoint x="605.4340277777778" y="169.56597222222223"></omgdi:waypoint>
<omgdi:waypoint x="605.1384083044983" y="255.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="directorPassFlow" id="BPMNEdge_directorPassFlow">
<omgdi:waypoint x="785.0" y="190.0"></omgdi:waypoint>
<omgdi:waypoint x="785.0" y="281.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="bossNotPassFlow" id="BPMNEdge_bossNotPassFlow">
<omgdi:waypoint x="555.0" y="295.0"></omgdi:waypoint>
<omgdi:waypoint x="455.0" y="295.0"></omgdi:waypoint>
<omgdi:waypoint x="455.0" y="190.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
\ No newline at end of file
<?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:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="holidayRequest" name="Holiday Request" isExecutable="true">
<startEvent id="startEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>
<userTask id="approveTask" name="Approve or reject request" flowable:candidateGroups="managers"/>
<sequenceFlow sourceRef="approveTask" targetRef="decision"/>
<exclusiveGateway id="decision"/>
<sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${approved}
]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="sendRejectionMail">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${!approved}
]]>
</conditionExpression>
</sequenceFlow>
<serviceTask id="externalSystemCall" name="Enter holidays in external system"
flowable:class="com.stylefeng.guns.flowable.CallExternalSystemDelegate"/>
<sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>
<userTask id="holidayApprovedTask" name="Holiday approved" flowable:assignee="${employee}"/>
<sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>
<serviceTask id="sendRejectionMail" name="Send out rejection email"
flowable:class="org.flowable.SendRejectionMail"/>
<sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
<endEvent id="approveEnd"/>
<endEvent id="rejectEnd"/>
</process>
</definitions>
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version> <version>2.0.3.RELEASE</version>
</parent> </parent>
<properties> <properties>
...@@ -42,8 +42,7 @@ ...@@ -42,8 +42,7 @@
<ehcache.core.version>2.6.11</ehcache.core.version> <ehcache.core.version>2.6.11</ehcache.core.version>
<mysql-connector-java.version>5.1.38</mysql-connector-java.version> <mysql-connector-java.version>5.1.38</mysql-connector-java.version>
<jwt.version>0.7.0</jwt.version> <jwt.version>0.7.0</jwt.version>
<flowable.version>6.2.0</flowable.version> <hutool.version>4.1.1</hutool.version>
<hutool.version>4.0.0</hutool.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
...@@ -54,12 +53,6 @@ ...@@ -54,12 +53,6 @@
<version>${guns.version}</version> <version>${guns.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-basic</artifactId>
<version>${flowable.version}</version>
</dependency>
<!--guns-->
<dependency>
<groupId>com.stylefeng</groupId> <groupId>com.stylefeng</groupId>
<artifactId>guns-core</artifactId> <artifactId>guns-core</artifactId>
<version>${guns.version}</version> <version>${guns.version}</version>
...@@ -68,7 +61,7 @@ ...@@ -68,7 +61,7 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId> <artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version> <version>2.0.3.RELEASE</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
...@@ -196,11 +189,63 @@ ...@@ -196,11 +189,63 @@
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.9.RELEASE</version>
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build> </build>
<profiles>
<profile>
<id>local</id>
<properties>
<spring.active>local</spring.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>dev</id>
<properties>
<spring.active>dev</spring.active>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<spring.active>test</spring.active>
</properties>
</profile>
<profile>
<id>produce</id>
<properties>
<spring.active>produce</spring.active>
</properties>
</profile>
</profiles>
</project> </project>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment