1.介绍

1.1 Spring Boot

Spring Boot基于Spring和“习惯由于配置”原则,实现快速搭建项目的准生产框架。建议现在的Java从业者快速迁移到以Spring Boot为基础开发,这将大大降低开发的难度和极大的提高开发效率。

1.2 Activiti

在做企业级应用开发的时候,为了避免流程和业务的耦合,我们经常会引入工作流来解决业务中所遇到的审批相关的操作。

Activiti是一个轻量级的工作流和业务流程管理平台,它的核心是一个超快的BPMN2引擎。

1.3 spring-boot-starters

Spring Boot基于“习惯优于配置”的原则,为大量第三方的库提供自动配置的功能。由Spring专家Josh Long主导开发的spring-boot-starters为我们在Spring Boot下使用Activiti做了自动配置。

其中主要自动配置包括:
* 自动创建Activiti ProcessEngine的Bean;
* 所有的Activiti Service都自动注册为Spring的Bean;
* 创建一个Spring Job Executor
* 自动扫描并部署位于src/main/resources/processes目录下的流程处理文件。

2.实战

2.1 流程设计

Activi为我们提供了一个基于eclipse的流程设计器,安装地址为:http://activiti.org/designer/update/

新建Activi项目或流程

我们当前模拟一个简单的工作流程,某人想加入某个公司,然后有权限审批的人审批,审批同意后将此人加入组织并输出“加入组织成功”,不同意输出“加入组织失败”。

设计的流程图如下:

流程源码如下:


1. <processid="joinProcess"name="Join process"isExecutable="true">
2. <startEventid="startevent1"name="Start">
3. <extensionElements>
4. <activiti:formPropertyid="personId"name="person id"
5. type="long"required="true"></activiti:formProperty>
6. <activiti:formPropertyid="compId"name="company Id"
7. type="long"required="true"></activiti:formProperty>
8. </extensionElements>
9. </startEvent>
10. <endEventid="endevent1"name="End"></endEvent>
11. <userTaskid="ApprovalTask"name="Approval Task"
12. activiti:candidateUsers="${joinService.findUsers(execution)}"isForCompensation="true">
13. <extensionElements>
14. <activiti:formPropertyid="joinApproved"name="Join Approved"
15. type="enum">
16. <activiti:valueid="true"name="Approve"></activiti:value>
17. <activiti:valueid="false"name="Reject"></activiti:value>
18. </activiti:formProperty>
19. </extensionElements>
20. </userTask>
21. <sequenceFlowid="flow1"sourceRef="startevent1"targetRef="ApprovalTask"></sequenceFlow>
22. <serviceTaskid="AutoTask"name="Auto Task"
23. activiti:expression="${joinService.joinGroup(execution)}"></serviceTask>
24. <sequenceFlowid="flow2"sourceRef="ApprovalTask"targetRef="AutoTask"></sequenceFlow>
25. <sequenceFlowid="flow3"sourceRef="AutoTask"targetRef="endevent1"></sequenceFlow>
26. </process>


 

流程解释:

流程最左边是开始,最右边结束,左二小人图标为用户任务(User Task)需要人参与操作,我们选择有权限的操作的人来源于Spring的bean方法activiti:candidateUsers=”${joinService.findUsers(execution)}”,左三齿轮图标为服务任务(Service Task),是自动执行的任务,自动调用Spring的bean方法。

2.2 项目搭建

pom.xml



    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0</modelVersion>
    5. <groupId>com.wisely</groupId>
    6. <artifactId>activiti</artifactId>
    7. <version>0.0.1-SNAPSHOT</version>
    8. <packaging>jar</packaging>
    9. <name>activiti</name>
    10. <description>Demo project for Spring Boot</description>
    11. <parent>
    12. <groupId>org.springframework.boot</groupId>
    13. <artifactId>spring-boot-starter-parent</artifactId>
    14. <version>1.3.0.RELEASE</version>
    15. <relativePath/><!-- lookup parent from repository -->
    16. </parent>
    17. <properties>
    18. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    19. <java.version>1.8</java.version>
    20. <activiti.version>5.19.0</activiti.version>
    21. </properties>
    22. <dependencies>
    23. <dependency>
    24. <groupId>org.springframework.boot</groupId>
    25. <artifactId>spring-boot-starter-web</artifactId>
    26. </dependency>
    27. <dependency>
    28. <groupId>org.springframework.boot</groupId>
    29. <artifactId>spring-boot-starter-data-jpa</artifactId>
    30. </dependency>
    31. <dependency>
    32. <groupId>mysql</groupId>
    33. <artifactId>mysql-connector-java</artifactId>
    34. </dependency>
    35. <dependency>
    36. <groupId>org.activiti</groupId>
    37. <artifactId>activiti-spring-boot-starter-basic</artifactId>
    38. <version>${activiti.version}</version>
    39. </dependency>
    40. <dependency>
    41. <groupId>org.springframework.boot</groupId>
    42. <artifactId>spring-boot-starter-test</artifactId>
    43. <scope>test</scope>
    44. </dependency>
    45. </dependencies>
    46. <build>
    47. <plugins>
    48. <plugin>
    49. <groupId>org.springframework.boot</groupId>
    50. <artifactId>spring-boot-maven-plugin</artifactId>
    51. </plugin>
    52. </plugins>
    53. </build>
    54. </project>



     

    application.properties配置


    1. spring.jpa.hibernate.ddl-auto=update
    2. spring.jpa.database=MYSQL
    3. spring.datasource.url=jdbc:mysql://192.168.1.68:3306/activiti-spring-boot?characterEncoding=UTF-8
    4. spring.datasource.username=root
    5. spring.datasource.password=密码
    6. spring.datasource.driver-class-name=com.mysql.jdbc.Driver

     

    2.3 核心代码

    实体类


      1. @Entity
      2. publicclass Person {
      3. @Id
      4. @GeneratedValue
      5. private Long personId;
      6. privateString personName;
      7. @ManyToOne(targetEntity = Comp.class)
      8. private Comp comp;
      9. publicPerson(){
      10. }
      11. publicPerson(String personName){
      12. super();
      13. this.personName = personName;
      14. }
      15.  //省略getter、setter方法
      16. }
       
       
       
       
       
      1. @Entity
      2. publicclass Comp {
      3. @Id
      4. @GeneratedValue
      5. private Long compId;
      6. privateString compName;
      7. @OneToMany(mappedBy = "comp",targetEntity = Person.class)
      8. private List<Person> people;
      9. publicComp(String compName){
      10. this.compName = compName;
      11. }
      12. publicComp(){
      13. }
      14. //省略getter、setter方法
      15. }



       

      DAO



        1. publicinterface PersonRepository extends JpaRepository<Person, Long> {
        2. public Person findByPersonName(String personName);
        3. }
         
         
         
         
         
        1. publicinterface CompRepository extends JpaRepository<Comp, Long>{
        2. }


         

        Activiti服务



          1. @Service
          2. @Transactional
          3. publicclass ActivitiService {
          4.  //注入为我们自动配置好的服务
          5. @Autowired
          6. private RuntimeService runtimeService;
          7. @Autowired
          8. private TaskService taskService;
          9.  //开始流程,传入申请者的id以及公司的id
          10. publicvoidstartProcess( Long personId, Long compId){
          11.  Map<String, Object> variables = new HashMap<String, Object>();
          12.  variables.put("personId", personId);
          13.  variables.put("compId", compId);
          14.  runtimeService.startProcessInstanceByKey("joinProcess", variables);
          15. }
          16.  //获得某个人的任务别表
          17. public List<Task> getTasks(String assignee){
          18. return taskService.createTaskQuery().taskCandidateUser(assignee).list();
          19. }
          20.  //完成任务
          21. publicvoidcompleteTasks(Boolean joinApproved, String taskId){
          22.  Map<String, Object> taskVariables = new HashMap<String, Object>();
          23.  taskVariables.put("joinApproved", joinApproved);
          24.  taskService.complete(taskId, taskVariables);
          25. }
          26. }



           

          Service Task服务


          1. @Service
          2. publicclass JoinService {
          3. @Autowired
          4.  PersonRepository personRepository;
          5. @Autowired
          6. private CompRepository compRepository;
          7.  //加入公司操作,可从DelegateExecution获取流程中的变量
          8. publicvoidjoinGroup(DelegateExecution execution){
          9.  Boolean bool = (Boolean) execution.getVariable("joinApproved");
          10. if(bool){
          11.  Long personId = (Long) execution.getVariable("personId");
          12.  Long compId = (Long) execution.getVariable("compId");
          13.  Comp comp = compRepository.findOne(compId);
          14.  Person person = personRepository.findOne(personId);
          15.  person.setComp(comp);
          16.  personRepository.save(person);
          17. System.out.println("加入组织成功");
          18. }else{
          19. System.out.println("加入组织失败");
          20. }
          21. }
          22.  //获取符合条件的审批人,演示这里写死,使用应用使用实际代码
          23. public List<String> findUsers(DelegateExecution execution){
          24. return Arrays.asList("admin","wtr");
          25. }
          26. }

           

          控制器


          1. @RestController
          2. publicclass MyRestController {
          3. @Autowired
          4. private ActivitiService myService;
          5.  //开启流程实例
          6. @RequestMapping(value="/process/{personId}/{compId}", method= RequestMethod.GET)
          7. publicvoidstartProcessInstance(@PathVariable Long personId,@PathVariable Long compId){
          8.  myService.startProcess(personId,compId);
          9. }
          10.  //获取当前人的任务
          11. @RequestMapping(value="/tasks", method= RequestMethod.GET)
          12. public List<TaskRepresentation> getTasks(@RequestParamString assignee){
          13.  List<Task> tasks = myService.getTasks(assignee);
          14.  List<TaskRepresentation> dtos = new ArrayList<TaskRepresentation>();
          15. for(Task task : tasks){
          16.  dtos.add(newTaskRepresentation(task.getId(), task.getName()));
          17. }
          18. return dtos;
          19. }
          20.  //完成任务
          21. @RequestMapping(value="/complete/{joinApproved}/{taskId}", method= RequestMethod.GET)
          22. publicStringcomplete(@PathVariable Boolean joinApproved,@PathVariableString taskId){
          23.  myService.completeTasks(joinApproved,taskId);
          24. return"ok";
          25. }
          26.  //Task的dto
          27. staticclass TaskRepresentation {
          28. privateString id;
          29. privateString name;
          30. publicTaskRepresentation(String id, String name){
          31. this.id = id;
          32. this.name = name;
          33. }
          34. publicStringgetId(){
          35. return id;
          36. }
          37. publicvoidsetId(String id){
          38. this.id = id;
          39. }
          40. publicStringgetName(){
          41. return name;
          42. }
          43. publicvoidsetName(String name){
          44. this.name = name;
          45. }
          46. }
          47. }


           

          入口类


          1. @SpringBootApplication
          2. publicclass ActivitiApplication {
          3. @Autowired
          4. private PersonRepository personRepository;
          5. @Autowired
          6. private CompRepository compRepository;
          7. publicstaticvoidmain(String[] args){
          8.  SpringApplication.run(ActivitiApplication.class, args);
          9. }
          10.  //初始化模拟数据
          11. @Bean
          12. public CommandLineRunner init(final ActivitiService myService){
          13. returnnewCommandLineRunner(){
          14. publicvoidrun(String... strings)throws Exception {
          15. if(personRepository.findAll().size() == 0){
          16.  personRepository.save(newPerson("wtr"));
          17.  personRepository.save(newPerson("wyf"));
          18.  personRepository.save(newPerson("admin"));
          19. }
          20. if(compRepository.findAll().size() == 0){
          21.  Comp group = newComp("great company");
          22.  compRepository.save(group);
          23.  Person admin = personRepository.findByPersonName("admin");
          24.  Person wtr = personRepository.findByPersonName("wtr");
          25.  admin.setComp(group);wtr.setComp(group);
          26.  personRepository.save(admin);personRepository.save(wtr);
          27. }
          28. }
          29. };
          30. }
          31. }


           

          2.4 演示

          启动程序会自动初始化Activiti所用的数据库和我们的业务数据库,并自动发布我们的流程。

          java 集成Activiti activiti集成springboot_spring boot

          java 集成Activiti activiti集成springboot_java 集成Activiti_02

          java 集成Activiti activiti集成springboot_java 集成Activiti_03

          java 集成Activiti activiti集成springboot_spring boot_04

          此时我们要加入的公司id为1,申请加入的人的id为2,使用PostMan访问http://localhost:8080/process/2/1 此时数据库发生如下变化

          java 集成Activiti activiti集成springboot_spring boot_05

          java 集成Activiti activiti集成springboot_java 集成Activiti_06

          此时用户admin和wtr具备审批申请的权利,此时我们访问http://localhost:8080/tasks?assignee=admin 查看admin用户的任务,返回结果为:


          1. [
          2. {
          3. "id":"10",
          4. "name":"Approval Task"
          5. }
          6. ]


           

          我们现在通过访问http://localhost:8080/complete/true/10 完成任务,true为同意(可以选择false),10为task的id,任务完成后会自动调用Service Task,此时wyf这条记录的comp_compId为更新为当前公司的id。

          java 集成Activiti activiti集成springboot_java 集成Activiti_07