Springboot 项目搭建activiti流程项目demo

Springboot 项目搭建activiti流程项目demo

首先在pom文件中添加依赖:

<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti5-engine</artifactId>
            <version>6.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring</artifactId>
            <version>6.0.0</version>
        </dependency>

        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
//数据库依赖
<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

更改配置文件application.yml:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3366/activiti?useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true&serverTimezone=UTC
    username: root
    password: 123456
    data: activiti.cfg.xml

在resources资源文件下添加xml配置文件。文件名必须为:activiti.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3366/activiti??useUnicode=true&amp;characterEncoding=UTF-8&amp;nullCatalogMeansCurrent=true&amp;serverTimezone=UTC"></property>
        <property name="jdbcUsername" value="root"></property>
        <property name="jdbcPassword" value="123456"></property>
        <property name="databaseSchemaUpdate" value="true"></property>
    </bean>
</beans>

在整个项目中,引包的时候要注意,因为包不一样对应程序可能不同。
添加activiti测试类,自动将activiti用到的表加入数据库中:

package activiti;

import jdk.nashorn.internal.ir.CallNode;
import org.activiti5.engine.ProcessEngine;
import org.activiti5.engine.ProcessEngineConfiguration;
import org.junit.Test;

public class ActivitiText {
//两种方法都可
    @Test
    public void testInit(){
        //创建流程引擎配置对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
        configuration.setJdbcDriver("com.mysql.cj.jdbc.Driver");
        configuration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti_1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC");
        configuration.setJdbcUsername("root");
        configuration.setJdbcPassword("root");
        //创建表
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        //构建流程引擎
        ProcessEngine ProcessEngine = configuration.buildProcessEngine();

    }
    

    @Test
    public void creatTable(){
        ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml").buildProcessEngine();
    }
}

运行后发现数据库中自动加入了16张表,activiti.6.0.0应该为26张。是因为目前没有写相关流程业务。


在idea中添加插件,因为本人未找到actiBMPN插件,所以添加了activiti BPMN。
在这里插入图片描述
创建activiti配置类:

package com.dsr.config;

import lombok.SneakyThrows;
import org.activiti.engine.*;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.io.IOException;
import java.lang.management.PlatformLoggingMXBean;

@Configuration
public class ActivitiConfig {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;
	
    @Bean
    public SpringProcessEngineConfiguration springProcessEngineConfiguration(){
        SpringProcessEngineConfiguration processEngineConfiguration = new SpringProcessEngineConfiguration();
        processEngineConfiguration.setDataSource(dataSource);
        processEngineConfiguration.setTransactionManager(platformTransactionManager);
        processEngineConfiguration.setDatabaseSchemaUpdate("true");
        Resource[] resources = null;
        try{
        //流程资源目录
            resources = new PathMatchingResourcePatternResolver().getResources("classpath*:bpmn/*.bpmn");

        } catch (IOException e){
            e.printStackTrace();
        }
        processEngineConfiguration.setDeploymentResources(resources);
        return processEngineConfiguration;
    }

    @Bean
    public ProcessEngineFactoryBean processEngineFactoryBean(){
        ProcessEngineFactoryBean processEngine = new ProcessEngineFactoryBean();
        processEngine.setProcessEngineConfiguration(springProcessEngineConfiguration());
        return processEngine;
    }

    @Bean
    public RepositoryService repositoryService() throws Exception{
        return processEngineFactoryBean().getObject().getRepositoryService();
    }

    @Bean
    public RuntimeService runtimeService() throws Exception{
        return processEngineFactoryBean().getObject().getRuntimeService();
    }

    @Bean
    public TaskService taskService() throws Exception{
        return processEngineFactoryBean().getObject().getTaskService();
    }

    @Bean
    public HistoryService historyService() throws Exception{
        return processEngineFactoryBean().getObject().getHistoryService();
    }

    @SneakyThrows
    @Bean
    public ManagementService managementService(ProcessEngine processEngine) {
        return processEngineFactoryBean().getObject().getManagementService();
    }

    @SneakyThrows
    @Bean
    public IdentityService identityService(ProcessEngine processEngine) {
        return processEngineFactoryBean().getObject().getIdentityService();
    }
}

若运行测试类后,未能自动添加表,可以在写完配置类后,运行程序:

package com.dsr;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication(scanBasePackages = {"com.dsr"})
//@MapperScan("com.dsr.mapper")
@MapperScan("com.dsr.mapper")
@ComponentScan({"com.dsr.config"})
public class Application {
    public static void main(String[] args){
        SpringApplication.run(Application.class,args);

    }
}

