项目集成Activiti

集成新版(5.17+)Activiti Modeler与Rest服务

转自:http://www.kafeitu.me/blog.html
css

这又是一片迟来的博客,上一篇博文仍是2014年4月24日写的,由于不少内容都在书(《Activiti实战》)里了已经有详细的解释了,不过因为书里面使用的是5.16.4版本,从5.17.0版本后Activiti Modeler的整合方式有些变化,因此写此博问做为补充内容。html

声明前端

  1. 此教程适合Activiti 5.17+版本。
  2. 本博客所涉及的内容都可在kft-activiti-demo中找到。
  3. 在线demo能够访问 http://demo.kafeitu.me:8080/kft-activiti-demo 菜单路径:管理模块 -> 流程管理 -> 模型工做区,能够『建立』或者『编辑』模型

1. 简介

上一篇介绍整合Activiti Modeler《整合Activiti Modeler到业务系统(或BPM平台)》已经有2年多时间了,自从Activiti 5.17版本发布之后该教程已经不适用了,不少网友也反馈不知道怎么把Activiti Modeler整合到本身的项目中去,为此抽时间为适配5.17+版本的集成方法整理成这篇博文,但愿对有需求的网友有帮助。java

最新版本的kft-activiti-demo已经使用了5.17+版本的Activiti,而且集成了最新的Activiti Modeler组件,能够下载最新源码:https://github.com/henryyan/kft-activiti-demogit

1.1 新版Activiti Modeler特性

先来欣赏一下新版的界面,相比上一版漂亮了许多,调性高了~~~github

新版Activiti Modeler

界面布局:上(工具区)、左(组件类目)、右(工做区)、右下(属性区)web

Activiti Modeler内部的实现上仍是以oryx为图形组件为内核,用angular.js做为界面基本元素的基础组件以及调度oryx的API。spring

2. 官方Activiti Explorer的集成方式

先从Github下载官方Activiti源码,地址:https://github.com/Activiti/Activiti数据库

2.1 Activiti Exploer的内部结构-Java

源码目录(若是是zip下载请先解压缩)中找到modules/activiti-webapp-explorer2/src/main子目录,结构以下:express

├── assembly
├── java
│   └── org
│       └── activiti
├── resources
│   └── org
│       └── activiti
└── webapp
    ├── META-INF
    ├── VAADIN
    │   ├── themes
    │   └── widgetsets
    ├── WEB-INF
    ├── diagram-viewer
    │   ├── images
    │   └── js
    └── editor-app
        ├── configuration
        ├── css
        ├── editor
        ├── fonts
        ├── i18n
        ├── images
        ├── libs
        ├── partials
        ├── popups
        └── stencilsets

咱们须要关注的目录是webapp/editor-app,以及java/org/activiti,目录结构:

Activiti Explorer源码目录

