浅谈activiti工作流

本文档是我综合了“前人”的经验以及我自己的一点儿心得所写。里面清楚的讲述了activiti从环境配置到真正项目的运行的详细过程。本人自知能力有限,发表此文章,有两个目的:第一,希望高人能指教一二;第二,供自己以后...
一:环境配置(前提:JBK、Tomcat和Eclispe、myeclipse已经安装好)
JDK1.5以上版本
Ant 1.8.1以上版本,运行自带的Demo必须.
Ant 的安装:
1、下载ant,并解压到E:\apache-ant-1.8.2 http://ant.apache.org/bindownload.cgi 2、配置环境变量
%ANT_HOME%:E:\apache-ant-1.8.2 (这里为你自己解压缩的目录)
PATH:%ANT_HOME%\bin(这个设置是为了方便在dos环境下操作)
3、检测是否安装成功
Activiti的安装:(下载的是整好的项目)
1、下载activiti-5.5.zip,并解压到E:\activiti-5.5 http://www.activiti.org/download.html 2、运行脚本,设置 Activiti 环境
打开DOS窗口,cd到setup目录。
输入 ant demo.start,然后按 enter 键。
脚本完成后,会在浏览器内启动所有的 Activiti 的 web 应用。以 kermit/kermit 登陆。

引用
注意:在执行ant demo.start时,如果更换数据库,比如mysql(默认是H2),需要更新如下文件
1.build.properties
Java代码

# The db property should refer to the type of database that
# you want to use. Currently h2, MySQL(mysql),
# Postgres SQL(postgres) and Oracle 10g (oracle) is supported.
#
# SQL Server(mssql) is also supported, but is an EXPERIMENTAL feature.
# IBM DB2(db2) is also supported, but is an EXPERIMENTAL feature.
#
# When using oracle, follow the instructions described in the userguide, chapter
# Configuration > Changing the database > Using Oracle in the demo setup
db=mysql

# The tx property refers to the transaction environment
# you want to use. Choose from {standalone}
tx=standalone

# Specify the version of Tomcat that you want to use.
# We only tested with the given Tomcat version but in
# theory any tomcat 6.0.x version should do fine.
tomcat.version=6.0.32

# If you have tomcat already downloaded, point the
# downloads.dir property to that directly. If tomcat is
# not found in the downloads.dir, it will be automatically
# downloaded there.
# The downloads directory should be outside of /target/
# to avoid re-downloading after a clean
downloads.dir=../../downloads

# Remove this property or set it to disabled if you're not using Activiti Cycle
feature.cycle=enabled

# Remove this property or set it to disabled if you're not using Activiti Modeler
feature.modeler=enabled
修改数据库类型为mysql 打开文件“setup\build.properties”修改db=mysql(默认为h2) 2、build.mysql.properties
Java代码
db=mysql
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://IP地址:3306/activiti?autoReconnect=true
jdbc.username=所用数据库的用户名
jdbc.password=所用数据库的密码

遇到的问题:

一直提示9092端口被占用,其实本机上没有任何程序运行在端口9092,可以通过命令查看:netstat -an而且异常中提示的url不一定是tcp://localhost:9092,localhost可能是其他ip,最关键的就在这里,为什么会出现其他IP呢? 原因是在本机安装的了Vmware workstation,本机会出现三个网卡,如是就会出现异常。 把本机的两个虚拟网卡禁用就OK了。 这个问题比较难找到真实原因,因为问题提示太有误导性port may be in use
2、执行“ant demo.start”之前,需要创建数据库,否则会出现下边的问题:
3、执行“ant demo.start”完毕之后,自带的web应用访问不了,如下图:
原因:activiti-modeler-5.5.war不会自动发布,导致访问不了
(自己写)安装Activiti的Eclipse或者myeclipse插件 直接Update就行 http://activiti.org/designer/update/
Eclipse 3.6.2以上版本
Myeclipse8.5或者myeclipse 9.0版本的
支持的数据库
以下是Activiti使用参考数据库类型(区分大小写!)。
Activiti数据库类型 版本测试 JDBC URL示例 注释
H2 1.2.132 jdbc:h2:tcp://localhost/activiti 默认配置的数据库
MySQL 5.1.11 jdbc:mysql://localhost:3306/activiti 测试使用的mysql - connetor Java数据库驱动程序
Oracle 10.2.0 jdbc:oracle:thin:@localhost:1521:xe
POSTGRES 8.4 jdbc:postgresql://localhost:5432/activiti
DB2 DB2 9.7中使用db2jcc4 jdbc:db2://localhost:50000/activiti
MSSQL 2008使用JDBC JTDS - 1.2.4 jdbc:jtds:sqlserver://localhost:1433/activiti
·下面的是数据库表结构:
一、数据库建表:
建表说明目前省略
数据库表的命名
Acitiviti数据库中表的命名都是以ACT_开头的。第二部分是一个两个字符用例表的标识。此用例大体与服务API是匹配的。
ACT_RE_*:’RE’表示repository。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。
ACT_RU_*:’RU’表示runtime。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。
ACT_ID_*:’ID’表示identity。这些表包含标识的信息,如用户,用户组,等等。
ACT_HI_*:’HI’表示history。就是这些表包含着历史的相关数据,如结束的流程实例,变量,任务,等等。
ACT_GE_*:普通数据,各种情况都使用的数据。
二、数据库表结构说明:
1、用建模工具反向出来的数据库表结构图如下:




2、数据库表结构说明:
· ACT_GE_PROPERTY:属性数据表。存储整个流程引擎级别的数据。
1. NAME_:属性名称
2. VALUE_:属性值
3. REV_INT:版本号?
· ACT_GE_BYTEARRAY:用来保存部署文件的大文本数据的。
1. ID_:资源文件编号,自增长
2. REV_INT:版本号?
3. NAME_:资源文件名称
4. DEPLOYMENT_ID_:来自于父表ACT_RE_DEPLOYMENT中的主键
5. BYTES_:大文本类型,存储文本字节流
· ACT_RE_DEPLOYMENT:用来存储部署时需要被持久化保存下来的信息。
1. ID_:部署编号,自增长
2. NAME_:部署的包名称
3. DEPLOY_TIME_:部署时间
· ACT_RE_PROCDEF:业务流程定义数据表。
1. ID_:流程ID,由“流程编号:流程版本号:自增长ID ” 组成
2. CATEGORY_:流程命令空间(该编号就是流程文件targetNamespace的属性值)
3. NAME_:流程名称(该编号就是流程文件process元素的name属性值)
4. KEY_:流程编号(该编号就是流程文件process元素的id属性值)
5. VERSION_:流程版本号(由程序控制,新增即为1,修改后依次加1来完成的)
6. DEPLOYMENT_ID_:部署编号
7. RESOURCE_NAME_:资源文件名称
8. DGRM_RESOURCE_NAME_:图片资源文件名称
9. HAS_START_FORM_KEY_:是否有Start Form Key。
注意:此表与ACT_RE_DEPLOYMENT是多对一的关系,即,一个部署的bar包里可能包含多个流程定义文件,每个流程定义文件都会有一条记录在ACT_RE_PROCDEF表内,每条流程定义的数据,都会对应ACT_GE_BYTEARRAY表内的一个资源文件和PNG图片文件。与ACT_GE_BYTEARRAY的关联是通过程序用ACT_GE_BYTEARRAY.NAME_与ACT_RE_PROCDEF.RESOURCE_NAME_完成的,在数据库表结构内没有体现。
· ACT_ID_GROUP:用来保存用户组信息。
1. ID_:用户组名
2. REV_INT:版本号?
3. NAME_:用户组描述信息
4. TYPE_:用户组类型
· ACT_ID_MEMBERSHIP:用来保存用户分组信息。
1. USER_ID_:用户名
2. GROUP_ID_:用户组名
· ACT_ID_USER:用来保存用户信息。
1. ID_:用户名
2. REV_INT:版本号?
3. FIRST_:用户名称
4. LAST_:用户姓氏
5. EMAIL_:邮箱
6. PWD_:登录密码
· ACT_RU_EXECUTION:
1. ID_:
2. REV_:版本号?
3. PROC_INST_ID_:流程实例编号
4. BUSINESS_KEY_:业务编号
5. PARENT_ID_:
6. PROC_DEF_ID_:流程ID
7. SUPER_EXEC_:
8. ACT_ID_:
9. IS_ACTIVE_:
10. IS_CONCURRENT_:
11. IS_SCOPE_:
· ACT_RU_JOB:运行时定时任务数据表。
1. ID_:
2. REV_:
3. TYPE_:
4. LOCK_EXP_TIME_:
5. LOCK_OWNER_:
6. EXCLUSIVE_:
7. EXECUTION_ID_:
8. PROCESS_INSTANCE_ID_:
9. RETRIES_:
10. EXCEPTION_STACK_ID_:
11. EXCEPTION_MSG_:
12. DUEDATE_:
13. REPEAT_:
14. HANDLER_TYPE_:
15. HANDLER_CFG_:
· ACT_RU_TASK:运行时任务数据表。
1. ID_:
2. REV_:
3. EXECUTION_ID_:
4. PROC_INST_ID_:
5. PROC_DEF_ID_:
6. NAME_:
7. DESCRIPTION_:
8. TASK_DEF_KEY_:
9. ASSIGNEE_:
10. PRIORITY_:
11. CREATE_TIME_:
· ACT_RU_IDENTITYLINK:任务参与者数据表。主要存储当前节点参与者的信息。
1. ID_:
2. REV_:
3. GROUP_ID_:
4. TYPE_:
5. USER_ID_:
6. TASK_ID_:
· ACT_RU_VARIABLE:运行时流程变量数据表。
1. ID_:
2. REV_:
3. TYPE_:
4. NAME_:
5. EXECUTION_ID_:
6. PROC_INST_ID_:
7. TASK_ID_:
8. BYTEARRAY_ID_:
9. DOUBLE_:
10. LONG_:
11. TEXT_:
12. TEXT2_:
· ACT_HI_PROCINST:
· ACT_HI_ACTINST:
· ACT_HI_TASKINST:
· ACT_HI_DETAIL:
3、结论及改造建议

流程文件部署主要涉及到3个表,分别是:ACT_GE_BYTEARRAY、ACT_RE_DEPLOYMENT、ACT_RE_PROCDEF。主要完成“部署包”-->“流程定义文件”-->“所有包内文件”的解析部署关系。从表结构中可以看出,流程定义的元素需要每次从数据库加载并解析,因为流程定义的元素没有转化成数据库表来完成,当然流程元素解析后是放在缓存中的,具体的还需要后面详细研究。
流程定义中的java类文件不保存在数据库里 。
组织机构的管理相对较弱,如果要纳入单点登录体系内还需要改造完成,具体改造方法有待研究。
运行时对象的执行与数据库记录之间的关系需要继续研究
历史数据的保存及作用需要继续研究。
Act_Execution Act_task Act_TaskInvolement Act_Job Act_Variable这五张表。 这五张表在执行完所谓的”部署“逻辑后,是不会被填上任何值的。那什么时候这些表会被填充上值呢? 当我们根据一个叫做ProcessService(在jBPM中,这个类是ExecutionService)的类,来真正启动(Start)一个流程 时,这些表中才会被根据你定义的流程定义,填充上相应的记录。 一个不精确的比喻,在Activiti中,流程定义和流程执行实例,就像Java中的Class何Class Instance关系一样,根据一个流程定义,可以启动多个流程实例,供不同业务需求使用;一个类,当然可以有多个运行时实例,供不同需求使用。 需要多说一点,Act_TaskInvolement这张表直译过来就是,任务参与者,所以它存的是:和一个流程中,一个具体动作(Activity)相 关的用户(User)和角色(Group)的信息,即:当前节点参与者的信息。其他的表,也可以顾名思义了吧,就是存和一个具体动作相关的参数以及作业的 信息。 最后强调一点:这五张表有点像即擦即用的Flash存储介质哦。 什么意思,一个流程假设有多个动作(任务、节点......叫啥也行)组成,那么这五张表只是存储当前流程实例中,”活动(Active)行为“的相关数 据,如果现在活动的行为已经从A节点流到B节点了,那么,与A节点相关的所有信息是会从这4张表(不包含Act_Execution,流程实例全部完成, 相关记录才会删除;而不是一个动作完成)中被删除的!!!!
Activiti的持久化方式:
Activiti使用Mybatis3做持久化工作,可以在配置中设置流程引擎启动时创建表。
Activiti-administrator:自带的用户管理系统,维护用户和组,需要配置数据连接参数,在activiti-administrator\WEB-INF\applicationContext.xml中,并加入JDBC驱动包。
Activiti-cycle:PVM活动检测的,由activiti-rest提供服务,不需配置。
Activiti-explorer:可以查看用户任务和启动流程,由activiti-rest提供服务,不需配置。
Activiti-kickstart:简单的点对点流程定义维护工具,需要配置数据连接,把activiti.cfg.xml文件放在classes下,并加入驱动包
Activiti-modeler:在线编辑和维护流程定义的工具,最后以文件夹的方式部署,需要配置:activiti-modeler\WEB-INF\classes\configuration.properties文件。
Activiti-probe:PVM的观测服务,由activiti-rest提供服务,不需配置。可以查看deployment、processdefinition、processinstance、database。
Activiti-rest:其它几个应用的服务提供者,需要配置数据连接,把activiti.cfg.xml文件放在classes下,并加入驱动包。
关键对象:
Deployment:流程部署对象,部署一个流程是创建。
processDefinitions:流程定义,部署成功后自动创建。
ProcessInstances:流程实例,启动流程是创建。
Task:任务,在activiti中的task仅指有角色参与的任务,即定义中的UserTask。
Execution:执行计划,流程实例和流程执行中的所有节点都是Execution,如UserTask、ServiceTask等。
服务接口:
ProcessEngine:流程引擎接口,提供流程管理和运作的所有接口。
RuntimeService:运行时服务接口,提供流程启动服务,运行中流程查询,运行变量设置和获取。
TaskService:用户任务接口(UserTask),提供运行时任务查询、领取、完成、删除及变量设置用户管理等服务。
IdentityService:用户和组管理接口。
ManagementService:流程引擎管理接口。
HistoryService:流程处理查询接口,包括执行中流程查询和历史流程查询。
简单入门:
Activiti的实用意义: Activiti是JBPM的原创者的团队编写的,实际上它才是JBPM“血统”的继承者。而如今的JBPM5所用的几乎是Drools Flow的源码。因此一直在用JBPM的用户更倾向于使用Activiti,需要注意的是Activiti用的是BPMN的流程定义语言BPEL而非当初 的JBDL了。 二、Activiti的designer在eclipse中的安装: 打开 HelpInstall New Software。在如下面板中,点击 Add 按钮,然后填写下列字段: Name:Activiti BPMN 2.0 designer Location:http://activiti.org/designer/update/ 务必不要选中”Contact all updates sites..”,因为所有必需的插件都能从 Activiti 更新站点下载。 三、Activiti整合MySql数据库的方法 要将演示程序设置配置到不同的数据库,或生成不同的数据库的配置文件,按如下步骤:  编辑 setup/build.propertyies,将 db 参数修改成你的数据库类型{oracle | mysql | postgres | h2 | db2 | mssql}。 编辑 setup/build.${db}.propertyies,将 JDBC 连接参数修改成你安装的数据库的参数。 要想根据你在 build.*.properties 文件指定的属性来创建数据的配置文件,请在(开始->运行->CMD)setup 文件内运行: ant cfg.create 可以在 setup/build/activti.cfg 内找到生成的配置文件。同时,方便起见,可以在 setup/build 下找到包含了配置文件的 jar 文件 activiti-cfg.jar。 四、部署Activiti实例和Activiti的web designer部署 打开控制台,ant demo.start 这时则开始建立数据库,部署实例到eclipse,部署designer到tomcat服务器,这里的tomcat服务器在{%activiti-5.6%}\apps\apache-tomcat-6.0.32下。 如果之前更改了数据库, Eclipse中需要将实例的配置文件activiti.cfg.xml的内容改为{%activiti-5.6%}\setup\build\activiti-cfg\activiti.cfg.xml的内容。 为了使Activiti KickStart 能够正常运行,我们需要单独更改它的数据库驱动程序activiti.cfg.jar (正确配置的jar位于{%activiti-5.6%}/setup/build/下) ,并将其置于apps/apache-tomcat-6.x/webapps/activiti-kickstart/WEB-INF/lib 文件夹下。同样,必须将数据库驱动程序置于同一文件夹下。 可以在 setup/files/dependencies/libs/下找到你的数据库驱动程序(除了 Oracle)。 五、Activiti web designer以及部署到eclipse的实例介绍 应用名称 URL 描述 Activiti Probe http://localhost:8080/activiti-probe 管理员管理控制台。使用该工具查看配置好的流程引擎是否正确初始化,以及数据库内容。 Activiti Explorer http://localhost:8080/activiti-explorer 流程引擎用户控制台。使用该工具查看您的个人任务、候选人任务,以及完成的任务。 Activiti Cycle http://localhost:8080/activiti-cycle Activiti 协助工具。使用该工具浏览资料库以及执行模型格式之间的转换。 Activiti Modeler http://localhost:8080/activiti-modeler 基于Web 的流程设计工具。使用该工具绘制BPMN2.0 规范的流程定义文件。(对浏览器有版本要求) Activiti KickStart http://localhost:8080/activiti-kickstart Activiti KickStart 是利用 Activiti 引擎的可用构造的子集来快速创建’临时安排的(adhoc)’业务流程的一个基于 web 的工具。 activiti-engine-examples:该套示例展示了 Activiti 最常用的用法:BPMN 流程定义和流程的执行被存储在数据库中, 并且示例中使用了持久化 API。  activiti-spring-examples:这些示例展示了在 Spring 环境下如何使用 Activiti 引擎。  activiti-groovy-examples:这些示例展示了 groovy 的依赖库以及一个使用 groovy 脚本的流程。  activiti-jpa-examples:这些示例展示了依赖库以及 Activiti 中如何使用 JPA。  activiti-cxf-examples:这些示例展示了依赖库以及在 Activiti 中如何使用 web 服务。  activiti-cycle-examples:此项目内含有一个关于 Activiti Cycle 的演示示例。  activiti-modeler-examples:在演示程序安装内 Activiti Modeler 配置的模型库文件。
通过 ProcessEngineBuilder 读取 activiti 的配置文件,就可以生成流程引擎实例。
通过流程引擎实例 processEngine, 我们就可以通过 getXXXService() 取得各种包含 workflow/BPM 方法的 service 。
RepositoryService : 提供方法获取各种流程和部署文件的信息 .
TaskService : 提供对任务相关的各种操作
identityService : 管理用户和用户组。
FormService : 获取或者绑定数据到流程实例上
RuntimeService : 提供操作部署文件,流程文件和流程实例的方法 .
ManagementService : 提供管理员对流程引擎的监控,和流程引擎服务应用无关。
HistoryService : 提供正在执行和过去执行的各种流程实例信息
ProcessEngines.getDefaultProcessEngine()会在第一次被调用时初始并构建process engine,接下来对该方法的调用返回的都
是同一个流程引擎。利用ProcessEngines.init()、ProcessEngines.destroy()可以正确创建、关闭流程引擎。
ProcessEngines 会浏览所有activiti.cfg.xml 和activiti-context.xml 文件。对于那些activiti.cfg.xml 文件,将以Activiti 特有的方
式来构建流程引擎:
ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine()。对于那些
activiti-context.xml 文件,将以Spring 的方式来构建流程引擎:首先,创建spring 应用上下文;然后,从该上下文中获取流程引擎。


绘制流程图
创建完后会发现它自动把流程图放到main.resources.diagrams 包下面了,如果不想放在这下面可以直接移动过去。本人移动到了activiti.process.def包下面,这样比较符合编码规范。
接下来就是打开创建的流程图,开始绘制了。
按照上面绘制完后,就该编写相应的代码了。
package activiti.process;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

public class ProcessHelloWorld implements JavaDelegate {

@Override
public void execute(DelegateExecution arg0) throws Exception {
System.out.println("HelloWorld");
}

}
然后给 HelloWorld这个节点指定相应的执行相应的代码,需要打开流程图HelloWorld.activiti 然后点击HelloWorld节点 在下面的点开Main config选项卡里面指定Service class 为刚才写的流程代码。这样当流程走到这一步的时候就会执行这个类里面的execute方法。

接下来咱们需要做的就是发布流程以及启动流程了。
编写ProcessUtil封装一些方法,方便调用。

package activiti.process;

import java.util.HashMap;

/**
* 与流程有关的工具类
*
*
*/
public class ProcessUtil {
/**
* 发布流程的方法
*/
public static void deploy() {
RepositoryService service = (RepositoryService) CommonUtil.getBean("repositoryService");
service.createDeployment().addClasspathResource("activiti/process/def/HelloWorld.bpmn20.xml")
.addClasspathResource("activiti/process/def/HelloWorld.png").deploy();
}

/**
* 启动流程
*/
public static String start() {
RuntimeService service = (RuntimeService) CommonUtil.getBean("runtimeService");
ProcessInstance instance = service.startProcessInstanceByKey("HelloWorld");

return instance.getProcessInstanceId();
}
}
CommonUtil代码

public class CommonUtil implements ApplicationContextAware {
private static ApplicationContext springFactory = null;

public static Object getBean(String name) {
return springFactory.getBean(name);
}

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
springFactory = applicationContext;
}
}
编写相应的servlet
public class ProcessAction extends HttpServlet {
private static final long serialVersionUID = 1L;
public ProcessAction() {
super();
}

/**
* @see HttpServlet#service(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String cmd = request.getParameter("cmd");
String page = null;
if ("deploy".equals(cmd)) {
ProcessUtil.deploy();
request.setAttribute("result", "流程发布成功");
page = "success.jsp";
} else if ("start".equals(cmd)) {
String id = ProcessUtil.start();
request.setAttribute("result", "流程启动成功,流程ID:" + id);
page = "success.jsp";
}
request.getRequestDispatcher(page).forward(request, response);
}
}
相应的页面index.jsp
[html]view plaincopyprint?

<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>流程测试</title>
</head>
<body>
<form action="process" method="post">
<input type="radio" name="cmd" value="deploy">发布流程</input>
<input type="radio" name="cmd" value="start">启动流程</input>
<input type="radio" name="cmd" value="view">查看当前启动用户流程</input>
<input type="submit" value="提交">
</form>
</body>
</html>
success.jsp
[html]view plaincopyprint?

<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>成功</title>
</head>
<body>
处理结果:<%=request.getAttribute("result") %>
<a href="index.jsp">返回</a>
</body>
</html>
web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
<span style="white-space:pre"> </span>classpath*:*.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>ProcessAction</servlet-name>
<servlet-class>com.hollycrm.servlet.ProcessAction</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProcessAction</servlet-name>
<url-pattern>/process</url-pattern>
</servlet-mapping>
</web-app>
至此编码工作已经全部完成,发布应用进入index.jsp,首先点击发布流程。然后再点击启动流程。看看是不是控制台输出了HelloWorld! 因为ServiceTask
为自动任务不需要人工干预,所以会自动执行。启动流程以后直接进入到了HellorWorld执行完后流程也就结束了。
在activiti中每一个用户属于一个用户组,不同的用户拥有不同的权限,不同的权限可以有不同的操作,因此请求的资源路径和登录的安全验证相当的重要。需要添加相关的验证。
原理实现REST的org.restlet.Application接口实现,实现REST访问方式唯一的入口点,同时添加相关的权限验证。然后再web.xml配置即可。

web.xml配置如下:<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<display-name>Activiti REST</display-name>

<listener>
<listener-class>org.activiti.rest.servlet.ActivitiServletContextListener</listener-class>
</listener>

<!-- Restlet adapter -->
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
<init-param>
<!-- Application class name -->
<param-name>org.restlet.application</param-name>
<param-value>org.activiti.rest.application.ActivitiRestApplication</param-value>
</init-param>
</servlet>

<!-- Catch all requests -->
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
</web-app>





代码如下:
package org.activiti.rest.application;

import org.activiti.rest.api.ActivitiUtil;
import org.activiti.rest.api.DefaultResource;
import org.activiti.rest.api.engine.ProcessEngineResource;
import org.activiti.rest.api.identity.GroupResource;
import org.activiti.rest.api.identity.GroupUsersResource;
import org.activiti.rest.api.identity.LoginResource;
import org.activiti.rest.api.identity.UserGroupsResource;
import org.activiti.rest.api.identity.UserPictureResource;
import org.activiti.rest.api.identity.UserResource;
import org.activiti.rest.api.identity.UserSearchResource;
import org.activiti.rest.api.management.JobExecuteResource;
import org.activiti.rest.api.management.JobResource;
import org.activiti.rest.api.management.JobsExecuteResource;
import org.activiti.rest.api.management.JobsResource;
import org.activiti.rest.api.management.TableDataResource;
import org.activiti.rest.api.management.TableResource;
import org.activiti.rest.api.management.TablesResource;
import org.activiti.rest.api.process.ProcessDefinitionFormResource;
import org.activiti.rest.api.process.ProcessDefinitionPropertiesResource;
import org.activiti.rest.api.process.ProcessDefinitionsResource;
import org.activiti.rest.api.process.ProcessInstanceDiagramResource;
import org.activiti.rest.api.process.ProcessInstanceResource;
import org.activiti.rest.api.process.ProcessInstancesResource;
import org.activiti.rest.api.process.StartProcessInstanceResource;
import org.activiti.rest.api.repository.DeploymentDeleteResource;
import org.activiti.rest.api.repository.DeploymentUploadResource;
import org.activiti.rest.api.repository.DeploymentsDeleteResource;
import org.activiti.rest.api.repository.DeploymentsResource;
import org.activiti.rest.api.task.TaskAddResource;
import org.activiti.rest.api.task.TaskAttachmentAddResource;
import org.activiti.rest.api.task.TaskAttachmentResource;
import org.activiti.rest.api.task.TaskFormResource;
import org.activiti.rest.api.task.TaskOperationResource;
import org.activiti.rest.api.task.TaskPropertiesResource;
import org.activiti.rest.api.task.TaskResource;
import org.activiti.rest.api.task.TaskUrlAddResource;
import org.activiti.rest.api.task.TasksResource;
import org.activiti.rest.api.task.TasksSummaryResource;
import org.restlet.Application;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.ChallengeScheme;
import org.restlet.routing.Router;
import org.restlet.security.ChallengeAuthenticator;
import org.restlet.security.SecretVerifier;
import org.restlet.security.Verifier;

/**
* @author Tijs Rademakers
*/
public class ActivitiRestApplication extends Application {

private ChallengeAuthenticator authenticator;

/**
* Creates a root Restlet that will receive all incoming calls.
*/
@Override
public synchronized Restlet createInboundRoot() {
Verifier verifier = new SecretVerifier() {

@Override
public boolean verify(String username, char[] password) throws IllegalArgumentException {
boolean verified = ActivitiUtil.getIdentityService().checkPassword(username, new String(password));
return verified;
}
};
authenticator = new ChallengeAuthenticator(null, true, ChallengeScheme.HTTP_BASIC,
"Activiti Realm") {

@Override
protected boolean authenticate(Request request, Response response) {
if (request.getChallengeResponse() == null) {
return false;
} else {
return super.authenticate(request, response);
}
}
};
authenticator.setVerifier(verifier);

Router router = new Router(getContext());

router.attachDefault(DefaultResource.class);

router.attach("/process-engine", ProcessEngineResource.class);

router.attach("/login", LoginResource.class);

router.attach("/user/{userId}", UserResource.class);
router.attach("/user/{userId}/groups", UserGroupsResource.class);
router.attach("/user/{userId}/picture", UserPictureResource.class);
router.attach("/users/{searchText}", UserSearchResource.class);

router.attach("/group/{groupId}", GroupResource.class);
router.attach("/groups/{groupId}/users", GroupUsersResource.class);

router.attach("/process-definitions", ProcessDefinitionsResource.class);
router.attach("/process-instances", ProcessInstancesResource.class);
router.attach("/process-instance", StartProcessInstanceResource.class);
router.attach("/processInstance/{processInstanceId}", ProcessInstanceResource.class);
router.attach("/processInstance/{processInstanceId}/diagram", ProcessInstanceDiagramResource.class);
router.attach("/process-definition/{processDefinitionId}/form", ProcessDefinitionFormResource.class);
router.attach("/process-definition/{processDefinitionId}/properties", ProcessDefinitionPropertiesResource.class);

router.attach("/tasks", TasksResource.class);
router.attach("/tasks-summary", TasksSummaryResource.class);
router.attach("/task", TaskAddResource.class);
router.attach("/task/{taskId}", TaskResource.class);
router.attach("/task/{taskId}/form", TaskFormResource.class);
router.attach("/task/{taskId}/attachment", TaskAttachmentAddResource.class);
router.attach("/task/{taskId}/url", TaskUrlAddResource.class);
router.attach("/task/{taskId}/{operation}", TaskOperationResource.class);

router.attach("/attachment/{attachmentId}", TaskAttachmentResource.class);

router.attach("/form/{taskId}/properties", TaskPropertiesResource.class);

router.attach("/deployments", DeploymentsResource.class);
router.attach("/deployment", DeploymentUploadResource.class);
router.attach("/deployments/delete", DeploymentsDeleteResource.class);
router.attach("/deployment/{deploymentId}", DeploymentDeleteResource.class);

router.attach("/management/jobs", JobsResource.class);
router.attach("/management/job/{jobId}", JobResource.class);
router.attach("/management/job/{jobId}/execute", JobExecuteResource.class);
router.attach("/management/jobs/execute", JobsExecuteResource.class);

router.attach("/management/tables", TablesResource.class);
router.attach("/management/table/{tableName}", TableResource.class);
router.attach("/management/table/{tableName}/data", TableDataResource.class);

authenticator.setNext(router);

return authenticator;
}

public String authenticate(Request request, Response response) {
if (!request.getClientInfo().isAuthenticated()) {
authenticator.challenge(response, false);
return null;
}
return request.getClientInfo().getUser().getIdentifier();
}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值