Activiti6简明教程,关于自定义sql查询

Activiti流程 关于自定义sql查询,activitisql

由于才接触Activiti不久,对于表结构也不熟悉,甚至可以说连那些表对应的实体类都搞不清楚,又不能通过Activiti自带的链式查询实现;在这种情况下跟不知道怎么通过sql去实现自己想要的查询。上网看了些别人关于Activiti的介绍也不是很多,有的时候在自己模棱两可情况下看了别人的资料更不知道该怎么做了。

例如:我现在需要做个流程的已办事项,结果activiti的人都知道,activiti会将我们正在执行的任务复制一份在历史表中,要是这个任务完成了的话,他就会将正在执行的任务表中的数据清除使历史任务表中的数据结束时间有值,但是如果正在执行的任务没有完成的话,我们历史表就会用一条数据,如果现在将这条数据展示给用户的话,用户的体验就会很不好。

通常我们会使用链式查询出历史表中的所有数据:

List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery().taskAssignee(organid)
                                            .orderByHistoricActivityInstanceStartTime().desc().listPage(pagin.getStartResult(), pagin.getPageSize());

这样查询出来的任务列表他包含了结束时间为空的数据,直接给用户展示的话,用户的体验就不好了。

如果我使用拼写sql的形式去查询“END_TIME_ is not null”就直接 简单的多。但是我们该怎么写这个sql呢?

List<HistoricTaskInstance> tasks = historyService.createNativeHistoricTaskInstanceQuery()
        .sql("select * from " + managementService.getTableName(HistoricTaskInstance.class)+" H where H.END_TIME_ is not null and H.ASSIGNEE_ like #{organid} order by H.END_TIME_ desc")
        .parameter("organid", "%"+organid+"%")
        .listPage(pagin.getStartResult(), pagin.getPageSize());

代码中标红处:1、通过managementService接口找到我们需要使用的class类直接转换为对应的表,这样的话  我们不需要去知道这个实体所对应的表文件是“谁”了。

         2、使用了模糊查询,看网上别人的帖子,最开始以为activiti的模糊查询跟其他的模糊查询是一样的,可是自己试了下后,总是表示拼写的sql从在错误。才发现“%”拼错地方了这个东西需要拼写到参数这边,而不是拼写到sql语句中。

 

 

问题:其实在做已办事项的时候  我遇到一个问题,虽然后面我通过歪点子解决了这个问题,但是心里其实还是很想知道 activiti大神 或者是activiti正常的思维是怎么解决类似的问题的。

由于我这儿的流程很多,在已办中用于区分开不同分类的流程,使其分发走不同的业务Action;必须需要一个属性来区分,故而将其流程的key定义为每个业务类的类名(类名不能重复);那么问题来了,如何在历史任务中获得ProcessDefinitionKey

问题描述:

如果是待办事项的话 我们可以很轻松的从ProcessInstance对象中拿到ProcessDefinitionKey(这个字段我是用的是对应流程业务类的类名),但是在已办事项中这个字段从HistoricProcessInstance这个对象中拿不到的。不知道给位使用过activiti的同仁们是怎么做到的。

解决方案:

我对于activiti的存放是这样的:我在启动流程的时候设置了流程BUSINESS_KEY(业务类的类名.业务的ID),由于我的流程的key对于的也是业务类的类名所以这儿就能偷到这个懒,当然有些人这个BUSINESS_KEY是直接存放的业务ID。

关于自定义sql查询,activitisql 由于才接触Activiti不久,对于表结构也不熟悉,甚至可以说连那些表对应的实体类都搞不清楚,又...

图片 1工作流引擎对比图片 27大接口

7大接口
  1. RepositoryService:提供一系列管理流程部署和流程定义的API。
  2. RuntimeService:在流程运行时对流程实例进行管理与控制。
  3. TaskService:对流程任务进行管理,例如任务提醒、任务完成和创建任务等。
  4. IdentityService:提供对流程角色数据进行管理的API,这些角色数据包括用户组、用户及它们之间的关系。
  5. ManagementService:提供对流程引擎进行管理和维护的服务。
  6. HistoryService:对流程的历史数据进行操作,包括查询、删除这些历史数据。
  7. FormService:表单服务。
28张表

图片 328张表