新版本的Activiti Explorer放弃了XML方式的配置方式,采用Bean Configuration的方式代替,上图中org/activiti/explorer/conf包中就是各类配置,在org/activiti/explorer/servlet/WebConfigurer类用Servlet 3.0方式配置Servlet映射关系,映射的路径为/service/*

2.2 Activiti Exploer的内部结构-Web

新版本Activiti Modeler的Web资源再也不像旧版那么散乱,新版本只须要关注:

  • src/main/webapp/editor-app:目录中包含设计器里面全部的资源:angular.js、oryx.js以及配套的插件及css
  • src/main/webapp/modeler.html:设计器的主页面,用来引入各类web资源
  • src/main/resources/stencilset.json: bpmn标准里面各类组件的json定义,editor以import使用。

3. 整合到本身的项目中

了解过网友的需求不知道如何整合新版Activiti Modeler的缘由有两个:

  1. 不知道怎么把注解的方式转换为XML方式
  2. editor-app目录的结构位置
  3. 和本身应用的整合参数配置

3.1 Activiti Rest接口与Spring MVC配置

3.1.1 Maven依赖

Activiti Modeler对后台服务的调用经过Spring MVC方式实现,全部的Rest资源统一使用注解RestController标注,因此在整合到本身项目的时候须要依赖Spring MVC,Modeler模块使用的后台服务都存放在activiti-modeler模块中,在本身的项目中添加依赖:

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-modeler</artifactId>
    <version>5.19.0</version>
</dependency>
<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-diagram-rest</artifactId>
    <version>5.19.0</version>
</dependency>

模块做用:

  • activiti-modeler模块提供模型先关的操做:建立、保存、转换json与xml格式等
  • activiti-diagram-rest模块用来处理流程图有关的功能:流程图布局(layout)、节点高亮等

3.1.2 准备基础服务类

复制文件(https://github.com/henryyan/kft-activiti-demo/tree/master/src/main/java/org/activiti/explorer) 里面的java文件到本身项目中。

3.1.3 Activiti Spring配置

建立文件src/main/resources/beans/beans-activiti.xml定义Activiti引擎的beans:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 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-4.1.xsd">

    <context:component-scan
            base-package="org.activiti.conf,org.activiti.rest.editor">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 单例json对象 -->
    <bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper"/>

    <!-- 引擎内部提供的UUID生成器,依赖fastxml的java-uuid-generator模块 -->
    <bean id="uuidGenerator" class="org.activiti.engine.impl.persistence.StrongUuidGenerator" />

    <!-- Activiti begin -->
    <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="true"/>
    </bean>

    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>

    <!-- 7大接口 -->
    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
    <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
    <bean id="formService" factory-bean="processEngine" factory-method="getFormService"/>
    <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/>
    <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"/>

</beans>

在spring初始化的时候引入便可,例如在web.xml中使用通配符方式:

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath*:/beans/beans-*.xml</param-value>
</context-param>

3.1.4 Spring MVC配置

建立文件WEB-INF/spring-mvc-modeler.xml,内容以下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">

	<!-- 自动扫描且只扫描@Controller -->
	<context:component-scan base-package="org.activiti.rest.editor,org.activiti.rest.diagram">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
	</context:component-scan>

	<mvc:annotation-driven />
</beans>

上面XML中告知spring mvc扫描路径为**

3.1.5 web.xml中配置Servlet服务

web.xml中配置下面的Servlet:

<servlet>
	<servlet-name>ModelRestServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring-mvc-modeler.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>ModelRestServlet</servlet-name>
	<url-pattern>/service/*</url-pattern>
</servlet-mapping>

3.1.6 模型设计器的Web资源

  1. 直接从Activiti Explorer中复制文件modeler.html文件到src/main/webapp目录便可,该文件会引入定义基本的布局(div)、引入css以及js文件。

  2. 修改editor-app/app-cfg.js文件的contextRoot属性为本身的应用名称,例如/kft-activiti-demo/service

3.1.7 模型控制器

《整合Activiti Modeler到业务系统(或BPM平台)》中已经介绍过ModelController类的做用了,这里须要在基础上稍微作一点调整:

  • create方法中在建立完Model后跳转页面由service/editor?id=改成modeler.html?modelId=
  • 当从模型列表编辑某一个模型时也须要把路径修改成modeler.html?modelId=

4. 整合Activiti Rest

有了Activiti Modeler的基础只须要依葫芦画瓢便可。

4.1 Maven依赖

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-rest</artifactId>
    <version>5.19.0</version>
</dependency>

4.3 Activiti组件包扫描

文件src/main/resources/beans/beans-activiti.xmlcontext:component-scan标签的base-package属性中添加org.activiti.rest.service包,包里面包含了全部Rest API的接口Rest Controller。

4.4 添加Rest安全认证组件

package org.activiti.conf;

import org.activiti.rest.security.BasicAuthenticationProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;

@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean
    public AuthenticationProvider authenticationProvider() {
        return new BasicAuthenticationProvider();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authenticationProvider(authenticationProvider())
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .csrf().disable()
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .httpBasic();
    }
}

4.5 spring mvc配置文件

建立文件WEB-INF/spring-mvc-rest.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">

    <!-- 自动扫描且只扫描@Controller -->
    <context:component-scan base-package="org.activiti.rest">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

    <mvc:annotation-driven />
</beans>

4.6 配置Servlet映射

<servlet>
    <servlet-name>RestServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-mvc-rest.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>RestServlet</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

4.7 访问Rest接口

如今启动应用能够访问 http://localhost:8080/your-app/rest/management/properties 以Rest方式查看引擎的属性列表,若是在网页中访问会提示输入用户名密码;也能够访问在线demo测试http://demo.kafeitu.me:8080/kft-activiti-demo/rest/management/properties (用户名:kafeitu,密码:000000)

5. 结束语

以上步骤若是在实施过程当中有问题能够参考kft-activiti-demo中的配置,有其余问题能够在本博客中留言或者到QQ群问询。

最后再广告一下个人书《Activiti实战》,Tijs强力推荐的哦;同时也感谢一直支持和活跃在Activiti社区的你。

24 Apr 2014
分享到: 10
Comments

集成Diagram Viewer跟踪流程

首先这是一篇迟来的教程,由于从5.12版本(目前最新版本为5.15.1)开始就已经提供了Diagram Viewer这个流程图跟踪组件,无论如何总归有人须要用到,因此我以为仍是要和你们分享一下。

1. 前言

目前被你们所采用的流程图跟踪有两种方式:

  • 一种是由引擎后台提供图片,能够把当前节点标记用红色
  • 一种是比较灵活的方式,先用引擎接口获取流程图(原图),而后再经过解析引擎的Activity对象逐个解析(主要是判断哪一个是当前节点),最后把这些对象组成一个集合转换成JSON格式的数据输出给前端,用Javascript和Css技术实现流程的跟踪

这两种方式在kft-activiti-demo中都有演示,这里就不介绍了,参考流程跟踪部门代码便可。

2. Diagram Viewer简介

Diagram Viewer是官方在5.12版本中添加的新组件,以Raphaël为基础库,用REST(参考:《如何使用Activiti Rest模块》)方式获取JSON数据生成流程图并把流程的处理过程用不一样的颜色加以标注,最终的效果以下图所示。

在应用中使用时也很方便,把这个组件的源码复制到项目中再配置一个REST拦截器,最后拼接一个URL便可;举个例子:

http://demo.kafeitu.me/kft-activiti-demo/diagram-viewer/index.html?processDefinitionId=leave-jpa:1:22&processInstanceId=27

这个URL中有两个参数:

  • processDefinitionId: 流程定义ID
  • processInstanceId: 流程实例ID

3. 集成Diagram Viewer

3.1 建立REST路由类

REST路由类源码在官方的Activiti Explorer里面有提供,代码以下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package org.activiti.explorer.rest;
 
import org.activiti.rest.common.api.DefaultResource;
import org.activiti.rest.common.application.ActivitiRestApplication;
import org.activiti.rest.common.filter.JsonpFilter;
import org.activiti.rest.diagram.application.DiagramServicesInit;
import org.activiti.rest.editor.application.ModelerServicesInit;
import org.restlet.Restlet;
import org.restlet.routing.Router;
 
public class ExplorerRestApplication extends ActivitiRestApplication {
   
   public ExplorerRestApplication() {
     super ();
   }
   /**
    * Creates a root Restlet that will receive all incoming calls.
    */
   @Override
   public synchronized Restlet createInboundRoot() {
     Router router = new Router(getContext());
     router.attachDefault(DefaultResource. class );
     ModelerServicesInit.attachResources(router);
     DiagramServicesInit.attachResources(router);
     JsonpFilter jsonpFilter = new JsonpFilter(getContext());
     jsonpFilter.setNext(router);
     return jsonpFilter;
   }
 
}