在配置文件中配置了getResources(“classpath*:bpmn/*.bpmn”),所以需要在resources文件下创建对应的bpmn文件夹。在bpmn文件夹下创建文件:
在这里插入图片描述
创建好之后,右击选择View BPMN之后打开文件,在空白处右击即可开始画流程图。(需要设置ID、name等)
在这里插入图片描述

画好之后连线问题,注意点击图标后可以在右上角看见箭头,后需要再点一次进行连接。
在这里插入图片描述
出现这样才可以连线。
流程图画好之后,可以看到对应的xml文件新增了内容:
在这里插入图片描述

创建实体类,创建时须在数据库中有对应表,这里用到了Lombok如何集成可以见之前博客:

package com.dsr.dao;

import lombok.Data;

import java.util.Date;

@Data
public class ActivitiTask {
    private String id;
    private String activiti;
    private String name;
    private Date startTime;

}

package com.dsr.dao;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Date;


@Data
@AllArgsConstructor
public class Activiti {
    /**
     * 申请人
     */
    private String applyUser;
    private int days;
    private String reason;
    private Date applyTime;
    private String applyStatus;

    /**
     * 审核人
     */
    private String auditor;
    private String result;
    private Date auditTime;

}

创建activiti接口:

package com.dsr.service;

import com.dsr.dao.Activiti;
import com.dsr.dao.ActivitiTask;

import java.util.List;


public interface AcitivitiService {
    public Boolean startActiviti(Activiti act,String username);

    public List<String> myActiviti(String username);

    public List<ActivitiTask> myApproval(String name);

    public Boolean passApproval(String name,ActivitiTask task);

    public List<Activiti> myActivitiRecord(String name);

    public List<Activiti> myApprovalRecord(String name);

}

创建接口实现类:

package com.dsr.service.impl;

import com.dsr.dao.Activiti;
import com.dsr.dao.ActivitiTask;
import com.dsr.service.AcitivitiService;
import com.dsr.util.ActivitiUtil;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 RepositoryService:  流程仓库Service,用于管理流程仓库,例如:部署,删除,读取流程资源
 IdentityService:身份Service,可以管理,查询用户,组之间的关系
 RuntimeService:运行时Service,可以处理所有正在运行状态的流程实例,任务等
 TaskService:任务Service,用于管理,查询任务,例如:签收,办理,指派等
 HistoryService:历史Service,可以查询所有历史数据,例如:流程实例,任务,活动,变量,附件等
 FormService:表单Service,用于读取和流程,任务相关的表单数据
 ManagementService:引擎管理Service,和具体业务无关,主要是可以查询引擎配置,数据库,作业等
 DynamicBpmnService:一个新增的服务,用于动态修改流程中的一些参数信息等,是引擎中的一个辅助的服务
 */
@Service
@Slf4j
public abstract class ActivitiServiceImpl implements AcitivitiService {

    private static final String PROCESS_KEY = "demo1";
    private static final String NEXT_ASSIGNEE = "dsr";

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private IdentityService identityService;

    @Resource
    private TaskService taskService;

    @Resource
    private HistoryService historyService;

    @Resource
    private RepositoryService repositoryService;

    @Override
    public Boolean startActiviti(Activiti act, String username) {
        log.info("========流程开始========");
        /*认证用户的作用是设置流程发起人:在流程开始之前设置,会自动在表ACT_HI_PROCINST 中的START_USER_ID_中设置用户ID
    用来设置启动流程的人员ID,引擎会自动把用户ID保存到activiti:initiator中*/
        try{
            identityService.setAuthenticatedUserId(username);
            //开始
            ProcessInstance pro = runtimeService.startProcessInstanceByKey(PROCESS_KEY);
            String id = pro.getId();

            Task currentTask = taskService.createTaskQuery().processInstanceId(pro.getId()).singleResult();
            String taskId = currentTask.getId();

            // 申明任务人
            //taskService.claim(currentTask.getId(), userName);
            taskService.setAssignee(taskId,username);
            Map<String,Object> vars = new HashMap<>(4);
            vars.put("applyUser", username);
            vars.put("days", act.getDays());
            vars.put("reason", act.getReason());
            //在此方法中,Vaction 是申请时的具体信息,在完成“申请报销”任务时,可以将这些信息设置成参数。
            taskService.complete(currentTask.getId(),vars);

            Task task = taskService.createTaskQuery().processInstanceId(id).singleResult();
            String taskNext = task.getId();
            taskService.setAssignee(taskNext,NEXT_ASSIGNEE);

        } catch (Exception e)
        {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public List<String> myActiviti(String username) {
        List<ProcessInstance> instanceList = runtimeService.createProcessInstanceQuery().startedBy(username).list();
        List<String> activitiList = new ArrayList<>();
        for(ProcessInstance instance : instanceList){
            Activiti activiti =getActiviti(instance);
            activitiList.add(String.valueOf(activiti));
        }
        return activitiList;
    }

    private Activiti getActiviti(ProcessInstance instance){
        Integer days = runtimeService.getVariable(instance.getId(), "days", Integer.class);
        String reason = runtimeService.getVariable(instance.getId(), "reason", String.class);
        Activiti activiti = new Activiti();
        activiti.setApplyUser(instance.getStartUserId());
        activiti.setDays(days);
        activiti.setReason(reason);
        Date startTime = (Date) instance.getStartTime(); // activiti 6 才有
        activiti.setApplyTime(startTime);
        activiti.setApplyStatus(instance.isEnded() ? "申请结束" : "等待审批");
        return activiti;

    };

    @Override
    public List<ActivitiTask> myApproval(String name) {
        name = "dsr";
        List<Task> taskList = taskService.createTaskQuery().taskAssignee(name).orderByTaskCreateTime().desc().list();
        List<ActivitiTask> activitiTaskList = new ArrayList<>();
        for(Task task : taskList){
            ActivitiTask activitiTask = new ActivitiTask();
            activitiTask.setId(task.getId());
            activitiTask.setName(task.getName());
            activitiTask.setStartTime((Date) task.getCreateTime());
            String instanceId = task.getProcessInstanceId();
            ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
            Activiti activiti = getActiviti(instance);
            activitiTask.setActiviti(activiti);
            activitiTaskList.add(activitiTask);
        }
        return activitiTaskList;
    }

    @Override
    public Boolean passApproval(String name, ActivitiTask task) {
        name = "dsr";
        String taskId = task.getId();
        String result = task.getActiviti();
        Map<String, Object> vars = new HashMap<>();
        vars.put("result", result);
        vars.put("auditor", name);
        //Date time = new Date();
        vars.put("auditTime",new java.util.Date());
        //taskService.claim(taskId, userName);
        taskService.setAssignee(taskId, name);
        taskService.complete(taskId, vars);
        return true;
    }

    @Override
    public List<Activiti> myActivitiRecord(String name) {
        List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery()
                .processDefinitionKey(PROCESS_KEY).startedBy(name).finished().orderByProcessInstanceEndTime().desc().list();
        List<Activiti> activitiList = new ArrayList<>();
        for(HistoricProcessInstance historic : historicProcessInstances){
            Activiti activiti = new Activiti();
            activiti.setApplyUser(historic.getStartUserId());
            activiti.setApplyTime((Date) historic.getStartTime());
            activiti.setApplyStatus("申请结束");
            List<HistoricVariableInstance> varInstanceList = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(historic.getId()).list();
            ActivitiUtil.setVars(activiti, varInstanceList);
            activitiList.add(activiti);
        }
        return activitiList;
    }

    @Override
    public List<Activiti> myApprovalRecord(String name) {
        name = "dsr";
        List<HistoricProcessInstance> hisProInstance = historyService.createHistoricProcessInstanceQuery()
                .processDefinitionKey(PROCESS_KEY).involvedUser(name).finished()
                .orderByProcessInstanceEndTime().desc().list();

        List<String> auditTaskNameList = new ArrayList<>();
        auditTaskNameList.add("经理审批");
        auditTaskNameList.add("老板审批");
        List<Activiti> activitiList = new ArrayList<>();
        for (HistoricProcessInstance hisInstance : hisProInstance) {

            Activiti activiti = new Activiti();
            activiti.setApplyUser(hisInstance.getStartUserId());
            activiti.setApplyStatus("申请结束");
            activiti.setApplyTime((Date) hisInstance.getStartTime());
            List<HistoricVariableInstance> varInstanceList = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(hisInstance.getId()).list();
            ActivitiUtil.setVars(activiti, varInstanceList);
            activitiList.add(activiti);
        }
        return activitiList;
    }
}

最后则需要创建对应controler类和html文件。

package com.dsr.controller;

import com.dsr.dao.Activiti;
import com.dsr.dao.ActivitiTask;
import com.dsr.service.AcitivitiService;

import org.activiti.engine.identity.User;
import org.activiti.engine.repository.Model;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;
import java.util.List;

@Controller
@RequestMapping("/activiti")
public class ActivitiController {

    @Autowired
    private AcitivitiService acitivitiService;

    @RequestMapping(value = "/allRecord", method = RequestMethod.GET)
    public String allRecord(HttpSession session, Model model){
        //myActiviti();
        List<Activiti> list = acitivitiService.myActiviti();
        model.add("list",list);
        //myApproval();
        List<ActivitiTask> list3 = acitivitiService.myApproval(session);
        model.addAttribute("list3",list3);
        //myActivitiRecord();
        List<Activiti> list2 = acitivitiService.myActivitiRecord(session);
        model.addAttribute("list2",list2);
        //myApprovalRecord();
        List<Activiti> list4 = acitivitiService.myActivitiRecord(session);
        model.addAttribute("list4",list4);
        return "activitiList";
    }

    @RequestMapping(value = "/createActiviti", method = RequestMethod.POST)
    @ResponseBody
    public Object createActiviti(Activiti vac,HttpSession session){
        ResponseMsg<Object> msg = new ResponseMsg<Object>();
        SecurityProperties.User user=(SecurityProperties.User)session.getAttribute("user");
        String userName = user.getUsername();
        activitiService.startActiviti(vac, userName);
        msg.setCode(0);
        return msg;
    }
    //我正在申请的假
    @RequestMapping(value = "/myActiviti", method = RequestMethod.GET)
    public List<Activiti> myActiviti(HttpSession session) {
        User user=(User)session.getAttribute("user");
        String userName = user.getUsername();
        List<Activiti> list = acitivitiService.myActiviti(userName);
        return list;
    }
    //待我审核的请假
    @RequestMapping(value = "/myApproval", method = RequestMethod.GET)
    public List<ActivitiTask> myApproval(HttpSession session) {
        User user=(User)session.getAttribute("user");
        //String userName = user.getUsername();
        String userName = "huangxu2";
        List<ActivitiTask> list3 = acitivitiService.myApproval(userName);
        return list3;
    }
    @RequestMapping(value = "/passApproval", method = RequestMethod.POST)
    @ResponseBody
    public Object passApproval(String id,String result,HttpSession session) {
        ResponseMsg<Object> msg = new ResponseMsg<Object>();
        User user=(User)session.getAttribute("user");
        ActivitiTask activitiTask = new ActivitiTask();
        Activiti activiti = new Activiti();
        activitiTask.setId(id);
        activiti.setResult(result);
        activitiTask.setActiviti(activiti);
        String userName = user.getLastName();
        acitivitiService.passApproval(userName, activitiTask);
        msg.setCode(0);
        return msg;
    }
    //我申请过的假
    @RequestMapping(value = "/myActivitiRecord", method = RequestMethod.GET)
    public List<Activiti> myActivitiRecord(HttpSession session) {
        User user=(User)session.getAttribute("user");
        String userName = user.getLastName();
        List<Activiti> list2 = acitivitiService.myActivitiRecord(userName);
        return list2;
    }
    //我的审核记录
    @RequestMapping(value = "/myApprovalRecord", method = RequestMethod.GET)
    public List<Activiti> myApprovalRecord(HttpSession session) {
        User user=(User)session.getAttribute("user");
        String userName = user.getFirstName();
        List<Activiti> list4 = acitivitiService.myApprovalRecord(userName);
        return list4;
    }


}

若之前在springboot中未能加在web模块,可以在idea中配置:
在这里插入图片描述
点击最后一个选择Modules->Web->
在这里插入图片描述
添加后可以看到:
在这里插入图片描述
在webapp中添加html文件:

<!DOCTYPE html>
<html lang="UTF-8">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div ng-controller="myAudit">
    <h2 ng-init="myAudit()">待我审核</h2>
    <table border="0">
        <tr>
            <td>任务名称</td>
            <td>任务时间</td>
            <td>申请人</td>
            <td>申请时间</td>
            <td>天数</td>
            <td>事由</td>
            <td>操作</td>
        </tr>
        <tr ng-repeat="vacTask in vacTaskList">
            <td>{{vacTask.name}}</td>
            <td>{{vacTask.startTime | date:'yyyy-MM-dd HH:mm:ss'}}</td>
            <td>{{vacTask.vac.applyUser}}</td>
            <td>{{vacTask.vac.applyTime | date:'yyyy-MM-dd HH:mm:ss'}}</td>
            <td>{{vacTask.vac.days}}</td>
            <td>{{vacTask.vac.reason}}</td>
            <td>
                <button type="button" ng-click="passAudit(vacTask.id, 1)">审核通过</button>
                <button type="button" ng-click="passAudit(vacTask.id, 0)">审核拒绝</button>
            </td>
        </tr>
    </table>


</div>

app.controller("myAudit", function ($scope, $http, $window) {
    $scope.vacTaskList = [];

    $scope.myAudit = function () {
        $http.get(
            "/myAudit"
        ).then(function (response) {
            $scope.vacTaskList = response.data;
        })
    };

    $scope.passAudit = function (taskId, result) {
        $http.post(
            "/passAudit",
            {
                "id": taskId,
                "vac": {
                    "result": result >= 1 ? "审核通过" : "审核拒绝"
                }
            }
        ).then(function (response) {
            if (response.data === true) {
                alert("操作成功!");
                $window.location.reload();
            } else {
                alert("操作失败!");
            }
        })
    }
});

</body>
</html>


由于目前controller层和html文件还存在问题,controller层采用了shiro,本人正在调试,后续会更新正确的controller层和html文件。 shiro依赖配置:
 <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.4.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.4.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!-- 配置 fork 进行热部署支持  -->
                <configuration>
                    <fork>true</fork>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值