1、act_ge_ 通用数据表,ge是general的缩写2、act_hi_ 历史数据表,hi是history的缩写,对应HistoryService接口3、act_id_ 身份数据表,id是identity的缩写,对应IdentityService接口4、act_re_ 流程存储表,re是repository的缩写,对应RepositoryService接口,存储流程部署和流程定义等静态数据5、act_ru_ 运行时数据表,ru是runtime的缩写,对应RuntimeService接口和TaskService接口,存储流程实例和用户任务等动态数据

1.将Activiti提供的流程设计器应用activiti-app.war部署到Tomcat的webapps目录。2.创建新的MySql数据库。修改activiti-appWEB-INFclassesMETA-INFactiviti-app目录下的activiti-app.properties配置文件,默认使用H2内存数据库,创建的模型重启后会丢失,改成使用MySql数据库。3.浏览器访问

图片 4请假审批流程图

  • 给每个用户任务指派候选组(有权限执行当前任务的角色)

    图片 5指派候选组图片 6指派候选组

  • 排他网关设置条件分支表达式

    图片 7设置条件分支图片 8设置条件分支

    5.导出流程图为.bpmn20.xml文件

    图片 9导出xml文件

1.在POM文件中添加依赖

<dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter-basic</artifactId> <version>6.0.0</version></dependency>

2.将导出的.bpmn20.xml文件拷贝到项目文件夹/resources/processes下3.application.properties文件添加配置项

spring.activiti.database-schema-update=true

databaseSchemaUpdate配置项可以设置流程引擎启动和关闭时数据库执行的策略。 databaseSchemaUpdate有以下四个值:

  • false:false为默认值,设置为该值后,Activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配时,将在启动时抛出异常。
  • true:设置为该值后,Activiti会对数据库中所有的表进行更新,如果表不存在,则Activiti会自动创建。
  • create-drop:Activiti启动时,会执行数据库表的创建操作,在Activiti关闭时,执行数据库表的删除操作。
  • drop-create:Activiti启动时,执行数据库表的删除操作在Activiti关闭时,会执行数据库表的创建操作。

4.启动应用,会在数据库里创建28张表,表创建好之后停止应用。application.properties文件修改配置项

#每次应用启动不检查Activiti数据表是否存在及版本号是否匹配,提升应用启动速度spring.activiti.database-schema-update=false

5.application.properties文件增加配置项

#保存历史数据级别设置为full最高级别,便于历史数据的追溯spring.activiti.history-level=full

对于历史数据,保存到何种粒度,Activiti提供了history-level属性对其进行配置。history-level属性有点像log4j的日志输出级别,该属性有以下四个值:

  • none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
  • activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
  • audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
  • full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。6.完成以上步骤,就可以在程序中使用自动注入的方式,使用Activiti的7大接口。
@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate TaskService taskService;@Autowiredprivate IdentityService identityService;@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate ProcessEngine processEngine;@Autowiredprivate HistoryService historyService;

每个项目都有自己的用户、角色表,Activiti也有自己的用户、用户组表。因此项目中的用户、角色与Activiti中的用户、用户组要做整合。

//项目中每创建一个新用户,对应的要创建一个Activiti用户//两者的userId和userName一致User admin=identityService.newUser;admin.setLastName;identityService.saveUser;//项目中每创建一个角色,对应的要创建一个Activiti用户组Group adminGroup=identityService.newGroup;adminGroup.setName;identityService.saveGroup(adminGroup);//用户与用户组关系绑定identityService.createMembership;

1.请假申请和请假审批数据库表设计表设计原则:流程数据和业务数据相分离。Activiti相关表只负责流程的跳转、走向等。流程中产生的业务表单数据、审批意见、附件等存储在开发人员定义的业务表中。流程数据和业务数据之间通过processInstanceId和业务数据主键相互关联。

为什么不使用Activiti相关表来存储表单数据和附件?

图片 10activiti参数表

Activiti为了应用的灵活性和通用性采用了纵表的方式存储表单数据。假设一条请假申请表单数据有10个字段,那就需要10条记录存储原本横表只需要一条记录存储的数据。采用纵表的方式会有如下问题:

  • 会有大量的冗余数据并且数据量会急剧的增长
  • 查询语句复杂,查询效率低
  • 尤其不适合做后期的统计报表分析

