Liferay7 BPM门户开发之5: Activiti和Spring集成
参考文档:
https://github.com/jbarrez/spring-boot-with-activiti-example
https://github.com/sxyx2008/spring-activiti-webapp
http://www.cnblogs.com/hongwz/p/5548473.html
Spring典型配置
<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="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> <property name="driverClass" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" /> <property name="username" value="sa" /> <property name="password" value="" /> </bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean><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><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" />...
自定义的实体类可以这么设置:
<beans> ... <tx:annotation-driven transaction-manager="transactionManager"/><bean id="userBean" class="org.activiti.spring.test.UserBean"> <property name="runtimeService" ref="runtimeService" /> </bean><bean id="printer" class="org.activiti.spring.test.Printer" /></beans>
写注解:
@ContextConfiguration("classpath:org/activiti/spring/test/transaction/SpringTransactionIntegrationTest-context.xml")
然后就可以访问Activiti的工厂类和自定义的实体类,
比如RepositoryService的实例这样获得,同时这也是Spring集成环境下的bpmn文件的部署方式:
RepositoryService repositoryService = (RepositoryService) applicationContext.getBean("repositoryService"); String deploymentId = repositoryService .createDeployment() .addClasspathResource("org/activiti/spring/test/hello.bpmn20.xml") .deploy() .getId();
new 一个自定义的实体类实例:
UserBean userBean = (UserBean) applicationContext.getBean("userBean"); userBean.hello();
自定义的实体类:
public class UserBean {/** Spring 注入 */ private RuntimeService runtimeService;@Transactional public void hello() { runtimeService.startProcessInstanceByKey("helloProcess"); }public void setRuntimeService(RuntimeService runtimeService) { this.runtimeService = runtimeService; } }
表达式
在流程定义文件bpmn20.xml使用表达式
表达式可以灵活动态的使用类的方法,他可以实现流程计算逻辑和实体类的解耦,说具体些就是流程定义文件可以不用Hardcode了,直接通过接口调用的形式访问具体的类,
举例,定义一个输出打印的类,
public class Printer {public void printMessage() {System.out.println("hello world"); } }
在Spring里注册:
<beans> ...<bean id="printer" class="org.activiti.examples.spring.Printer" /></beans>
建立关联配置:
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> ... <property name="beans"> <map> <entry key="printer" value-ref="printer" /> </map> </property> </bean>
最后,就可以在流程定义文件bpmn20.xml使用表达式,定义了一个serviceTask:
这种调用方法非常灵活,也是集成Spring高效和方便的地方
<definitions id="definitions"><process id="helloProcess"><startEvent id="start" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="print" /><serviceTask id="print" activiti:expression="#{printer.printMessage()}" /> <sequenceFlow id="flow2" sourceRef="print" targetRef="end" /><endEvent id="end" /></process></definitions>
使用Spring自动部署bpmn20.xml
仅当文件变化的时候,才会被重新部署,特别方便用于系统调试,程序员必备
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> ... <property name="deploymentResources" value="classpath*:/org/activiti/spring/test/autodeployment/autodeploy.*.bpmn20.xml" /> </bean><bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration" /> </bean>
可以使用通配符
<property name="deploymentResources" value="classpath*:/activiti/*.bpmn" /> <property name="deploymentMode" value="single-resource" />
Hibernate 4.2.x集成
POM:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework.version}</version> </dependency><dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.183</version> </dependency>
配置是不是很简单?
然后就可以开发了
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration;@Configuration @ComponentScan @EnableAutoConfiguration public class MyApplication {public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); }@Bean public CommandLineRunner init(final RepositoryService repositoryService, final RuntimeService runtimeService, final TaskService taskService) {return new CommandLineRunner() { @Override public void run(String... strings) throws Exception { System.out.println("Number of process definitions : " + repositoryService.createProcessDefinitionQuery().count()); System.out.println("Number of tasks : " + taskService.createTaskQuery().count()); runtimeService.startProcessInstanceByKey("oneTaskProcess"); System.out.println("Number of tasks after process start: " + taskService.createTaskQuery().count()); } };} }
使用MySQL数据库
POM:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.34</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>8.0.15</version> </dependency>
数据源
@Bean public DataSource database() { return DataSourceBuilder.create() .url("jdbc:mysql://127.0.0.1:3306/activiti-spring-boot?characterEncoding=UTF-8") .username("alfresco") .password("alfresco") .driverClassName("com.mysql.jdbc.Driver") .build(); }
REST开发扩展
Spring Boot可以快速开发web api接口,REST对集成第三方应用非常重要
POM:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring.boot.version}</version> </dependency>
开发服务类,服务类是用于控制器的重复调用,即帮助类
@Service public class MyService {@Autowired private RuntimeService runtimeService;@Autowired private TaskService taskService;@Transactional public void startProcess() { runtimeService.startProcessInstanceByKey("oneTaskProcess"); }@Transactional public List<Task> getTasks(String assignee) { return taskService.createTaskQuery().taskAssignee(assignee).list(); }}
控制器:
注意:启动流程使用POST,获取任务使用了GET,在输出时自动把实体类(TaskRepresentation)转换为JSON格式
@RestController public class MyRestController {@Autowired private MyService myService;@RequestMapping(value="/process", method= RequestMethod.POST) public void startProcessInstance() { myService.startProcess(); }@RequestMapping(value="/tasks", method= RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE) public List<TaskRepresentation> getTasks(@RequestParam String assignee) { List<Task> tasks = myService.getTasks(assignee); List<TaskRepresentation> dtos = new ArrayList<TaskRepresentation>(); for (Task task : tasks) { dtos.add(new TaskRepresentation(task.getId(), task.getName())); } return dtos; }static class TaskRepresentation {private String id; private String name;public TaskRepresentation(String id, String name) { this.id = id; this.name = name; }public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}}
需要注意@ComponentScan一定在加在application类的注解
测试:
curl -X POST http://localhost:8080/process
curl http://localhost:8080/tasks?assignee=kermit
[{"id":"10004","name":"my task"}]
JPA支持
默认JPA是Hibernate
POM:
<dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter-jpa</artifactId> <version>${activiti.version}</version> </dependency>
实体类:
@Entity class Person {@Id @GeneratedValue private Long id;private String username;private String firstName;private String lastName;private Date birthDate;public Person() { }public Person(String username, String firstName, String lastName, Date birthDate) { this.username = username; this.firstName = firstName; this.lastName = lastName; this.birthDate = birthDate; }public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getUsername() { return username; }public void setUsername(String username) { this.username = username; }public String getFirstName() { return firstName; }public void setFirstName(String firstName) { this.firstName = firstName; }public String getLastName() { return lastName; }public void setLastName(String lastName) { this.lastName = lastName; }public Date getBirthDate() { return birthDate; }public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } }
如果不使用in-memory数据库,数据表不会自动建立,需要 application.properties 增加配置:
spring.jpa.hibernate.ddl-auto=update
增加接口:
public interface PersonRepository extends JpaRepository<Person, Long> {Person findByUsername(String username);}
服务类:
@Service @Transactional public class MyService {@Autowired private RuntimeService runtimeService;@Autowired private TaskService taskService;@Autowired private PersonRepository personRepository;public void startProcess(String assignee) {Person person = personRepository.findByUsername(assignee);Map<String, Object> variables = new HashMap<String, Object>(); variables.put("person", person); runtimeService.startProcessInstanceByKey("oneTaskProcess", variables); }public List<Task> getTasks(String assignee) { return taskService.createTaskQuery().taskAssignee(assignee).list(); }public void createDemoUsers() { if (personRepository.findAll().size() == 0) { personRepository.save(new Person("jbarrez", "Joram", "Barrez", new Date())); personRepository.save(new Person("trademakers", "Tijs", "Rademakers", new Date())); } }}
在CommandLineRunner 初始化的时候,添加用户持久化数据(createDemoUsers())
@Bean public CommandLineRunner init(final MyService myService) {return new CommandLineRunner() { public void run(String... strings) throws Exception {myService.createDemoUsers(); } };}
控制器:
@RestController public class MyRestController {@Autowired private MyService myService;@RequestMapping(value="/process", method= RequestMethod.POST) public void startProcessInstance(@RequestBody StartProcessRepresentation startProcessRepresentation) { myService.startProcess(startProcessRepresentation.getAssignee()); }...static class StartProcessRepresentation {private String assignee;public String getAssignee() { return assignee; }public void setAssignee(String assignee) { this.assignee = assignee; } }
流程定义再一次使用了表达式:
<userTask id="theTask" name="my task" activiti:assignee="${person.id}"/>
测试:POST一个流程启动者的username
curl -H "Content-Type: application/json" -d '{"assignee" : "jbarrez"}' http://localhost:8080/process
curl http://localhost:8080/tasks?assignee=1
[{"id":"12505","name":"my task"}]
更高级的内容可以自行研究:
- Actuator support
- Spring Integration support
- Rest API integration
- Spring Security support
Liferay7 BPM门户开发之5: Activiti和Spring集成相关推荐
- Liferay7 BPM门户开发之11: Activiti工作流程开发的一些统一规则和实现原理(完整版)...
注意:以下规则是我为了规范流程的处理过程,不是Activiti公司的官方规定. 1.流程启动需要设置启动者,在Demo程序中,"启动者变量"名统一设置为initUserId 启动时 ...
- Liferay7 BPM门户开发之4: Activiti事件处理和监听Event handlers
事件机制从Activiti 5.15开始引入,这非常棒,他可以让你实现委托. 可以通过配置添加事件监听器,也可以通过Runtime API加入注册事件. 所有的事件参数子类型都来自org.activi ...
- bpmn 文件 服务器部署,Liferay7 BPM门户开发之45: 集成Activiti文件上传部署流程BPMN模型...
开发文件上传,部署流程模板. 首先,开发jsp页面,deploy.jsp ${RETURN_MESSAGE} 其中,上传form的action为portlet:actionURL,它的name就是在p ...
- Liferay7 BPM门户开发之10: 通用流程实现从Servlet到Portlet(Part1)
开发目的: 实现通用流程自动化处理(即实现不需要hardcode代码的bpm统一处理后台,仅需要写少量前端html form代码和拖拽设计BPM定义) 既可独立运行或可依托于Liferay或依托其它门 ...
- Liferay7 BPM门户开发之46: 集成Activiti用户、用户组、成员关系同步
在实际的BPM集成开发过程中,Liferay和Activiti这两个异构的系统之间,用户.组的同步需求非常重要,用来实现签收组的概念,比如指定签收组.会签.抢签都需要用到. Activiti可以通过自 ...
- liferay7.0 mysql_Liferay7 BPM门户开发之6: Activiti数据库换为mysql
第一步: 在mysql中创建数据库名字叫 'activiti' 执行D:\activiti-5.21.0\database\create下的脚本 第二步: 打开=> apache-tomcat/ ...
- Liferay7 BPM门户开发之24: Liferay7应用程序安全
整理中...... Resources, Roles, and Permissions Portal Access Control List (PACL) Custom SSO Providers A ...
- Activiti学习——Activiti与Spring集成
与Spring集成 基础准备 目录结构 相关jar包 Activiti的相关jar包 Activiti依赖的相关jar包 Spring的相关jar包 Spring依赖的相关jar包 本示例相关 ...
- activiti与spring集成
摘要: 一.集成配置 <bean id="dataSource" class="org.springframework.jdbc.datasource.Simple ...
最新文章
- C# richtextbox 自动下拉到最后 方法 RichTextBox读取txt中文后出现乱码
- spi时序图怎么分析,怎么看懂spi时序图
- (12) Hibernate+EhCache配置二级缓存
- python里面的正则表达式_Python中的正则表达式
- 嵌入式学习之Qt入门第七篇
- [html] button标签的type默认值是什么呢?
- 区块链是大数据生态圈技术之一_区块链技术再发力,携手智能制造构建产业生态圈...
- 架构重构改善既有代码的设计
- 论文阅读:Spatial Transformer Networks
- 2020年9月26日-02-软件工程-工程化思维+瀑布模型+敏捷开发
- html中怎样播放本地视频教程,【Axure9基础教程】内联框架如何引入本地音频 视频 HTML PDF等本地文件...
- java gc堆中的分区_jvm内存各个区域详解
- ZCTF2015 pwn试题分析
- JavaWeb中实现验证码(servlet版)
- 232转485通讯测试软件,(DIY制作)多功能调试工具——实现USB转:485/232/NRF24L01等(原理图和程序)...
- TCP BBR - 一键安装最新内核并开启 TCP BBR
- 旧手机改文件储存服务器,旧手机改云服务器
- Hi3861 ADC驱动 如何使用开发板上的3个按键
- android 广播的插件化
- VisualStudio/VS在一个项目中添加多个c++文件