上文提到,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的更多相关文章

  1. Spring同时集成JPA与Mybatis

    @ 目录 ORM Spring ORM Spring ORM 同时集成JPA与Mybatis 一.创建一个SpringBoot项目 二.建立用户信息登记表 三.Web应用项目集成mysql 四.添加S ...

  2. Flowable实战(五)表单和流程变量

    一.流程变量   流程实例按步骤执行时,需要保存并使用一些数据,在Flowable中,这些数据称为变量(variable).   流程实例可以持有变量,称作流程变量(process variables ...

  3. springboot 集成 jpa/hibernate

    pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  4. Spring Boot集成JPA的Column注解命名字段无效的问题

    偶然发现,Spring Boot集成jpa编写实体类的时候,默认使用的命名策略是下划线分隔的字段命名. Spring Boot版本:1.5.4.release 数据表: id int, userNam ...

  5. spring集成jpa【为什么有 persistant.xml 文件呢?】

    原文地址: http://www.cnblogs.com/javahuang/archive/2012/12/19/2824633.html spring集成JPA的其中一种方式 JPA和hibern ...

  6. 对ORM的支持 之 8.4 集成JPA ——跟我学spring3

    8.4  集成JPA JPA全称为Java持久性API(Java Persistence API),JPA是Java EE 5标准之一,是一个ORM规范,由厂商来实现该规范,目前有Hibernate. ...

  7. spingboot集成jpa(一)

    springboot + jpa 练习 spingboot集成jpa(一):最基本的环境搭建 spingboot集成jpa(二):使用单元测试 1. pom.xml中添加依赖 <!-- jdbc ...

  8. Python爬虫实战六之抓取爱问知识人问题并保存至数据库

    大家好,本次为大家带来的是抓取爱问知识人的问题并将问题和答案保存到数据库的方法,涉及的内容包括: Urllib的用法及异常处理 Beautiful Soup的简单应用 MySQLdb的基础用法 正则表 ...

  9. spring集成JPA的三种方法配置

    JPA是Java EE5规范之一,是一个orm规范,由厂商来实现该规范.目前有hibernate,OpenJPA,TopLink和EclipseJPA等实现 spring提供三种方法集成JPA:1.L ...

随机推荐

  1. [BUUCTF]PWN——pwnable_start

    pwnable_start 附件 步骤: 例行检查,32位程序,什么保护都没开,首先想到的是ret2shellcode的方法 本地试运行一下,看看程序大概的情况 32位ida载入,没法f5,好在汇编不 ...

  2. [BUUCTF]PWN4——pwn1_sctf_2016

    [BUUCTF]PWN4--pwn1_sctf_2016 题目网址:https://buuoj.cn/challenges#pwn1_sctf_2016 步骤: 例行检查,32位,开启nx(堆栈不可执 ...

  3. 延时间隔(Project)

    <Project2016 企业项目管理实践>张会斌 董方好 编著 像"饭前洗手"这种事,绝大部分情况下,是洗完手马上就可以动筷子开吃,但总会有意外,比如手都洗好了,突然 ...

  4. 解放生产力「GitHub 热点速览 v.21.51」

    作者:HelloGitHub-小鱼干 解放生产力一直都是我们共同追求的目标,能在摸鱼的空闲把赚了.而大部分好用的工具便能很好地解放我们的生产力,比如本周特推 RedisJSON 不用对 JSON 做哈 ...

  5. 极简!一个注解就能创建Jaeger的Span

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. LuoguP3932 浮游大陆的68号岛 题解

    Content 在一个无限长的数轴上有 \(n\) 个点.第 \(i\) 个点上面有 \(a_i\) 件物品,且第 \(i\) 个点到第 \(i+1\) 个点的距离为 \(b_i\). 定义从第 \( ...

  7. epoll linux和协程gevent的区别

    epoll linux  底层是libevent.so模块实现的 gevent也是IO多路复用,底层是libevent.so模块实现的是更上层的封装 Twsited异步网络框架.代码量非常大.在开源p ...

  8. springboot整合阿里云视频点播接口

    官方SDK文档地址: https://help.aliyun.com/document_detail/57756.html?spm=a2c4g.11186623.6.904.4e0d3bd9VbkIC ...

  9. 【剑指Offer】二叉树中和为某一值的路径 解题报告(Python)

    [剑指Offer]二叉树中和为某一值的路径 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-intervi ...

  10. 如何让 Spring Security 「少管闲事」

    记两种让 Spring Security「少管闲事」的方法. 遇到问题 一个应用对外提供 Rest 接口,接口的访问认证通过 Spring Security OAuth2 控制,token 形式为 J ...