Commit 7bfead66 by stylefeng

移除flowable,升级spring boot 2.0

parent bd04afe2
# 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.1新增集成工作流引擎flowable6.2.0!
## 最新Guns技术文档
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 @@
<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>
<groupId>com.stylefeng</groupId>
<artifactId>guns-core</artifactId>
......@@ -145,14 +129,6 @@
<build>
<plugins>
<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>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
......@@ -166,6 +142,7 @@
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
......
package com.stylefeng.guns;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* 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;
}
}
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:
swagger-open: true #是否开启swagger (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)
spring-session-open: false #是否开启spring session,如果是多机环境需要开启(true/false)
session-invalidate-time: 1800 #session失效时间(只在单机环境下生效,多机环境在SpringSessionConfig类中配置) 单位:秒
session-validation-interval: 900 #多久检测一次失效的session(只在单机环境下生效) 单位:秒
log:
path: guns-logs
################### 项目启动端口 ###################
server:
......@@ -27,12 +25,8 @@ beetl:
################### spring配置 ###################
spring:
redis:
host: localhost
port: 6379
password:
profiles:
active: dev
active: @spring.active@
mvc:
static-path-pattern: /static/**
view:
......@@ -40,16 +34,17 @@ spring:
http:
converters:
preferred-json-mapper: fastjson
multipart:
max-request-size: 100MB #最大请求大小
max-file-size: 100MB #最大文件大小
devtools:
restart:
enabled: false #是否开启开发者工具(true/false)
enabled: false
additional-paths: src/main/java
exclude: static/**,WEB-INF/view/**
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:
......@@ -71,52 +66,30 @@ mybatis-plus:
---
##########################################################
################### 开发环境的profile ###################
##########################################################
spring:
profiles: dev
profiles: local
datasource:
url: jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: root
db-name: guns
filters: log4j,wall,mergeStat
filters: wall,mergeStat
#flowable数据源和多数据源配置
#多数据源配置
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:
default-dataSource-name: dataSourceGuns #默认的数据源名称
url: jdbc:mysql://127.0.0.1:3306/guns_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
url: jdbc:mysql://127.0.0.1:3306/guns2?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: root
logging:
level.root: info
level.com.stylefeng: debug
path: logs/
file: guns.log
defaultDataSourceName: dataSourceGuns #默认的数据源名称
---
##########################################################
################### 正式环境的profile ###################
##########################################################
spring:
profiles: produce
datasource:
url: jdbc:mysql://127.0.0.1:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: root
filters: log4j,wall,mergeStat
logging:
level.root: warn
path: logs/
file: guns.log
filters: wall,mergeStat
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 此xml在spring-boot-1.5.3.RELEASE.jar里 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<!-- 开启后可以通过jmx动态控制日志级别(springboot Admin的功能) -->
<!--<jmxConfigurator/>-->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_PATH}${LOG_FILE}</File>
<!--定义日志存放的位置-->
<springProperty scope="context" name="gunsLogPath" source="guns.log.path"
defaultValue="guns-logs"/>
<!-- ****************************************************************************************** -->
<!-- ****************************** 本地开发只在控制台打印日志 ************************************ -->
<!-- ****************************************************************************************** -->
<springProfile name="local">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--encoder 默认配置为PatternLayoutEncoder-->
<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>
</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">
<!-- 添加.gz 历史日志会启用压缩 大大缩小日志文件所占空间 -->
<fileNamePattern>${LOG_PATH}daily/${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>30</maxHistory><!-- 保留30天日志 -->
<!-- 归档的日志文件的路径,例如今天是2013-12-21日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
而2013-12-21的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<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>
<!-- 追加方式记录日志 -->
<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>
<!--<logger name="org.springframework" level="error"/>-->
<!--<logger name="jdbc.connection" level="OFF"/>-->
<!--<logger name="org.apache" level="error"/>-->
<!--<logger name="com.alibaba" level="error"/>-->
<!--<logger name="org.apache.kafka.clients.producer.ProducerConfig" level="warn"/>-->
<!-- 日志记录器,日期滚动记录 -->
<appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${gunsLogPath}/logs/log_total.log</file>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<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">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
<root level="info">
<appender-ref ref="FILE_ERROR"/>
<appender-ref ref="FILE_ALL"/>
</root>
</springProfile>
</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 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<version>2.0.3.RELEASE</version>
</parent>
<properties>
......@@ -42,8 +42,7 @@
<ehcache.core.version>2.6.11</ehcache.core.version>
<mysql-connector-java.version>5.1.38</mysql-connector-java.version>
<jwt.version>0.7.0</jwt.version>
<flowable.version>6.2.0</flowable.version>
<hutool.version>4.0.0</hutool.version>
<hutool.version>4.1.1</hutool.version>
</properties>
<dependencyManagement>
......@@ -54,12 +53,6 @@
<version>${guns.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-basic</artifactId>
<version>${flowable.version}</version>
</dependency>
<!--guns-->
<dependency>
<groupId>com.stylefeng</groupId>
<artifactId>guns-core</artifactId>
<version>${guns.version}</version>
......@@ -68,7 +61,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<version>2.0.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
......@@ -196,11 +189,63 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.9.RELEASE</version>
</plugin>
</plugins>
</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>
<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>
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