图片 11activiti附件表

Activiti存储附件使用Blob数据格式,文件存储在数据库里,数据库的数据文件会变得超大,不利于数据库备份和迁移。请假申请表结构

图片 12请假申请表

请假审批表结构

图片 13请假审批表2.填写请假申请表单,启动流程实例图片 14填写请假申请

//启动流程实例,字符串"vacation"是BPMN模型文件里process元素的idProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacation");//流程实例启动后,流程会跳转到请假申请节点Task vacationApply = taskService.createTaskQuery().processInstanceId(processInstance.getId.singleResult();//设置请假申请任务的执行人taskService.setAssignee(vacationApply.getId(), req.getUserId().toString;//设置流程参数:请假天数和表单ID//流程引擎会根据请假天数days>3判断流程走向//formId是用来将流程数据和表单数据关联起来Map<String, Object> args = new HashMap<>();args.put("days", req.getDays;args.put("formId", formId);//完成请假申请任务taskService.complete(vacationApply.getId;

3.待审批列表

图片 15待审批列表

//查出当前登录用户所在的用户组List<Group> groups = identityService.createGroupQuery() .groupMember(String.valueOf.list();List<String> groupNames = groups.stream() .map(group -> group.getName.collect(Collectors.toList;//查询用户组的待审批请假流程列表List<Task> tasks = taskService.createTaskQuery() .processDefinitionKey("vacation") .taskCandidateGroupIn(groupNames) .listPage(pageNum - 1, pageSize);//根据流程实例ID查询请假申请表单数据List<String> processInstanceIds = tasks.stream() .map(task -> task.getProcessInstanceId .collect(Collectors.toList;List<VacationApplyBasicPO> vacationApplyList = vacationRepository.getVacationApplyList(processInstanceIds);

4.请假审批功能

图片 16请假审批

//查询当前审批节点Task vacationAudit = taskService.createTaskQuery() .taskId(req.getTaskId.singleResult();if (req.getAuditResult {//审批通过 //设置流程参数:审批ID Map<String, Object> args = new HashMap<>(); args.put("auditId", auditId); //设置审批任务的执行人 taskService.claim(vacationAudit.getId(), req.getUserId().toString; //完成审批任务 taskService.complete(vacationAudit.getId;} else { //审批不通过,结束流程 runtimeService.deleteProcessInstance(vacationAudit.getProcessInstanceId(), auditId);}

5.查看流程图功能

图片 17查看流程图

//controller层代码@RequestMapping(value = "/image", method = RequestMethod.GET)public void image(HttpServletResponse response, @RequestParam String processInstanceId) { try { InputStream is = vacationService.getDiagram(processInstanceId); if (is == null) return; response.setContentType("image/png"); BufferedImage image = ImageIO.read; OutputStream out = response.getOutputStream(); ImageIO.write(image, "png", out); is.close(); out.close(); } catch (Exception ex) { logger.error("查看流程图失败", ex); }}//service层代码@Overridepublic InputStream getDiagram(String processInstanceId) { //获得流程实例 ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult(); String processDefinitionId = StringUtils.EMPTY; if (processInstance == null) { //查询已经结束的流程实例 HistoricProcessInstance processInstanceHistory = historyService.createHistoricProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult(); if (processInstanceHistory == null) return null; else processDefinitionId = processInstanceHistory.getProcessDefinitionId(); } else { processDefinitionId = processInstance.getProcessDefinitionId(); } //使用宋体 String fontName = "宋体"; //获取BPMN模型对象 BpmnModel model = repositoryService.getBpmnModel(processDefinitionId); //获取流程实例当前的节点,需要高亮显示 List<String> currentActs = Collections.EMPTY_LIST; if (processInstance != null) currentActs = runtimeService.getActiveActivityIds(processInstance.getId; return processEngine.getProcessEngineConfiguration() .getProcessDiagramGenerator() .generateDiagram(model, "png", currentActs, new ArrayList<String>(), fontName, fontName, fontName, null, 1.0);}

最后,spring boot应用打成jar包部署的时候,需要注意:图片 18

本文由华夏彩票发布于关于计算机,转载请注明出处:Activiti6简明教程,关于自定义sql查询

您可能还会对下面的文章感兴趣: