新建springBoot项目时勾选activiti,或者在已建立的springBoot项目添加以下依赖:

  1. <dependency>
  2. <groupId>org.activiti</groupId>
  3. <artifactId>activiti-spring-boot-starter-basic</artifactId>
  4. <version>6.0.0</version>
  5. </dependency>

数据源和activiti配置:

  1. server:
  2. port: 8081
  3.  
  4. spring:
  5. datasource:
  6. url: jdbc:mysql://localhost:3306/act5?useSSL=true
  7. driver-class-name: com.mysql.jdbc.Driver
  8. username: root
  9. password: root
  10.  
  11. # activiti default configuration
  12. activiti:
  13. database-schema-update: true
  14. check-process-definitions: true
  15. process-definition-location-prefix: classpath:/processes/
  16. # process-definition-location-suffixes:
  17. # - **.bpmn
  18. # - **.bpmn20.xml
  19. history-level: full

在activiti的默认配置中,process-definition-location-prefix 是指定activiti流程描述文件的前缀(即路径),启动时,activiti就会去寻找此路径下的流程描述文件,并且自动部署;suffix 是一个String数组,表示描述文件的默认后缀名,默认以上两种。

springMVC配置:

  1. package com.yawn.config;
  2.  
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.format.FormatterRegistry;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.web.servlet.config.annotation.*;
  7.  
  8. /**
  9. * Created by yawn on 2017/8/5.
  10. */
  11. @EnableWebMvc
  12. @Configuration
  13. public class MvcConfig extends WebMvcConfigurerAdapter {
  14.  
  15. @Override
  16. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  17. registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
  18. registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
  19. super.addResourceHandlers(registry);
  20. }
  21.  
  22. @Override
  23. public void addViewControllers(ViewControllerRegistry registry) {
  24. registry.addViewController("/index");
  25. registry.addViewController("/user");
  26. registry.addRedirectViewController("/","/templates/login.html");
  27. // registry.addStatusController("/403", HttpStatus.FORBIDDEN);
  28. super.addViewControllers(registry);
  29. }
  30. }

这里配置静态资源和直接访问的页面:在本示例项目中,添加了thymeleaf依赖解析视图,主要采用异步方式获取数据,通过angularJS进行前端数据的处理和展示。

配置了数据源和activiti后,启动项目,activiti 的各个服务组件就已经被加入到spring容器中了,所以就可以直接注入使用了。如果在未自动配置的spring环境中,可以使用通过指定bean的init-method来配置activiti的服务组件。

以以下请假流程为例:

1. 开始流程并“申请请假”(员工)

  1. private static final String PROCESS_DEFINE_KEY = "vacationProcess";
  2.  
  3. public Object startVac(String userName, Vacation vac) {
  4.  
  5. identityService.setAuthenticatedUserId(userName);
  6. // 开始流程
  7. ProcessInstance vacationInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINE_KEY);
  8. // 查询当前任务
  9. Task currentTask = taskService.createTaskQuery().processInstanceId(vacationInstance.getId()).singleResult();
  10. // 申明任务
  11. taskService.claim(currentTask.getId(), userName);
  12.  
  13. Map<String, Object> vars = new HashMap<>(4);
  14. vars.put("applyUser", userName);
  15. vars.put("days", vac.getDays());
  16. vars.put("reason", vac.getReason());
  17. // 完成任务
  18. taskService.complete(currentTask.getId(), vars);
  19.  
  20. return true;
  21. }

在此方法中,Vaction 是申请时的具体信息,在完成“申请请假”任务时,可以将这些信息设置成参数。

2. 审批请假(老板)

(1)查询需要自己审批的请假

  1. public Object myAudit(String userName) {
  2. List<Task> taskList = taskService.createTaskQuery().taskCandidateUser(userName)
  3. .orderByTaskCreateTime().desc().list();
  4. // / 多此一举 taskList中包含了以下内容(用户的任务中包含了所在用户组的任务)
  5. // Group group = identityService.createGroupQuery().groupMember(userName).singleResult();
  6. // List<Task> list = taskService.createTaskQuery().taskCandidateGroup(group.getId()).list();
  7. // taskList.addAll(list);
  8. List<VacTask> vacTaskList = new ArrayList<>();
  9. for (Task task : taskList) {
  10. VacTask vacTask = new VacTask();
  11. vacTask.setId(task.getId());
  12. vacTask.setName(task.getName());
  13. vacTask.setCreateTime(task.getCreateTime());
  14. String instanceId = task.getProcessInstanceId();
  15. ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
  16. Vacation vac = getVac(instance);
  17. vacTask.setVac(vac);
  18. vacTaskList.add(vacTask);
  19. }
  20. return vacTaskList;
  21. }
  22.  
  23. private Vacation getVac(ProcessInstance instance) {
  24. Integer days = runtimeService.getVariable(instance.getId(), "days", Integer.class);
  25. String reason = runtimeService.getVariable(instance.getId(), "reason", String.class);
  26. Vacation vac = new Vacation();
  27. vac.setApplyUser(instance.getStartUserId());
  28. vac.setDays(days);
  29. vac.setReason(reason);
  30. Date startTime = instance.getStartTime(); // activiti 6 才有
  31. vac.setApplyTime(startTime);
  32. vac.setApplyStatus(instance.isEnded() ? "申请结束" : "等待审批");
  33. return vac;
  34. }
  35.  
  36. package com.yawn.entity;
  37.  
  38. import java.util.Date;
  39.  
  40. /**
  41. * @author Created by yawn on 2018-01-09 14:31
  42. */
  43. public class VacTask {
  44.  
  45. private String id;
  46. private String name;
  47. private Vacation vac;
  48. private Date createTime;
  49.  
  50. // getter setter ...
  51. }

老板查询自己当前需要审批的任务,并且将任务和参数设置到一个VacTask对象,用于页面的展示。

(2)审批请假

  1. public Object passAudit(String userName, VacTask vacTask) {
  2. String taskId = vacTask.getId();
  3. String result = vacTask.getVac().getResult();
  4. Map<String, Object> vars = new HashMap<>();
  5. vars.put("result", result);
  6. vars.put("auditor", userName);
  7. vars.put("auditTime", new Date());
  8. taskService.claim(taskId, userName);
  9. taskService.complete(taskId, vars);
  10. return true;
  11. }

同理,result是审批的结果,也是在完成审批任务时需要传入的参数;taskId是刚才老板查询到的当前需要自己完成的审批任务ID。(如果流程在这里设置分支,可以通过判断result的值来跳转到不同的任务)

3. 查询记录

由于已完成的请假在数据库runtime表中查不到(runtime表只保存正在进行的流程示例信息),所以需要在history表中查询。

(1) 查询请假记录

  1. public Object myVacRecord(String userName) {
  2. List<HistoricProcessInstance> hisProInstance = historyService.createHistoricProcessInstanceQuery()
  3. .processDefinitionKey(PROCESS_DEFINE_KEY).startedBy(userName).finished()
  4. .orderByProcessInstanceEndTime().desc().list();
  5.  
  6. List<Vacation> vacList = new ArrayList<>();
  7. for (HistoricProcessInstance hisInstance : hisProInstance) {
  8. Vacation vacation = new Vacation();
  9. vacation.setApplyUser(hisInstance.getStartUserId());
  10. vacation.setApplyTime(hisInstance.getStartTime());
  11. vacation.setApplyStatus("申请结束");
  12. List<HistoricVariableInstance> varInstanceList = historyService.createHistoricVariableInstanceQuery()
  13. .processInstanceId(hisInstance.getId()).list();
  14. ActivitiUtil.setVars(vacation, varInstanceList);
  15. vacList.add(vacation);
  16. }
  17. return vacList;
  18. }

请假记录即查出历史流程实例,再查出关联的历史参数,将历史流程实例和历史参数设置到Vcation对象(VO对象)中去,即可返回,用来展示。

  1. package com.yawn.util;
  2.  
  3. import org.activiti.engine.history.HistoricVariableInstance;
  4.  
  5. import java.lang.reflect.Field;
  6. import java.util.List;
  7.  
  8. /**
  9. * activiti中使用得到的工具方法
  10. * @author Created by yawn on 2018-01-10 16:32
  11. */
  12. public class ActivitiUtil {
  13.  
  14. /**
  15. * 将历史参数列表设置到实体中去
  16. * @param entity 实体
  17. * @param varInstanceList 历史参数列表
  18. */
  19. public static <T> void setVars(T entity, List<HistoricVariableInstance> varInstanceList) {
  20. Class<?> tClass = entity.getClass();
  21. try {
  22. for (HistoricVariableInstance varInstance : varInstanceList) {
  23. Field field = tClass.getDeclaredField(varInstance.getVariableName());
  24. if (field == null) {
  25. continue;
  26. }
  27. field.setAccessible(true);
  28. field.set(entity, varInstance.getValue());
  29. }
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }

此外,以上是查询历史流程实例和历史参数后,设置VO对象的通用方法:可以根据参数列表中的参数,将与VO对象属性同名的参数设置到VO对象中去。

4. 前端展示和操作

(1)审批列表和审批操作示例

  1. <div ng-controller="myAudit">
  2. <h2 ng-init="myAudit()">待我审核的请假</h2>
  3. <table border="0">
  4. <tr>
  5. <td>任务名称</td>
  6. <td>任务时间</td>
  7. <td>申请人</td>
  8. <td>申请时间</td>
  9. <td>天数</td>
  10. <td>事由</td>
  11. <td>操作</td>
  12. </tr>
  13. <tr ng-repeat="vacTask in vacTaskList">
  14. <td>{{vacTask.name}}</td>
  15. <td>{{vacTask.createTime | date:'yyyy-MM-dd HH:mm:ss'}}</td>
  16. <td>{{vacTask.vac.applyUser}}</td>
  17. <td>{{vacTask.vac.applyTime | date:'yyyy-MM-dd HH:mm:ss'}}</td>
  18. <td>{{vacTask.vac.days}}</td>
  19. <td>{{vacTask.vac.reason}}</td>
  20. <td>
  21. <button type="button" ng-click="passAudit(vacTask.id, 1)">审核通过</button>
  22. <button type="button" ng-click="passAudit(vacTask.id, 0)">审核拒绝</button>
  23. </td>
  24. </tr>
  25. </table>
  26. </div>
  27.  
  28. app.controller("myAudit", function ($scope, $http, $window) {
  29. $scope.vacTaskList = [];
  30.  
  31. $scope.myAudit = function () {
  32. $http.get(
  33. "/myAudit"
  34. ).then(function (response) {
  35. $scope.vacTaskList = response.data;
  36. })
  37. };
  38.  
  39. $scope.passAudit = function (taskId, result) {
  40. $http.post(
  41. "/passAudit",
  42. {
  43. "id": taskId,
  44. "vac": {
  45. "result": result >= 1 ? "审核通过" : "审核拒绝"
  46. }
  47. }
  48. ).then(function (response) {
  49. if (response.data === true) {
  50. alert("操作成功!");
  51. $window.location.reload();
  52. } else {
  53. alert("操作失败!");
  54. }
  55. })
  56. }
  57. });

本人免费整理了Java高级资料,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G,需要自己领取。
传送门:https://mp.weixin.qq.com/s/igMojff-bbmQ6irCGO3mqA

在 Spring Boot 项目中使用 activiti的更多相关文章

  1. 你真的理解 Spring Boot 项目中的 parent 吗?

    前面和大伙聊了 Spring Boot 项目的三种创建方式,这三种创建方式,无论是哪一种,创建成功后,pom.xml 坐标文件中都有如下一段引用: <parent> <groupId ...

  2. Spring Boot项目中使用Swagger2

    Swagger2是一款restful接口文档在线生成和在线接口调试工具,Swagger2在Swagger1.x版本的基础上做了些改进,下面是在一个Spring Boot项目中引入Swagger2的简要 ...

  3. 在Spring Boot项目中使用Spock框架

    转载:https://www.jianshu.com/p/f1e354d382cd Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring B ...

  4. Spring Boot2 系列教程(三)理解 Spring Boot 项目中的 parent

    前面和大伙聊了 Spring Boot 项目的三种创建方式,这三种创建方式,无论是哪一种,创建成功后,pom.xml 坐标文件中都有如下一段引用: <parent> <groupId ...

  5. Spring Boot项目中使用Mockito

    本文首发于个人网站:Spring Boot项目中使用Mockito Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试:生成测试数据初始化数据库用于测试 ...

  6. 在Spring Boot项目中使用Spock测试框架

    本文首发于个人网站:在Spring Boot项目中使用Spock测试框架 Spock框架是基于Groovy语言的测试框架,Groovy与Java具备良好的互操作性,因此可以在Spring Boot项目 ...

  7. Spring Boot项目中如何定制拦截器

    本文首发于个人网站:Spring Boot项目中如何定制拦截器 Servlet 过滤器属于Servlet API,和Spring关系不大.除了使用过滤器包装web请求,Spring MVC还提供Han ...

  8. Spring Boot项目中如何定制PropertyEditors

    本文首发于个人网站:Spring Boot项目中如何定制PropertyEditors 在Spring Boot: 定制HTTP消息转换器一文中我们学习了如何配置消息转换器用于HTTP请求和响应数据, ...

  9. Spring Boot项目中如何定制servlet-filters

    本文首发于个人网站:Spring Boot项目中如何定制servlet-filters 在实际的web应用程序中,经常需要在请求(request)外面增加包装用于:记录调用日志.排除有XSS威胁的字符 ...

随机推荐

  1. 2019-9-9:渗透测试,基础学习,phpmyadmin getshell方法,基于时间的盲注,基于报错的注入,笔记

    phpmyadmin getshell方法1,查看是否有导入导出设置 show global variables like '%secure-file-priv%';2,如果secure-file-p ...

  2. linuxLVM

    一.概念性的东西 LVM2:Logical Volume Manager ,Cersion 2 LVM,依赖于内核的dm模块(将一个或多个底层的设备组织成一个逻辑设备的模块).可以将多个物理分区通过软 ...

  3. pyspark报错Exception: Java gateway process exited before sending its port number解决方法

    1.问题 搭建spark的python环境好后简单使用,源代码如下: 然后就给我丢了一堆错误: 2.解决办法 这里指定一下Java的环境就可以了,添加代码: import os os.environ[ ...

  4. 不用任何第三方,写一个RTMP直播推流器

    2016年是移动直播爆发年,不到半年的时间内无数移动直播App掀起了全民直播的热潮.然而个人觉得直播的门槛相对较高,从推流端到服务端器到播放端,无不需要专业的技术来支撑,仅仅推流端就有不少需要学习的知 ...

  5. Netty源码分析之ChannelPipeline(二)—ChannelHandler的添加与删除

    上篇文章中,我们对Netty中ChannelPipeline的构造与初始化进行了分析与总结,本篇文章我们将对ChannelHandler的添加与删除操作进行具体的的代码分析: 一.ChannelHan ...

  6. 2019-2020-3 20199317《Linux内核原理与分析》第三周作业

    第2章  操作系统是如何工作的 1  计算机的三大法宝      存储程序计算机:冯诺依曼结构 函数调用堆栈机制:记录调用的路径和参数的空间 中断机制:由CPU和内核代码共同实现了保存现场和恢复现场, ...

  7. 启动项目报错:org.apache.catalina.LifecycleException: Failed to start component

    原因 环境异常重启,项目java进程未关闭,原项目的端口依旧在占用. 一般为8080端口被占用 解决方法 以下两种方法都可以解决,原理相同(结束异常进程) 1. 简单粗暴: 打开任务管理器找到java ...

  8. 微信小程序——页面栈

    刚开始用小程序的时候没怎么在意页面的跳转,也没仔细看文档中说的页面栈的内容.只要能跳转就行,wx.navigateTo,wx.redirectTo 这些方法一顿乱用.最后在做一个十层页面(以前页面栈是 ...

  9. DS1302时钟芯片驱动程序

    /***************************************************************************** FileName : DS1302.c F ...

  10. java内存模型和内存结构

    java内存模型说的是多线程,网上可能会有写误导,并不是什么堆.栈.方法区,很多人都会搞混.说白了就是多线程中主线程和本地线程之间的一个数据可见性问题. jmm:java内存模型:jvm:java内存 ...