把这个路由配置到web.xml中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
< servlet >
     < servlet-name >ExplorerRestletServlet</ 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.explorer.rest.ExplorerRestApplication</ param-value >
     </ init-param >
</ servlet >
 
< servlet-mapping >
     < servlet-name >ExplorerRestletServlet</ servlet-name >
     < url-pattern >/service/*</ url-pattern >
</ servlet-mapping >

3.2 复制Diagram Viewer组件

在官方提供的Zip文件(能够从www.activiti.org/download.html下载)中有一个wars目录,用压缩工具解压activiti-explorer.war文件,目录结构以下图:

diagram-viewer复制到项目的webapp目录(或者是WebRoot目录)下,在项目中须要跟踪的地方拼接访问diagram-viewer/index.html的URL便可,别忘记了刚刚介绍的两个重要参数。

http://demo.kafeitu.me/kft-activiti-demo/diagram-viewer/index.html?processDefinitionId=leave-jpa:1:22&processInstanceId=27

URL中有两个参数:

  • processDefinitionId: 流程定义ID
  • processInstanceId: 流程实例ID

这是一个独立的页面,你能够直接打开它或者把它嵌入在一个对话框里面(kft-activiti-demo就是用的嵌入方式)。

18 Apr 2014
分享到: 0
Comments

在Activiti中集成JPA(解决动态表单生成的大量数据)

1. 为什么集成JPA

在《比较Activiti中三种不一样的表单及其应用》一文中介绍了不一样表单的特色以及表现形式,相信这是每一个初学者都会面临表单类型的选择。

若是选择了使用动态表单那么将面临一个比较“严峻”的问题——大数据量,咱们知道动态表单的内容都保存在一张表中(ACT_HI_DETAIL),咱们也清楚动态表单中每个Field都会在该表中插入一条记录,假如一个流程共有20个字段,这个数据量你们能够计算一下,天天多少个流程实例,每月、每一年多少?

日积月累的大数据会影响系统的性能,尤为涉及到关联查询时影响更深,除了性能以外动态表单还有一个弊端那就是数据是以的形式存储没有任何数据结构可言,流程运行中生成的数据很难被用于分析、查询,如何破解嘞?

2. 如何集成JPA

Activiti除了核心的Engine以外对企业现有的技术、平台、架构都有所支持,对于业务实体的持久化固然也会有所支持,那就是EJB的标准之一)——JPA,引擎把JPA的API引入到了内部,使用JPA功能的时候只须要把entityManagerFactory配置到引擎配置对象(参考:谈谈Activiti的引擎与引擎配置对象)便可。

参考用户手册的JPA章节,介绍了引擎配置对象中的几个jpa有关的属性,以下:

  • jpaPersistenceUnitName: 使用持久化单元的名称(要确保该持久化单元在类路径下是可用的)。根据该规范,默认的路径是/META-INF/persistence.xml)。要么使用 jpaEntityManagerFactory 或者jpaPersistenceUnitName。
  • jpaEntityManagerFactory: 一个实现了javax.persistence.EntityManagerFactory的bean的引用。它将被用来加载实体而且刷新更新。要么使用jpaEntityManagerFactory 或者jpaPersistenceUnitName。
  • jpaHandleTransaction: 在被使用的EntityManager 实例上,该标记表示流程引擎是否须要开始和提交/回滚事物。当使用Java事物API(JTA)时,设置为false。
  • jpaCloseEntityManager: 该标记表示流程引擎是否应该关闭从 EntityManagerFactory获取的 EntityManager的实例。当EntityManager 是由容器管理的时候须要设置为false(例如 当使用并非单一事物做用域的扩展持久化上下文的时候)。

2.1 配置持久化单元或者EntityManagerFactory

要在引擎中使用JPA须要提供EntityManagerFactory或者提供持久化单元名称(引擎会自动查找最终获取到EntityManagerFactory对象),在使用的时候能够根据本身的实际状况进行选择,在kft-activiti-demo中使用了jpaEntityManagerFactory属性注入EntityManagerFactory对象的方式。

2.2 Standalone模式的JPA配置

?
1
2
3
4
     < property name = "jpaPersistenceUnitName" value = "kft-jpa-pu" >
     < property name = "jpaHandleTransaction" value = "true" ></ property >
     < property name = "jpaCloseEntityManager" value = "true" ></ property >
</ property >

2.3 Spring(托管)模式的JPA配置

?
1
2
3
4
     < property name = "jpaEntityManagerFactory" ref = "entityManagerFactory" >
     < property name = "jpaHandleTransaction" value = "false" ></ property >
     < property name = "jpaCloseEntityManager" value = "false" ></ property >
</ property >

3. 实例分析

在最新版本(1.10)的kft-activiti-demo中添加了JPA演示,你们能够从Github上下载源码查看源码。

请假流程-JPA版本

3.1 相关说明

  • 流程定义文件:leave-jpa.bpmn
  • 实体文件:me.kafeitu.demo.activiti.entity.oa.LeaveJpaEntity
  • 实体管理器:me.kafeitu.demo.activiti.service.oa.leave.LeaveEntityManager

3.2 建立实体

在流程定义文件中定义了一个流程的start类型监听器:

?
1
2
3
< extensionelements >
   < activiti:executionlistener event = "start" expression = "${execution.setVariable('leave', leaveEntityManager.newLeave(execution))}" ></ activiti:executionlistener >
</ extensionelements >

这个监听器的触发的时候会执行一个表达式,调用名称为leaveEntityManager的Spring Bean对象的newLeave方法,而且把引擎的Execution对象传递过去,获得一个LeaveJpaEntity对象后设置到引擎的变量中(名称为leave)。

下面是LeaveEntityManager.java的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Entity (name = "LEAVE_JPA" )
public class LeaveJpaEntity implements Serializable {
 
     private Long id;
     private String processInstanceId;
     private String userId;
     private Date startTime;
     private Date endTime;
     private Date realityStartTime;
     private Date realityEndTime;
     private Date reportBackDate;
     private Date applyTime;
     private String leaveType;
     private String reason;
 
     /**
      * 部门领导是否赞成
      */
     private String deptLeaderApproved;
 
     /**
      * HR是否赞成
      */
     private String hrApproved;
     
     ...
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Service
public class LeaveEntityManager {
 
