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的繼承,把表單數據保存到自定義的表中,不僅把原來“無結構”的數據轉換為“有結構”的數據,還減少了變量表的數據量,提高了數據的查詢、使用效率。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM