首先是依赖
<!--flowable工作流依赖-->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.3.0</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
注意mysql版本问题 否则会报错
之后
配置数据源
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/flowable-spring-boot?characterEncoding=UTF-8
username: root
password: root
flowable:
activity-font-name: \u5B8B\u4F53(宋体)
label-font-name: \u5B8B\u4F53
annotation-font-name: \u5B8B\u4F53
check-process-definitions: false
这里上传文件与流程类型选择
在后台首先进行文件类型校对
boolean temp = Objects.requireNonNull(file.getOriginalFilename()).endsWith(FlowEngineConstant.SUFFIX);
String SUFFIX = ".bpmn20.xml";
即校对文件后缀名
之后就是执行具体的方法部署
public R deployUpload(@RequestParam List<MultipartFile> files, @RequestParam String category) {
return R.status(flowService.deployUpload(files, category));
}
@Override
public boolean deployUpload(List<MultipartFile> files, String category) {
files.forEach(file -> {
try {
String fileName = file.getOriginalFilename();
InputStream fileInputStream = file.getInputStream();
//repositoryService.createDeployment(); //流程部署对象,返会deploymentBuilder
//加载流程文件,从类路径加载
// // deploymentBuilder.addInputStream
//2.使用InputStream加载 (替换自己的文件路径)
//执行部署,直到调用deploy()方法才是真正的部署到引擎中了
//同时会在act_ge_bytearray ,act_re_deployment ,act_re_procdef这3个表中插入相关信息
//与以前的教程不一样的是,别的教程中会经常将流程图片和流程bpmn文件一起部署,但我认为有点多余了,因为在部署bpmn的时候会自动生成流程图片
Deployment deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
//定义流程
deploy(deployment, category);
} catch (IOException e) {
e.printStackTrace();
}
});
return true;
}
然后给定义好的流程 配好类型
private boolean deploy(Deployment deployment, String category) {
log.debug("流程部署--------deploy: " + deployment + " 分类---------->" + category);
// 使用repositoryService查询多个流程实例
//createProcessDefinitionQuery()//查询过程定义。返回processDefinitionQuery
// processDefinitionQuery.deploymentId("1");//使用部署对象ID查询
// List<ProcessDefinition> list = processDefinitionQuery.list();//多个结果集
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
StringBuilder logBuilder = new StringBuilder(500);
List<Object> logArgs = new ArrayList<>();
// 设置流程分类
for (ProcessDefinition processDefinition : list) {
if (StringUtil.isNotBlank(category)) {
repositoryService.setProcessDefinitionCategory(processDefinition.getId(), category);
}
logBuilder.append("部署成功,流程ID={} \n");
logArgs.add(processDefinition.getId());
}
if (list.size() == 0) {
throw new ServiceException("部署失败,未找到流程");
} else {
log.info(logBuilder.toString(), logArgs.toArray());
return true;
}
}
上传部署工作完成
然后就可以看到
public R<IPage<FlowProcess>> list(@ApiParam("流程类型") String category, Query query) {
IPage<FlowProcess> pages = flowService.selectProcessPage(Condition.getPage(query), category);
return R.data(pages);
}
private static final String IMAGE_NAME = "image";
private static final String XML_NAME = "xml";
@Override
public IPage<FlowProcess> selectProcessPage(IPage<FlowProcess> page, String category) {
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionKey().asc();
if (StringUtils.isNotEmpty(category)) {
//加入查询条件
processDefinitionQuery.processDefinitionCategory(category);
}
//查询流程定义
List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(Func.toInt((page.getCurrent() - 1) * page.getSize()), Func.toInt(page.getSize()));
List<FlowProcess> flowProcessList = new ArrayList<>();
//将flowable内部的流程放到转为自己的进行使用
processDefinitionList.forEach(processDefinition -> {
String deploymentId = processDefinition.getDeploymentId();
//ProcessDefinition processDefinition = processDefinitionQuery.singleResult();//唯一结果集
Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
FlowProcess flowProcess = new FlowProcess((ProcessDefinitionEntityImpl) processDefinition);
flowProcess.setDeploymentTime(deployment.getDeploymentTime());
flowProcessList.add(flowProcess);
});
page.setTotal(processDefinitionQuery.count());
page.setRecords(flowProcessList);
return page;
}
然后流程图显示:
private static final String IMAGE_NAME = "image";
private static final String XML_NAME = "xml";
private static final Integer INT_1024 = 1024;
@GetMapping("resource-view")
public void resourceView(@RequestParam String processDefinitionId, String processInstanceId, @RequestParam(defaultValue = IMAGE_NAME) String resourceType, HttpServletResponse response) throws Exception {
if (StringUtil.isAllBlank(processDefinitionId, processInstanceId)) {
return;
}
if (StringUtil.isBlank(processDefinitionId)) {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
processDefinitionId = processInstance.getProcessDefinitionId();
}
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
String resourceName = "";
if (resourceType.equals(IMAGE_NAME)) {
resourceName = processDefinition.getDiagramResourceName();
} else if (resourceType.equals(XML_NAME)) {
resourceName = processDefinition.getResourceName();
}
通过一个字节流提供对部署资源的访问。InputStream getResourceAsStream(String deploymentId, String resourceName);
InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
byte[] b = new byte[1024];
int len;
while ((len = resourceAsStream.read(b, 0, INT_1024)) != -1) {
response.getOutputStream().write(b, 0, len);
}
}
变更流程状态为
public R changeState(@RequestParam String state, @RequestParam String processId) {
String msg = flowService.changeState(state, processId);
return R.success(msg);
}
@Override
public String changeState(String state, String processId) {
if (state.equals(FlowEngineConstant.ACTIVE)) {
repositoryService.activateProcessDefinitionById(processId, true, null);
return StringUtil.format("激活ID为 [{}] 的流程成功", processId);
} else if (state.equals(FlowEngineConstant.SUSPEND)) {
repositoryService.suspendProcessDefinitionById(processId, true, null);
return StringUtil.format("挂起ID为 [{}] 的流程成功", processId);
} else {
return "暂无流程变更";
}
}
删除流程
public R deleteDeployment(String deploymentIds) {
return R.status(flowService.deleteDeployment(deploymentIds));
}
@Override
public boolean deleteDeployment(String deploymentIds) {
Func.toStrList(deploymentIds).forEach(
deploymentId -> repositoryService.deleteDeployment(deploymentId, true));
return true;
}
至此完成整个工作流的部署工作
RepositoryService服务类
一共47个接口
1.创建部署
//开始创建一个新的部署。
DeploymentBuilder createDeployment();
2.删除部署(3个)
//删除给定的部署。
void deleteDeployment(String deploymentId);
//将给定的部署和级联删除删除到流程实例、历史流程实例和作业。
void deleteDeploymentCascade(String deploymentId);
//同上
void deleteDeployment(String deploymentId, boolean cascade);
3.设置部署
//设置部署的类别。
可以按类别查询部署:参见{@link DeploymentQuery#deploymentCategory(String)}。
void setDeploymentCategory(String deploymentId, String category);
4.获取部署
//检索给定部署的部署资源列表,按字母顺序排列。
List<String> getDeploymentResourceNames(String deploymentId);
//通过一个字节流提供对部署资源的访问。
InputStream getResourceAsStream(String deploymentId, String resourceName);
//实验功能
更改部署的租户标识符,以匹配给定的租户标识符。
这一变化将波及任何相关实体:
void changeDeploymentTenantId(String deploymentId, String newTenantId);
5.创建
//查询过程定义。
ProcessDefinitionQuery createProcessDefinitionQuery();
//为流程定义返回一个新{@link org.activiti.engine.query.NativeQuery}。
NativeProcessDefinitionQuery createNativeProcessDefinitionQuery();
//查询部署。
DeploymentQuery createDeploymentQuery();
//返回一个新的部署{@link org.activiti.engine.query.NativeQuery}
NativeDeploymentQuery createNativeDeploymentQuery();
6.暂停流程
//用给定的id暂停流程定义。
void suspendProcessDefinitionById(String processDefinitionId);
//同上
void suspendProcessDefinitionById(String processDefinitionId, boolean suspendProcessInstances, Date suspensionDate);
//用给定的键(= id in the bpmn20.xml file)挂起所有的进程定义。
xml文件)。
void suspendProcessDefinitionByKey(String processDefinitionKey);
//同上
void suspendProcessDefinitionByKey(String processDefinitionKey, boolean suspendProcessInstances, Date suspensionDate);
//类似{@link #suspendProcessDefinitionByKey(String)}但只适用于给定的租户标识符。
void suspendProcessDefinitionByKey(String processDefinitionKey, String tenantId);
//类似{@link #suspendProcessDefinitionByKey(String, boolean, Date)}但只适用于给定的租户标识符。
void suspendProcessDefinitionByKey(String processDefinitionKey, boolean suspendProcessInstances, Date suspensionDate, String tenantId);
7.激活流程
//用给定的id激活流程定义。
void activateProcessDefinitionById(String processDefinitionId);
//同上
void activateProcessDefinitionById(String processDefinitionId, boolean activateProcessInstances, Date activationDate);
//用给定的key(=id in the bpmn20.xml file)激活流程定义。
void activateProcessDefinitionByKey(String processDefinitionKey);
//同上
void activateProcessDefinitionByKey(String processDefinitionKey, boolean activateProcessInstances, Date activationDate);
//类似于{@link #activateProcessDefinitionByKey(String)}但只适用于给定的租户标识符。
void activateProcessDefinitionByKey(String processDefinitionKey, String tenantId);
//类似于{@link #activateProcessDefinitionByKey(String, boolean, Date)}但只适用于给定的租户标识符。
void activateProcessDefinitionByKey(String processDefinitionKey, boolean activateProcessInstances, Date activationDate, String tenantId);
8.设置流程定义类别
//设置流程定义的类别。
流程定义可以查询类别:看到{ @link ProcessDefinitionQuery # processDefinitionCategory(String)}。
void setProcessDefinitionCategory(String processDefinitionId, String category);
9.访问已部署流程
//提供对已部署过程模型的访问,例如,一个BPMN 2.0 XML文件,通过一个字节流。
InputStream getProcessModel(String processDefinitionId);
//提供对已部署流程图的访问,例如PNG图像,通过一个字节流。
InputStream getProcessDiagram(String processDefinitionId);
//返回{@link ProcessDefinition},包括所有BPMN信息,如附加属性(如文档)。
ProcessDefinition getProcessDefinition(String processDefinitionId);
//使用提供的流程定义id返回与流程定义对应的{@link BpmnModel}。
BpmnModel getBpmnModel(String processDefinitionId);
10.检测流程状态
//检查流程定义是否被挂起。
boolean isProcessDefinitionSuspended(String processDefinitionId);
//在流程关系图中提供元素的位置和维度,如{@link RepositoryService#getProcessDiagram(String)}所提供的。
DiagramLayout getProcessDiagramLayout(String processDefinitionId);
11.模型的增删改查
//创建一个新的model,他的模型是暂时的,必须使用{@link #saveModel(模型)}来保存。
Model newModel();
//保存模型。
如果模型已经存在,那么模型就会被更新,否则就会创建一个新的模型。
void saveModel(Model model);
//删除model
void deleteModel(String modelId);
//为模型保存模型编辑器源。
void addModelEditorSource(String modelId, byte[] bytes);
//同上
void addModelEditorSourceExtra(String modelId, byte[] bytes);
//创建查询模型
ModelQuery createModelQuery();
//为流程定义返回一个新{@link org.activiti.engine.query.NativeQuery}
NativeModelQuery createNativeModelQuery();
//返回{@link Model}
Model getModel(String modelId);
//以字节数组的形式返回模型编辑器源。
byte[] getModelEditorSource(String modelId);
//同上
byte[] getModelEditorSourceExtra(String modelId);
12.授权用户
//授权候选用户进行流程定义。
void addCandidateStarterUser(String processDefinitionId, String userId);
//授权候选用户组进行流程定义。
void addCandidateStarterGroup(String processDefinitionId, String groupId);
//删除候选用户对流程定义的授权。
void deleteCandidateStarterUser(String processDefinitionId, String userId);
//删除候选用户组对流程定义的授权。
void deleteCandidateStarterGroup(String processDefinitionId, String groupId);
//检索与给定进程定义关联的{@link IdentityLink}。
这样的{@link IdentityLink}通知了一个特定的标识(如。
组或用户)被授权用于特定的流程定义。
List<IdentityLink> getIdentityLinksForProcessDefinition(String processDefinitionId);
//根据对Activiti引擎执行流程定义的规则,验证给定的流程定义。
List<ValidationError> validateProcess(BpmnModel bpmnModel);
还有一些其他的可以自己去查看