Activiti6工作流,搞懂模型,流程,任务,项目直接上手就干
1流程图概述
Activiti6工作流的流程设计需要经历 1模型的创建与发布 2流程的启用 3对于流程相关发起的节点任务进行申请,审批等操作
2管理模型说明
2.1创建/更新模型
1逻辑说明:
1新建一个空模型(默认后台创建,然后前端修改模型信息)
2然后页面展示绘制流程图,页面返回重定向地址:” /static/modeler.html?modelId=”(参数是返回的),默认修改后关闭自动保存)
2代码实现:
/**
* 新建一个空模型
*/
@RequestMapping("/create")
public void newModel(HttpServletRequest request, HttpServletResponse response) throws IOException {
RepositoryService repositoryService = processEngine.getRepositoryService();
// 初始化一个空模型
Model model = repositoryService.newModel();
// 设置一些默认信息
String name = "";
String description = "";
int revision = 1;
String key = "m_" + CreatedTools.getCreated();
// 设置子系统
model.setTenantId("子系统1");
ObjectNode modelNode = objectMapper.createObjectNode();
modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
model.setName(name);
model.setKey(key);
model.setMetaInfo(modelNode.toString());
repositoryService.saveModel(model);
String id = model.getId();
// 完善ModelEditorSource
ObjectNode editorNode = objectMapper.createObjectNode();
editorNode.put("id", "canvas");
editorNode.put("resourceId", "canvas");
ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
editorNode.put("stencilset", stencilSetNode);
repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
response.sendRedirect(request.getContextPath() + "/modeler.html?modelId=" + id);
}
/**
* 保存一个模型
*/
@RequestMapping(value = "/model/{modelId}/save", method = RequestMethod.PUT)
@ResponseStatus(value = HttpStatus.OK)
public void saveModel(@PathVariable String modelId, String name, String description, String json_xml,
String svg_xml) {
try {
Model model = repositoryService.getModel(modelId);
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
modelJson.put(MODEL_NAME, name);
modelJson.put(MODEL_DESCRIPTION, description);
model.setMetaInfo(modelJson.toString());
model.setName(name);
repositoryService.saveModel(model);
repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes("utf-8"));
InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));
TranscoderInput input = new TranscoderInput(svgStream);
PNGTranscoder transcoder = new PNGTranscoder();
// Setup output
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outStream);
// Do the transformation
transcoder.transcode(input, output);
final byte[] result = outStream.toByteArray();
repositoryService.addModelEditorSourceExtra(model.getId(), result);
outStream.close();
} catch (Exception e) {
LOGGER.error("Error saving model", e);
throw new ActivitiException("Error saving model", e);
}
}
3可视化页面
1.模型新增页面
2模型编辑页面
4涉及的表结构信息
表名 | 表说明 |
---|---|
act_ge_bytearray | #二进制文件表 |
字段名 | 字段说明 |
ID_ | 唯一标识 |
REV_ | |
NAME_ | |
DEPLOYMENT_ID_ | |
BYTES_ | 文件流 |
GENERATED_ |
2.2发布模型
1逻辑说明:
1选择模型进行发布操作
注意:1每次更改后需要重新发布,否则模型未更新;
2根据模型Id判断模型是否发布(已经发布的模型存在运行中的流程,需要先处理流程然后再发布);
3模型设计需要有主线流程(开始结束任务否则提示修改重新发布),在部署表中创建部署的信息,同时在二进制文件表中存储模型的信息
2代码实现:
/**
* 发布模型为流程定义
*/
@RequestMapping("/deploy")
@ResponseBody
public Object deploy(String modelId) throws Exception {
// 获取模型
RepositoryService repositoryService = processEngine.getRepositoryService();
Model modelData = repositoryService.getModel(modelId);
byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
if (bytes == null) {
return "模型数据为空,请先设计流程并成功保存,再进行发布。";
}
JsonNode modelNode = new ObjectMapper().readTree(bytes);
BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
model.setTargetNamespace(modelData.getCategory());
if (model.getProcesses().size() == 0) {
return "数据模型不符要求,请至少设计一条主线流程。";
}
byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
// 发布流程
String processName = modelData.getName() + ".bpmn20.xml";
Deployment deployment = repositoryService.createDeployment().name(modelData.getName())
.category(modelData.getCategory()).addString(processName, new String(bpmnBytes, "UTF-8")).deploy();
modelData.setDeploymentId(deployment.getId());
repositoryService.saveModel(modelData);
return "SUCCESS";
}
3可视化页面
4涉及的表结构信息
表名 | 表说明 |
---|---|
act_re_deployment | #流程部署表 |
2.3查询模型
1逻辑说明:
1查询模型
2代码实现:
/**
* 获取所有模型
*/
@RequestMapping("/modelList")
@ResponseBody
public Object modelList(String name) {
if (name == null) {
name = "";
}
RepositoryService repositoryService = processEngine.getRepositoryService();
return repositoryService.createModelQuery().modelNameLike("%" + name + "%").modelTenantId("子系统1").list();
}
/**
* 分页查询
*/
@RequestMapping("/modelListPage")
@ResponseBody
public Object modelListPage(String name,int page, int limit) {
if (name == null) {
name = "";
}
RepositoryService repositoryService = processEngine.getRepositoryService();
int totalCount = (int) repositoryService.createModelQuery().modelNameLike("%" + name + "%").modelTenantId("子系统1").count();
List<Model> list = repositoryService.createModelQuery().modelNameLike("%" + name + "%").modelTenantId("子系统1").listPage((page - 1) * limit, page * limit);
Map<String, Object> map = new HashMap<>();
map.put("list", list);
map.put("page", page);
map.put("limit", limit);
map.put("totalRow", totalCount);
return map;
}
3可视化页面
4涉及的表结构信息
表名 | 表说明 |
---|---|
act_ge_bytearray | #二进制文件表 |
字段名 | 字段说明 |
ID_ | 唯一标识 |
REV_ | |
NAME_ | |
DEPLOYMENT_ID_ | |
BYTES_ | 文件流 |
GENERATED_ |
2.4删除模型
1逻辑说明:
1删除模型前需要判断是否存在正在执行的流程,存在需要先处理流程,硬删除,删除表act_ge_bytearry模型信息(为发布的模型)1
2代码实现:
/**
* 删除工作流模型
*/
@RequestMapping("/deleteModel")
@ResponseBody
public Object deleteModel(String modelId) {
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.deleteModel(modelId);
return "SUCCESS";
}
3可视化页面
4涉及的表结构信息
表名 | 表说明 |
---|---|
act_re_procdef; | #流程定义 |
3管理流程说明
3.1启动流程型
1逻辑说明:
1.首先需要确定根据流程部署Id获取流程定义
2.可以自定义对象进行配置
3.启动流程
2代码实现:
// 启动一个流程实例
@GetMapping("/activiti_define_start")
@ResponseBody
public Wrapper<String> activiti_define_start(@Valid String id) {
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
Map<String, Object> varaiables = new HashMap<>();
// ...此处可注入变量
varaiables.put("username", "111");
varaiables.put("userNames", "111,222");
ProcessInstance pi = runtimeService.startProcessInstanceById(id, varaiables);
runtimeService.setProcessInstanceName(pi.getId(), pd.getName());
logger.info("启动流程实例,获取id-->{},实例名称-->{}", pi.getId(), pd.getName());
return WrapMapper.ok(pi.getId());
}
3可视化页面
4涉及的表结构信息
表名 | 表说明 |
---|---|
act_ru_execution | #流程启动一次只要没有执行完就会有一条数据 |
act_ru_task | #可能记录多条数据 |
act_ru_variable | #记录流程运行时的流程变量 |
act_ru_identitylink | #存放流程办理人的信息 |
act_hi_procinst | #历史流程实例 |
act_hi_taskinst | #历史任务实例 |
act_hi_actinst | #历史活动节点表 |
act_hi_varinst | #历史流程变量表 |
act_hi_identitylink | #历史办理人表 |
act_hi_comment | #批注表 |
act_hi_attachment | #附件表 |
3.2查询流程
逻辑:根据流程实例查询获取流程图信息
/**
* 查询流程定义列表
*
* @return
*/
@RequestMapping("/activitDefineList")
@ResponseBody
public List<Map<String, Object>> activitDefineList(String name) {
// 创建查询对象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 使用部署对象ID查询
// processDefinitionQuery.deploymentId(deploymentId);
// 使用流程定义ID查询
// processDefinitionQuery.processDefinitionId(processDefinitionId)
// 使用流程定义的KEY查询
// processDefinitionQuery.processDefinitionKey(processDefinitionKey)
// 使用流程定义的名称模糊查询
if (name == null || "".equals(name.trim())) {
} else {
processDefinitionQuery.processDefinitionNameLike("%" + name + "%");
}
List<ProcessDefinition> list = processDefinitionQuery.list();
return ActivitiTools.turnProcessDefinitions(list);
}
@RequestMapping("/activitiInstanceList")
public List<Map<String, Object>> activitiInstanceList(String name) {
// 创建查询对象
ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
if (name != null && !"".equals(name)) {
processInstanceQuery.processInstanceNameLike("%" + name + "%");
}
List<ProcessInstance> list = processInstanceQuery.list();
return ActivitiTools.turnProcessInstances(list);
}
4管理任务说明
4.1申请的任务
1逻辑说明:
1.查询申请的任务清单
2代码实现:
@RequestMapping("/todoTaskList")
@ResponseBody
public List<Map<String, Object>> todoTaskList(String name) {
// 创建查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
if (name != null && !"".equals(name)) {
taskQuery.processDefinitionNameLike("%" + name + "%");
}
// 设置查询条件
// 根据任务的办理人查询
// taskQuery.taskAssignee(assignee);
// 指定流程定义key,只查询某个流程的任务
// taskQuery.processDefinitionKey(processDefinitionKey);
// 获取查询列表
List<Task> list = taskQuery.list();
List<Map<String, Object>> listEnd = ActivitiTools.turnTasks(list);
// 分页时用,非分页慎用
/*
* ProcessInstanceQuery instanceQuery =
* runtimeService.createProcessInstanceQuery(); for (Map<String, Object> map :
* listEnd) { String processDefinitionId = (String)
* map.get("processDefinitionId"); if (processDefinitionId != null) {
* List<ProcessInstance> processInstanceList =
* instanceQuery.processDefinitionId(processDefinitionId).list(); if
* (processInstanceList != null) { for (ProcessInstance processInstance :
* processInstanceList) { map.put("processInstanceName",
* processInstance.getName()); } } } }
*/
return listEnd;
}
3可视化页面
4涉及的表结构信息
4.2审批的任务
1逻辑说明:
1.查询待审批的任务清单
2代码实现:
@RequestMapping("/mineTodoTaskList")
@ResponseBody
public List<Map<String, Object>> todoTaskList(String name, String user_id, String depart_id) {
// 创建查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
TaskQuery taskQuery1 = taskService.createTaskQuery();
if (name != null && !"".equals(name)) {
taskQuery.processDefinitionNameLike("%" + name + "%");
taskQuery1.processDefinitionNameLike("%" + name + "%");
}
taskQuery.taskCandidateOrAssigned(user_id);
taskQuery1.taskCandidateOrAssigned(depart_id);
// 设置查询条件
// 根据任务的办理人查询
// taskQuery.taskAssignee(assignee);
// 指定流程定义key,只查询某个流程的任务
// taskQuery.processDefinitionKey(processDefinitionKey);
// 获取查询列表
List<Task> list = taskQuery.list();
List<Task> list1 = taskQuery1.list();
list.addAll(list1);
List<Map<String, Object>> listEnd = ActivitiTools.turnTasks(list);
return listEnd;
}
4.3提交申请
1逻辑说明:
1.提交审批任务
2.更新form表单信息
2代码实现:
@PostMapping("/submit")
public Wrapper<String> submit(@Valid @RequestBody FormSubmitDto formSubmitDto) {
String task_id = formSubmitDto.getTask_id();
String form = formSubmitDto.getForm();
Task task = taskService.createTaskQuery().taskId(task_id).singleResult();
if (task == null) {
return WrapMapper.ok("您已提交成功!");
}
logger.info("表单提交...");
JSONObject formJson = JsonUtil.jsonStrToJsonObject(form);
logger.info("formJson--{}", formJson);
Set<String> keySet = formJson.keySet();
for (String key : keySet) {
Object val = formJson.getString(key);
logger.info("{}:{}", key, val);
taskService.setVariable(task.getId(), key, val);
taskService.setVariableLocal(task.getId(), key, val);
}
// 保存表单以及表单的值
formValsService.saveFormVals(formSubmitDto);
logger.info("表单相关操作完成!");
taskService.complete(task.getId());
logger.info("检查重复审批人, 自动去重.");
// formDuplicateService.doDuplicateTask(task.getProcessInstanceId());
logger.info("根据完成时间,自动设置提醒方式.");
modelJsonService.dueNextTaskPushHandle(task.getProcessInstanceId());
return WrapMapper.ok("提交成功!");
}
4.4提交审批
1逻辑说明:
1.提交审批任务
2.更新form表单信息
2代码实现:
@PostMapping("/submit")
public Wrapper<String> submit(@Valid @RequestBody FormSubmitDto formSubmitDto) {
String task_id = formSubmitDto.getTask_id();
String form = formSubmitDto.getForm();
Task task = taskService.createTaskQuery().taskId(task_id).singleResult();
if (task == null) {
return WrapMapper.ok("您已提交成功!");
}
logger.info("表单提交...");
JSONObject formJson = JsonUtil.jsonStrToJsonObject(form);
logger.info("formJson--{}", formJson);
Set<String> keySet = formJson.keySet();
for (String key : keySet) {
Object val = formJson.getString(key);
logger.info("{}:{}", key, val);
taskService.setVariable(task.getId(), key, val);
taskService.setVariableLocal(task.getId(), key, val);
}
// 保存表单以及表单的值
formValsService.saveFormVals(formSubmitDto);
logger.info("表单相关操作完成!");
taskService.complete(task.getId());
logger.info("检查重复审批人, 自动去重.");
// formDuplicateService.doDuplicateTask(task.getProcessInstanceId());
logger.info("根据完成时间,自动设置提醒方式.");
modelJsonService.dueNextTaskPushHandle(task.getProcessInstanceId());
return WrapMapper.ok("提交成功!");
}
五额外说明
1关于受理人概念
当一个流程被启动的时候,我们可以在节点上选择受理人是谁,如果选择并且填写了受理人
1受理人有值,XML流程里面定义的受理人,TASK会直接填入这个人
2受理人无值,可以使用签收功能去指定受理人,就是候选组里面谁签收谁就成了受理人
Task task=taskService.createTaskQuery().singleResult();
//签收
taskService.claim(task.getId(), "billy");
logger.info(taskService.createTaskQuery().singleResult().getAssignee());
2关于委托人概念
受理人委托其他人操作该TASK的时候,受理人就成了委托人OWNER_,其他人就成了受理人ASSIGNEE_
Task task=taskService.createTaskQuery().singleResult();
//委托
taskService.delegateTask(task.getId(), "cc");
logger.info(taskService.createTaskQuery().singleResult().getOwner());
logger.info(taskService.createTaskQuery().singleResult().getAssignee());
//结果:owner是Billy,assignee是cc
2受理人无值,可以使用签收功能去指定受理人,就是候选组里面谁签收谁就成了受理人
Task task=taskService.createTaskQuery().singleResult();
//签收
taskService.claim(task.getId(), "billy");
logger.info(taskService.createTaskQuery().singleResult().getAssignee());
2关于委托人概念
受理人委托其他人操作该TASK的时候,受理人就成了委托人OWNER_,其他人就成了受理人ASSIGNEE_
Task task=taskService.createTaskQuery().singleResult();
//委托
taskService.delegateTask(task.getId(), "cc");
logger.info(taskService.createTaskQuery().singleResult().getOwner());
logger.info(taskService.createTaskQuery().singleResult().getAssignee());
//结果:owner是Billy,assignee是cc