     @PersistenceContext
     private EntityManager entityManager;
     
     /* 把流程变量的值赋值给JPA实体对象并保存到数据库 */
     @Transactional
     public LeaveJpaEntity newLeave(DelegateExecution execution) {
         LeaveJpaEntity leave = new LeaveJpaEntity();
         leave.setProcessInstanceId(execution.getProcessInstanceId());
         leave.setUserId(execution.getVariable( "applyUserId" ).toString());
         leave.setStartTime((Date) execution.getVariable( "startTime" ));
         leave.setEndTime((Date) execution.getVariable( "endTime" ));
         leave.setLeaveType(execution.getVariable( "leaveType" ).toString());
         leave.setReason(execution.getVariable( "reason" ).toString());
         leave.setApplyTime( new Date());
         entityManager.persist(leave);
         return leave;
     }
 
     public LeaveJpaEntity getLeave(Long id) {
         return entityManager.find(LeaveJpaEntity. class , id);
     }
 
}

当启动流程后查看表LEAVE_JPA中的数据与表单填写的一致。

3.3 在流程中更改实体的值

部门领导或者人事审批节点完成时须要把审批结果更新到LeaveJpaEntity属性中(即更新表LEAVE_JPA),因此在这两个任务上添加一个complete类型的监听器,以下所示:

