Flowable实战(六)集成JPA
上文提到,Flowable所有的表单数据都保存在一张表(act_hi_varinst)中,随着时间的推移,表中数据越来越多,再加上数据没有结构优化,查询使用效率会越来越低。
在Flowable,可以通过集成JPA解决上述问题。JPA把表单数据保存在用户自定义的表中,有利于查询优化。
一、什么是JPA
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA在大多数系统中已经得到广泛应用,越来越多的开源框架发布了自己的JPA实现,例如Hibernate、Open JPA、Spring Data等。
二、JPA支持
在Springboot中,为Flowable添加JPA支持,增加下列依赖:
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring.boot.version}</version>
</dependency>
这会加入JPA用的Spring配置以及bean。默认使用Hibernate作为JPA提供者。
注意:JPA只是接口规范,没有具体实现,与Flowable使用的ORM框架MyBatis并无冲突。
在classpath的application.properties文件加入下列参数,自动创建数据库表。
spring.jpa.hibernate.ddl-auto=update
另外,推荐引用lombok包,可以让我们省去实体类写Getter和Setter方法的工作。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
三、JPA版本的请假流程
3.1 简单的请假流程
我们以一个简单的请假流程为实例说明JPA的具体使用。该请假实例只有一个用户任务,由用户填写表单数据,发起一个请假流程实例,后交由部门经理leader审批。
请假流程图示:

流程定义leave-process.bpmn20.xml
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:flowable="http://flowable.org/bpmn"
targetNamespace="Examples">
<process id="leaveProcess" name="The leave Process" >
<startEvent id="theStart" flowable:formKey="leave">
</startEvent>
<sequenceFlow sourceRef="theStart" targetRef="theLeaderApprove" />
<userTask id="theLeaderApprove" name="部门经理审批" flowable:candidateGroups="leader">
</userTask>
<sequenceFlow sourceRef="theLeaderApprove" targetRef="theEnd" />
<endEvent id="theEnd" >
</endEvent>
</process>
</definitions>
请假表单leave.form
{
"key": "leave",
"name": "请假流程",
"fields": [
{
"id": "startTime",
"name": "开始时间",
"type": "date",
"required": true,
"placeholder": "empty"
},
{
"id": "endTime",
"name": "结束时间",
"type": "date",
"required": true,
"placeholder": "empty"
},
{
"id": "reason",
"name": "请假原因",
"type": "text",
"required": true,
"placeholder": "empty"
}
]
}
3.2 启动流程时持久化JPA实体
定义一个请假申请表单类
@Data
@Entity(name="event_leave")
public class LeaveEntity implements Serializable {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String processInstanceId;
private LocalDate StartTime;
private LocalDate endTime;
private String reason;
private String leaderApproved;
}
注意:Flowable表单类型“Date”映射的是org.joda.time.LocalDate类,并不是JDK8自带的java.time.LocalDate类。
在流程中配置一个start类型的监听器,作用是读取用户填写的表单内容并创建实体类对象持久化到数据库中。
修改XML内容:
<startEvent id="theStart" flowable:formKey="leave">
<extensionElements>
<flowable:executionListener event="start" expression="${execution.setVariable('leave', leaveEntityManager.newLeave(execution))}}">
</flowable:executionListener>
</extensionElements>
</startEvent>
增加一个实体管理器,将表单数据映射成实体类并存入库。
@Service
public class LeaveEntityManager {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public LeaveEntity newLeave(DelegateExecution execution) {
LeaveEntity leave = new LeaveEntity();
leave.setProcessInstanceId(execution.getProcessInstanceId());
leave.setStartTime((LocalDate)execution.getVariable("startTime"));
leave.setEndTime((LocalDate)execution.getVariable("endTime"));
leave.setReason(execution.getVariable("reason").toString());
entityManager.persist(leave);
return leave;
}
}
下面展示填写表单,启动流程的具体代码。
Service层代码:
@Service
public class jpaService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private RepositoryService repositoryService;
@Transactional
public void startProcess() {
List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("leaveProcess").orderByProcessDefinitionId().desc().list();
String proDefId = processDefinitionList.get(0).getId();
Map<String, Object> formProp = new HashMap();
formProp.put("reason", "家里有事");
formProp.put("startTime", LocalDate.now());
formProp.put("endTime", LocalDate.now());
String outcome = "outStr";
runtimeService.startProcessInstanceWithForm(proDefId, outcome, formProp, "表单任务");
}
}
Controller层代码:
@RequestMapping("/jpa")
@RestController
public class jpaController {
@Autowired
private jpaService myService;
@RequestMapping(value="/process", method= RequestMethod.POST)
public void startProcessInstance() {
myService.startProcess();
}
}
启动应用后,使用cURL测试:
curl http://localhost:8080/jpa/process
这样在流程启动后查询数据表event_leave就看到一条数据:

我们再来观察运行时变量表:

可以看到变量“leave”的类型字段(TYPE-)为“jpa-entity”,该记录的“TEXT-”、“TEXT2-“字段分别代表实体的完整类名和主键ID。
3.3 更改JPA实体属性
在流程运行时,如果用户在办理时填写了任务表单,那么还需要把改动的数据更新到实体中,比如:部门领导审核节点完成时保存审批意见。
同样的,在用户任务上添加一个complete类型的监听器。
修改XML内容:
<userTask id="theLeaderApprove" name="部门经理审批" flowable:candidateGroups="leader">
<extensionElements>
<flowable:taskListener event="complete" expression="${leave.setLeaderApproved(leaderApproved)}">
</flowable:taskListener>
</extensionElements>
</userTask>
Service层增加方法:
@Transactional
public void complete(String groupName) {
List<Task> taskList = taskService.createTaskQuery().taskCandidateGroup(groupName).orderByTaskCreateTime().desc().list();
String taskId = taskList.get(0).getId();
Map<String, Object> param = new HashMap();
param.put("leaderApproved", true);
taskService.complete(taskId, param);
}
Controller层增加方法:
@RequestMapping(value="/complete", method= RequestMethod.GET, produces= MediaType.APPLICATION_JSON_VALUE)
public void complete(@RequestParam String groupName) {
myService.complete(groupName);
}
使用cURL测试:
http://localhost:8080/jpa/complete?groupName=leader
查看请假表数据:

同样变量表中的值也被修改。
上面我们只是设置了变量值,没有修改数据库,为什么就达到了修改实体属性的目的呢?这是因为Springboot已经帮我们配置了事务管理器,即由Springboot接管了Flowable的事务,当更改实体属性并提交事务时,就自动执行了数据库的update操作。
3.4 清理历史表单数据
现在我们已经成功把表单数据单独保存在用户自定义表中,但还有一个问题没有解决,那就是把历史变量表的对应数据删除,给历史变量表瘦身,提高查询效率。
同样的,我们设置一个end类型的监听器清理历史表单数据。
修改XML内容:
<endEvent id="theEnd" >
<extensionElements>
<flowable:executionListener event="end" delegateExpression="${leaveEndListener}">
</flowable:executionListener>
</extensionElements>
</endEvent>
leaveEndListener是一个service类,内容是把历史变量表act_hi_varinst中对应的变量数据删除。
@Service
@Transactional
class LeaveEndListener implements ExecutionListener {
@PersistenceContext
private EntityManager entityManager;
@Override
public void notify(DelegateExecution execution) {
String processInstanceId = execution.getProcessInstanceId();
String sql = "delete from act_hi_varinst where proc_inst_id_ = ?";
entityManager.createNativeQuery(sql).setParameter(1, processInstanceId).executeUpdate();
}
}
四、小结
本篇详细介绍了Flowable与JPA的继承,把表单数据保存到自定义的表中,不仅把原来“无结构”的数据转换为“有结构”的数据,还减少了变量表的数据量,提高了数据的查询、使用效率。
Flowable实战(六)集成JPA的更多相关文章
- Spring同时集成JPA与Mybatis
@ 目录 ORM Spring ORM Spring ORM 同时集成JPA与Mybatis 一.创建一个SpringBoot项目 二.建立用户信息登记表 三.Web应用项目集成mysql 四.添加S ...
- Flowable实战(五)表单和流程变量
一.流程变量 流程实例按步骤执行时,需要保存并使用一些数据,在Flowable中,这些数据称为变量(variable). 流程实例可以持有变量,称作流程变量(process variables ...
- springboot 集成 jpa/hibernate
pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- Spring Boot集成JPA的Column注解命名字段无效的问题
偶然发现,Spring Boot集成jpa编写实体类的时候,默认使用的命名策略是下划线分隔的字段命名. Spring Boot版本:1.5.4.release 数据表: id int, userNam ...
- spring集成jpa【为什么有 persistant.xml 文件呢?】
原文地址: http://www.cnblogs.com/javahuang/archive/2012/12/19/2824633.html spring集成JPA的其中一种方式 JPA和hibern ...
- 对ORM的支持 之 8.4 集成JPA ——跟我学spring3
8.4 集成JPA JPA全称为Java持久性API(Java Persistence API),JPA是Java EE 5标准之一,是一个ORM规范,由厂商来实现该规范,目前有Hibernate. ...
- spingboot集成jpa(一)
springboot + jpa 练习 spingboot集成jpa(一):最基本的环境搭建 spingboot集成jpa(二):使用单元测试 1. pom.xml中添加依赖 <!-- jdbc ...
- Python爬虫实战六之抓取爱问知识人问题并保存至数据库
大家好,本次为大家带来的是抓取爱问知识人的问题并将问题和答案保存到数据库的方法,涉及的内容包括: Urllib的用法及异常处理 Beautiful Soup的简单应用 MySQLdb的基础用法 正则表 ...
- spring集成JPA的三种方法配置
JPA是Java EE5规范之一,是一个orm规范,由厂商来实现该规范.目前有hibernate,OpenJPA,TopLink和EclipseJPA等实现 spring提供三种方法集成JPA:1.L ...
随机推荐
- 55 道MySQL基础题
1.一张表,里面有 ID 自增主键,当 insert 了 17 条记录之后, 删除了第 15, 16, 17 条记录,再把 Mysql 重启,再 insert 一条记 录,这条记录的 ID 是 18 ...
- redis hash操作 list列表操作
HSET key 子key 子value 192.168.11.5:6379> HSET stu1 name 'zhangmingda'(integer) 1192.168.11.5:6379& ...
- C库函数将字符串转大小写
头文件 #include <algorithm> transform 函数 转大写 std::string str_write; // 全部转为大写 std::transform(str_ ...
- nim_duilib(14)之xml配置半透明窗体控件不透明
before starting note 截至目前,我只能用xml写一些简单的布局和设置控件属性,循序渐进吧. 正在学习nim_duilib的xml的一些属性. xml配置半透明 GTAV中就有很多控 ...
- typora 基本使用和漂亮的主题样式
以下是使用博客园的markdown的效果: typora 基本使用和漂亮的主题样式 一.typora 基本使用 ps:文字排版,使用markdown nice 可以一键复制到公众号.知乎:https: ...
- Shell实现文件内容批量替换的方法
在Linux系统中,文件内容的批量替换同Windows平台相比要麻烦一点.不过这里可以通过Shell命令或脚本的方式实现批量替换的功能. 笔者使用过两个命令:perl和sed ,接下来会对其做出说明. ...
- Orthogonal Convolutional Neural Networks
目录 概 主要内容 符号说明 的俩种表示 kernel orthogonal regularization orthogonal convolution Wang J, Chen Y, Chakrab ...
- iOS提交AppStore审核时:提示有其他支付并隐藏功能被拒的处理办法
背景提示:数字类产品(比如购买会员等不需要配送实物的商品),Apple规定必须使用苹果IAP应用内支付,给Apple分成30%.打包的时候不要勾选微信或支付宝等其他支付方式.如果你提交的包里包含了微信 ...
- Spring企业级程序设计 • 【第3章 面向切面编程】
全部章节 >>>> 本章目录 3.1 AOP基本概念和术语 3.1.1 AOP概念 3.1.2 AOP的术语解释 3.1.3 通知类型介绍 3.1.4 通过AOP模拟事务操 ...
- Java程序设计基础笔记 • 【第9章 方法与参数类型】
全部章节 >>>> 本章目录 9.1 有参数有返回值的方法 9.1.1 有参数有返回值的方法的定义和调用 9.1.2 返回值的传递过程 9.1.3 方法返回值的注意事项 9 ...