什么是Activiti?
Activiti5是由Alfresco軟件在2010年5月17日發(fā)布的業(yè)務(wù)流程管理(BPM)框架孟抗,它是覆蓋了業(yè)務(wù)流程管理躲胳、工作流龄糊、服務(wù)協(xié)作等領(lǐng)域的一個(gè)開源的扬绪、靈活的奶甘、易擴(kuò)展的可執(zhí)行流程語言框架挥吵。Activiti基于Apache許可的開源BPM平臺重父,創(chuàng)始人Tom Baeyens是JBoss jBPM的項(xiàng)目架構(gòu)師,它特色是提供了eclipse插件忽匈,開發(fā)人員可以通過插件直接繪畫出業(yè)務(wù)流程圖房午。本文采用activiti5.22版本。數(shù)據(jù)庫是ORACLE11g
1.Activiti數(shù)據(jù)庫結(jié)構(gòu)
1)通過運(yùn)行activiti官方提供的數(shù)據(jù)庫腳本創(chuàng)建數(shù)據(jù)庫丹允,支持db2郭厌、h2袋倔、hsql、mssql沪曙、mysql奕污、oracle、postgres數(shù)據(jù)庫
1液走、act_ge_ 通用數(shù)據(jù)表碳默,ge是general的縮寫
2、act_hi_ 歷史數(shù)據(jù)表缘眶,hi是history的縮寫嘱根,對應(yīng)HistoryService接口
3、act_id_ 身份數(shù)據(jù)表巷懈,id是identity的縮寫该抒,對應(yīng)IdentityService接口
4、act_re_ 流程存儲表顶燕,re是repository的縮寫凑保,對應(yīng)RepositoryService接口,存儲流程部署和流程定義等靜態(tài)數(shù)據(jù)
5涌攻、act_ru_ 運(yùn)行時(shí)數(shù)據(jù)表欧引,ru是runtime的縮寫,對應(yīng)RuntimeService接口
2.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 定義流程引擎配置 -->
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="databaseSchemaUpdate" value="true"/>
<property name="jobExecutorActivate" value="false"/>
</bean>
<!-- 定義流程引擎 -->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"/>
</bean>
<!-- 定義Service服務(wù) -->
<bean id="repositoryService" factory-bean="processEngine"
factory-method="getRepositoryService"/>
<bean id="runtimeService" factory-bean="processEngine"
factory-method="getRuntimeService"/>
<bean id="taskService" factory-bean="processEngine"
factory-method="getTaskService"/>
<bean id="historyService" factory-bean="processEngine"
factory-method="getHistoryService"/>
<bean id="managementService" factory-bean="processEngine"
factory-method="getManagementService"/>
<bean id="identityService" factory-bean="processEngine"
factory-method="getIdentityService"/>
<bean id="formService" factory-bean="processEngine"
factory-method="getFormService"></bean>
</beans>
七大接口:
1.RepositoryService:提供一系列管理流程部署和流程定義的API恳谎。
2.RuntimeService:在流程運(yùn)行時(shí)對流程實(shí)例進(jìn)行管理與控制芝此。
3.TaskService:對流程任務(wù)進(jìn)行管理,例如任務(wù)提醒因痛、任務(wù)完成和創(chuàng)建任務(wù)等婚苹。
4.IdentityService:提供對流程角色數(shù)據(jù)進(jìn)行管理的API,這些角色數(shù)據(jù)包括用戶組鸵膏、用戶及它們之間的關(guān)系膊升。
5.ManagementService:提供對流程引擎進(jìn)行管理和維護(hù)的服務(wù)。
6.HistoryService:對流程的歷史數(shù)據(jù)進(jìn)行操作谭企,包括查詢用僧、刪除這些歷史數(shù)據(jù)。
7.FormService:表單服務(wù)赞咙。
3.activiti-webapp-explorer2整合
1)將模板導(dǎo)入項(xiàng)目中
explorer整合實(shí)現(xiàn)在線編輯工作流
將src目錄下diagram-viewer责循,editor-app,modeler.html 復(fù)制到自己項(xiàng)目中攀操,如下圖院仿,本文是復(fù)制到webapp下
2)配置全局路徑
配置前段訪問路徑,否則activiti編輯器會(huì)無法訪問
/*
* Activiti Modeler component part of the Activiti project
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
'use strict';
var ACTIVITI = ACTIVITI || {};
ACTIVITI.CONFIG = {
'contextRoot' : '/',#配置全文訪問路徑
};
3)后臺配置
1.配置后臺,頁面訪問接口配置歹垫,activti提供了基本的頁面獲取剥汤、流程保存、流程編輯等接口排惨,用于工作流的在線演示與編輯吭敢。
2.將stencilset.json賦值到配置文件目錄下,保證StencilsetRestResource能訪問到暮芭,這是流程設(shè)計(jì)器的菜單和功能文件鹿驼,保存為json格式。
4.后臺實(shí)例代碼
1)創(chuàng)建流程
/**
* 創(chuàng)建流程
*/
@RequestMapping("/createActiviti")
public void createActiviti(HttpServletRequest request,HttpServletResponse response) throws IOException{
Model model = repositoryService.newModel();
String name = "新建流程";
String description = "";
int revision = 1;
String key = "processKey";
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"));
// return "redirect:/modeler.html?modelId=" + id;
response.sendRedirect(request.getContextPath() + "/modeler.html?modelId="+id);
}
2)更新流程
/**
* 更新流程
*/
@RequestMapping("/updateActiviti")
public void updateActiviti(String id,HttpServletRequest request,HttpServletResponse response) throws IOException{
response.sendRedirect(request.getContextPath() + "/modeler.html?modelId="+id);
}
3)發(fā)布流程
/**
* 發(fā)布
*/
@PostMapping("/publish")
@ResponseBody
public Object publish(@RequestParam(value="id")String id){
Result result=new Result();
try {
Model modelData=repositoryService.getModel(id);
byte[] bytes=repositoryService.getModelEditorSource(modelData.getId());
if(bytes==null){
result.setMsg("模型不得為空");
result.setSuccess(false);
return result;
}
JsonNode modelNode=null;
modelNode=new ObjectMapper().readTree(bytes);
BpmnModel model=new BpmnJsonConverter().convertToBpmnModel(modelNode);
if(model.getProcesses().size()==0){
result.setMsg("數(shù)據(jù)不符合要求");
result.setSuccess(false);
return result;
}
byte[] bpmnByates = new BpmnXMLConverter().convertToXML(model);
//發(fā)布流程
String processName=modelData.getName()+".bpmn20.xml";
String convertToXML=new String(bpmnByates);
System.out.println(convertToXML);
Deployment deployment=repositoryService.createDeployment()
.name(modelData.getName())
.addString(processName, new String(bpmnByates, "UTF-8"))
.deploy();
modelData.setDeploymentId(deployment.getId());
repositoryService.saveModel(modelData);
result.setMsg("發(fā)布成功");
result.setSuccess(true);
} catch (Exception e) {
result.setMsg("發(fā)布失敗");
result.setSuccess(false);
}
return result;
}
3)流程查詢
/**
* 流程查詢
*/
@PostMapping("/deployDatagrid")
@ResponseBody
public Object deployDatagrid(String s_name, HttpServletResponse response,Integer page, Integer rows, String sort, String order){
PageInfo pageInfo = new PageInfo(page, rows, sort, order);
if(StringUtils.isBlank(s_name)){
s_name="";
}
int p1=page-1;
int r1=9-p1;
List<Deployment> deploymentList=repositoryService.createDeploymentQuery()
.deploymentNameLike("%" + s_name + "%").orderByDeploymenTime().desc()
.listPage(p1, r1);
long total=repositoryService.createDeploymentQuery().deploymentNameLike("%"+s_name+"%").count();
List<com.pasic.model.po.DeploymentEntity> deploymentList2=new ArrayList<com.pasic.model.po.DeploymentEntity>();
for (Deployment deployment : deploymentList) {
com.pasic.model.po.DeploymentEntity depm=new com.pasic.model.po.DeploymentEntity(deployment.getId(),deployment.getName(),deployment.getCategory(),deployment.getTenantId(),deployment.getDeploymentTime());
deploymentList2.add(depm);
}
System.out.println(deploymentList2);
pageInfo.setRows(deploymentList2);
pageInfo.setTotal((int)total);
if(total/rows==0){
pageInfo.setPagesize(0);
}else{
pageInfo.setPagesize(page++);
}
pageInfo.setNowpage(page);
pageInfo.setSize(rows);
pageInfo.setSuccess(true);
pageInfo.setMessage("列表獲取成功");
return pageInfo;
}
4)刪除流程
/**
* 刪除流程
*/
@PostMapping("/deleteDeploy")
@ResponseBody
public Object deleteDeploy(@RequestParam(value="id")String id){
Result result=new Result();
try {
//加true強(qiáng)制刪除
repositoryService.deleteDeployment(id,true);
result.setSuccess(true);
result.setMsg("刪除成功");
} catch (Exception e) {
result.setSuccess(false);
result.setMsg("刪除失敗");
}
return result;
}
5)查看流程圖片
1.后臺
/**
* 查看流程圖 圖片
*/
@GetMapping("/showProcessPng")
public String showProcessPng(@RequestParam(value="deployId")String deployId,org.springframework.ui.Model model){
// model.addAttribute("diagramResourceName", processDefinition.getDiagramResourceName());
model.addAttribute("deployId", deployId);
return "activiti/deploy/showProcessPng";
}
@RequestMapping("/showView")
public String showView(String deploymentId, HttpServletResponse response)
throws Exception {
ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery()
.deploymentId(deploymentId)
.singleResult();
InputStream inputStream = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
OutputStream outputStream = response.getOutputStream();
for (int b = -1; (b = inputStream.read()) != -1; ) {
outputStream.write(b);
}
outputStream.close();
inputStream.close();
return null;
}
2.前臺
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/commons/global.jsp" %>
<script>
</script>
<div class="bootui-layout" data-options="fit:true,border:false">
<div data-options="region:'center',fit:true,border:false">
<img style="position:absolute;top:0px;left:0px" src="${path }/act/showView?deploymentId=${deployId}">
</div>
</div>
6)將用戶同步到activiti認(rèn)證表中
/**
* 同步用戶到activiti中
*/
@PostMapping("/syncdata")
@ResponseBody
public Object syncdata(){
Result result=new Result();
try {
Wrapper<SysUser> wrapper=new EntityWrapper<SysUser>();
List<SysUser> userList=userService.selectList(wrapper);
User au = null;
for (SysUser user : userList) {
au=new UserEntity();
au.setId(user.getId());
au.setFirstName(user.getName());
au.setEmail("");
identityService.deleteUser(au.getId());
identityService.saveUser(au);
}
Wrapper<SysRole> wrapper2=new EntityWrapper<SysRole>();
List<SysRole> sysRoleList=roleService.selectList(wrapper2);
Group group=null;
for (SysRole role : sysRoleList) {
group=new GroupEntity();
group.setId(role.getId());
group.setName(role.getName());
identityService.deleteGroup(group.getId());
identityService.saveGroup(group);
}
Wrapper<SysUserRole> wrapper3=new EntityWrapper<SysUserRole>();
List<SysUserRole> roleUserList=userRoleService.selectList(wrapper3);
for (SysUserRole userRole : roleUserList) {
identityService.deleteMembership(userRole.getUserId(), userRole.getRoleId());
identityService.createMembership(userRole.getUserId(), userRole.getRoleId());
}
result.setMsg("同步成功");
result.setSuccess(true);
} catch (Exception e) {
result.setMsg("同步失敗");
result.setSuccess(false);
}
return result;
}