?
1
2
3
4
5
6
7
8
9
10
11
< usertask id = "deptLeaderAudit" name = "部门领导审批" activiti:candidategroups = "deptLeader" >
     < extensionelements >
         < activiti:tasklistener event = "complete" expression = "${leave.setDeptLeaderApproved(deptLeaderApproved)}" ></ activiti:tasklistener >
     </ extensionelements >
</ usertask >
 
< usertask id = "hrAudit" name = "人事审批" activiti:candidategroups = "hr" >
     < extensionelements >
         < activiti:tasklistener event = "complete" expression = "${leave.setHrApproved(hrApproved)}" ></ activiti:tasklistener >
     </ extensionelements >
</ usertask >

3.4 流程结束后删除表单数据

熟悉Activiti表的应该知道表单数据会保存在表ACT_HI_DETAIL中,特性是字段TYPE_字段的值为FormProperty,咱们只要根据流程实例ID过滤删除记录就能够清理掉已经结束流程的表单数据。

在最新版本的Demo中(1.10版本)添加了一个类用来执行SQL:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class ActivitiDao {
 
     @PersistenceContext
     private EntityManager entityManager;
 
     /**
      * 流程完成后清理detail表中的表单类型数据
      * @param processInstanceId
      * @return
      */
     public int deleteFormPropertyByProcessInstanceId(String processInstanceId) {
         int i = entityManager.createNativeQuery( "delete from act_hi_detail where proc_inst_id_ = ? and type_ = 'FormProperty' " )
                 .setParameter( 1 , processInstanceId).executeUpdate();
         return i;
     }
 
}

流程中定义了一个流程级别的结束监听器me.kafeitu.demo.activiti.service.oa.leave.LeaveProcessEndListener

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Service
@Transactional
public class LeaveProcessEndListener implements ExecutionListener {
 
     protected Logger logger = LoggerFactory.getLogger(getClass());
 
     @Autowired
     ActivitiDao activitiDao;
 
     @Override
     public void notify(DelegateExecution execution) throws Exception {
         String processInstanceId = execution.getProcessInstanceId();
 
         int i = activitiDao.deleteFormPropertyByProcessInstanceId(processInstanceId);
         logger.debug( "清理了 {} 条历史表单数据" , i);
     }
}

3.5 已知问题(未解决)

因为引擎的Bug致使数据不能完整删除

图中的三条数据由于是在销假任务完成后设置的,不知道是否是引擎的Bug致使插入这三个表单属性比调用流程结束监听器还晚(从引擎的日志中能够分析出来)致使这三条记录不能被删除,由于在删除的时候这三条数据尚未插入到数据库。

这个问题后面会继续跟踪,解决了会在这里更新!!!

23 Jan 2014
分享到: 0
Comments

剖析Activiti的Activity

1. 窥视Activity内部

在设计流程时每个组件在Activiti中均可以称之为——Activity,部署流程时引擎把XML文件保存到数据库,当启动流程、完成任务时会从数据库读取XML并转换为Java对象,不少人想在处理任务时获取任务的一些配置,例如某个任务配置了哪些监听器或者条件Flow配置了什么条件表达式。

2. 代码

下面的代码作了简单的演示,根据不一样的Activity类型输出属性,读者能够继续探索其余不一样类型Activity的属性,最终能够获取到全部Activity的属性。

3. 输出结果示例

{taskDefinition=org.activiti.engine.impl.task.TaskDefinition@19c6e4d1, default=null, name=部门领导审批, documentation=null, type=userTask}
{conditionText=${!deptLeaderPass}, condition=org.activiti.engine.impl.el.UelExpressionCondition@50d8628f, name=不一样意, documentation=null}
{conditionText=${deptLeaderPass}, condition=org.activiti.engine.impl.el.UelExpressionCondition@2e2ec3c0, name=赞成, documentation=null}
{taskDefinition=org.activiti.engine.impl.task.TaskDefinition@3589f0, default=null, name=调整申请, documentation=null, type=userTask}
{taskDefinition=org.activiti.engine.impl.task.TaskDefinition@3af2ebab, default=null, name=人事审批, documentation=null, type=userTask}
{conditionText=${hrPass}, condition=org.activiti.engine.impl.el.UelExpressionCondition@224e45c9, name=赞成, documentation=null}
{conditionText=${!hrPass}, condition=org.activiti.engine.impl.el.UelExpressionCondition@40c7a0b7, name=不一样意, documentation=null}
{taskDefinition=org.activiti.engine.impl.task.TaskDefinition@72086f9a, default=null, name=销假, documentation=null, type=userTask}
{conditionText=${reApply}, condition=org.activiti.engine.impl.el.UelExpressionCondition@7d721f3, name=从新申请, documentation=null}
{conditionText=${!reApply}, condition=org.activiti.engine.impl.el.UelExpressionCondition@3cf5dc8a, name=结束流程, documentation=null}
{name=Start, documentation=null, type=startEvent}
{name=End, documentation=null, type=endEvent}

更多博客

本文目的: 将activit 5.12.1 的 modeler 流程设计器 集成到本身的工程中去

 

解决问题:

1. 复制相关资源文件到本身的工程中

2. 解决modeler的路径访问问题,迁移到非系统根目录

3. 跟本身系统的spring无缝集成

 

首先请下载官方最新 5.12.1 发布包

下载地址: https://github.com/Activiti/Activiti/archive/activiti-5.12.1.zip

解压后以下图



 

 

步骤:

1. 复制相关文件

1.1首先复制类路径资源文件


复制 \modules\activiti-webapp-explorer2\src\main\resources\下


db.properties 没有选中
 
 选中文件到你的classpath 根目录下,(src 或者resource 类路径下)

 

1.2 复制ui文件到你的webroot文件夹中

 

在 WebRoot目录中创建一个文件夹 取名 modeler

 

复制 modules\activiti-webapp-explorer2\src\main\webapp 下

 




 
 选中文件夹 到modeler目录下.

 

1.3 修改web.xml文件. 添加modeler的servlet

添加以下代码:

Java代码   收藏代码
  1. <!-- Restlet adapter, used to expose modeler functionality through REST -->  
  2.     <servlet>  
  3.         <servlet-name>RestletServlet</servlet-name>  
  4.         <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>  
  5.         <init-param>  
  6.             <!-- Application class name -->  
  7.             <param-name>org.restlet.application</param-name>  
  8.             <param-value>org.activiti.explorer.rest.application.ExplorerRestApplication</param-value>  
  9.         </init-param>  
  10.     </servlet>  
  11.   
  12.   
  13.   
  14.     <!-- Catch all service requests -->  
  15.     <servlet-mapping>  
  16.         <servlet-name>RestletServlet</servlet-name>  
  17.         <url-pattern>/modeler/service/*</url-pattern>  
  18.     </servlet-mapping>  

 首先确认. 你的工程引入了spring的监听. 也就表明你工程有spring .  由于activit-modeler严重依赖spring.

若是你工程没有spring环境, 建议下面就别看了. (先把本身的ssh , ssi , ssm 等框架搭建起来).

 

若是你使用的是spring mvc  建议你在你的mvc控制文件中加入

 

Java代码   收藏代码
  1. <mvc:resources location="/modeler/" mapping="/modeler/**" />  

 

由于颇有可能你根我同样过滤的是全部路径



 

 

 

1.4 复制modules\activiti-webapp-explorer2\src\main\java\org\activiti\explorer\rest\application下的

ExplorerRestApplication.java文件到你的classpath路径下(会提示报错. 必须的. 由于尚未引入相关jar依赖)

 

1.5 在你的pom.xml文件中引入以下代码

仓库:

Java代码   收藏代码
  1. <repository>  
  2.             <id>buzzmedia</id>  
  3.             <url>http://maven.thebuzzmedia.com</url> <!-- ImageScalr -->  
  4.         </repository>  
  5.         <repository>  
  6.             <id>activiti</id>  
  7.             <name>Activiti</name>  
  8.             <url>https://maven.alfresco.com/nexus/content/repositories/activiti/</url>  
  9.         </repository>  
  10.         <repository>  
  11.             <id>Alfresco thirdparty</id>  
  12.             <url>https://maven.alfresco.com/nexus/content/repositories/thirdparty/</url>  
  13.         </repository>  
  14.         <repository>  
  15.             <id>activiti-third-party</id>  
  16.             <name>Activiti third party</name>  
  17.             <url>https://maven.alfresco.com/nexus/content/repositories/activiti-thirdparty/</url>  
  18.         </repository>  
  19.         <repository>  
  20.             <id>maven-restlet</id>  
  21.             <name>Public online Restlet repository</name>  
  22.             <url>http://maven.restlet.org</url>  
  23.         </repository>  

 jar依赖

Java代码   收藏代码
  1. <dependency>  
  2.             <groupId>org.activiti</groupId>  
  3.             <artifactId>activiti-modeler</artifactId>  
  4.             <version>${activiti.version}</version>  
  5.         </dependency>  
  6.         <dependency>  
  7.             <groupId>org.activiti</groupId>  
  8.             <artifactId>activiti-explorer</artifactId>  
  9.             <version>${activiti.version}</version>  
  10.             <exclusions>  
  11.                 <exclusion>  
  12.                     <groupid>com.vaadin</groupid>  
  13.                     <artifactid>vaadin</artifactid>  
  14.                 </exclusion>  
  15.                 <exclusion>  
  16.                     <groupid>org.vaadin.addons</groupid>  
  17.                     <artifactid>dcharts-widget</artifactid>  
  18.                 </exclusion>  
  19.                 <exclusion>  
  20.                     <artifactid>activiti-simple-workflow</artifactid>  
  21.                     <groupid>org.activiti</groupid>  
  22.                 </exclusion>  
  23.             </exclusions>  
  24.         </dependency>  
  25. <!-- 查看流程详细定义 -->  
  26.         <dependency>  
  27.             <groupId>org.activiti</groupId>  
  28.             <artifactId>activiti-diagram-rest</artifactId>  
  29.             <version>${activiti.version}</version>  
  30.         </dependency>  

 

修改 diagram-viewer\index.html

文件.

若是你打算使用他的流程跟踪的话(建议修改,5.13版本跟踪页面已经支持IE了.不集成还费劲本身搞跟踪图提示呢?)

只须要使用5.13的

jstools.js

ProcessDiagramCanvas.js

在 \modules\activiti-webapp-explorer2\src\main\webapp\diagram-viewer\js 下

这两个js 替换 5.12.1的同名js便可



  

 

OK编译,clean 下载jar. ....

 

 

里面的spring版本替换成你本身的版本

 

 

OK了. 至此,集成到项目中也就完成了.

是否要测试下?

 

启动

访问:

http://localhost:8080/YouPRJ/modeler/service/editor?id=2050

2050 替换成本身的流程部署文件id



 

 

 

OK能够直接编辑. 保存.

 



 

 

=======================================================================

 

 

以上是嵌入部署. 

下面是独立部署. 你也能够直接使用官方的activiti-explorer  (呵呵.有点大.多余功能用不上)

 

这个是我从explorer里面分离出来的 单独modeler模块. (maven-eclipse工程)

 

https://github.com/izerui/activiti-modeler

 

能够打包war包.跟你的项目放同一个web容器中.便可使用

 

http://localhost:8080/activiti-modeler/modeler/service/editor?id=2050

直接设计保存到数据库.

 

哦忘了. 前提你要修改数据库链接.哈哈

 



 

 

OK 了.   至此   activiti-modeler 嵌入式部署. 和独立式部署 都完成了.

 

建议:

使用独立部署方式. 只是在你的web容器中多了一个activiti-modeler.war而已. 

效果你可使用iframe.由于在同域下. 其实跟嵌入式都同样的.