Dict.CN 在线词典, 英语学习, 在线翻译 ------------- MyGitee 朱秋贵内科诊所 My腾云code

sb+activiti7实例<二>20230424

一、版本问题

 Activiti的Tijs Rademakers团队去开发Flowable框架。

Activiti7是 Salaboy团队开发的,内核使用的还是Activiti6,扩展了云化。Activiti5、Activiti6代码目前由 Salaboy团队代为维护,目前官宣已经暂停维护

 

 Activiti:Activiti在目前来看有点不思进取,核心功能和内核的优化并没有太大进步,着力点全在商业版和云上面,核心只支持BPMN2协议,跟6版本没有什么区别。如果你是一个老的Activiti使用者,并且只是用BPMN2协议,可以选用Activiti(非Cloud版本)。

Flowable:Flowable不管是功能层面还是在代码层面来讲,都是这3个中最重的,当初跟Activiti分道扬镳的原因也是因为理念不一样,Flowable更注重其功能性、扩展性和性能。在上面表格中,历史异步归档和异步任务全局锁都是对性能的极大优化,特别是异步任务这一项,当年在使用Activiti的使用是一个极大的困扰,因为异步任务的吞吐反而会随着实例数的增加而加速恶化。Flowable比较臃肿,它支持了太多的东西,以致于如果想做POC或者Demo,环境搭建这一步都够呛。但是如果你本身就想做一个扩展性强的,性能高的工作流平台(SaaS\PaaS),Flowable是不二的选择。

Camunda:Camunda是这3个里面比较轻量的一个,但是它并没有去掉PVM这个性能较差的流程推动引擎,所以如果你对性能要求很高的话,PVM肯定是不能满足的(Activiti已经在6.X版本的时候放弃了PVM,Flowable亦是如此)。但是Camunda有一个好东西就是它的编辑器,它是基于http://bpmn.io的bpmn.js,cmmn.js,dmn.js来开发的,并且开源了自己的组件库,所以,如果你想做一个轻巧的、灵活的、定制性强的编辑器,工作流是嵌入式的,那么Camunda是一个好选择。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

二、sb+activiti+jdk8实例

 1、流程

                                     请假申请流程

 

 

                                      出差申请流程

 

 

 

 

2、创建库activiti

 Security 所采取的权限访问控制方案:

RABC -基于角色的权限访问控制(Role-Based Access Control),导入 5 张表

 

/*Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50733
 Source Host           : localhost:3306
 Source Schema         : activiti_spring

 Target Server Type    : MySQL
 Target Server Version : 50733
 File Encoding         : 65001

 Date: 18/07/2022 15:55:30
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for permission
-- ----------------------------
DROP TABLE IF EXISTS `permission`;
CREATE TABLE `permission` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `url` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `description` varchar(255) DEFAULT NULL,
  `pid` bigint(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of permission
-- ----------------------------
BEGIN;
INSERT INTO `permission` VALUES (1, '/user/common', 'common', NULL, 0);
INSERT INTO `permission` VALUES (2, '/user/admin', 'admin', NULL, 0);
INSERT INTO `permission` VALUES (3, '/process/*', 'activiti', NULL, 0);
COMMIT;

-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of role
-- ----------------------------
BEGIN;
INSERT INTO `role` VALUES (1, 'USER');
INSERT INTO `role` VALUES (2, 'ADMIN');
INSERT INTO `role` VALUES (3, 'ACTIVITI_USER');
COMMIT;

-- ----------------------------
-- Table structure for role_permission
-- ----------------------------
DROP TABLE IF EXISTS `role_permission`;
CREATE TABLE `role_permission` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_id` bigint(11) NOT NULL,
  `permission_id` bigint(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of role_permission
-- ----------------------------
BEGIN;
INSERT INTO `role_permission` VALUES (1, 1, 1);
INSERT INTO `role_permission` VALUES (2, 2, 1);
INSERT INTO `role_permission` VALUES (3, 2, 2);
INSERT INTO `role_permission` VALUES (4, 3, 3);
COMMIT;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES (1, 'user', '$2a$10$4zd/aj2BNJhuM5PIs5BupO8tiN2yikzP7JMzNaq1fXhcXUefWCOF2');
INSERT INTO `user` VALUES (2, 'admin', '$2a$10$4zd/aj2BNJhuM5PIs5BupO8tiN2yikzP7JMzNaq1fXhcXUefWCOF2');
INSERT INTO `user` VALUES (3, 'Jack', '$2a$10$4zd/aj2BNJhuM5PIs5BupO8tiN2yikzP7JMzNaq1fXhcXUefWCOF2');
INSERT INTO `user` VALUES (4, 'Marry', '$2a$10$4zd/aj2BNJhuM5PIs5BupO8tiN2yikzP7JMzNaq1fXhcXUefWCOF2');
COMMIT;

-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(11) NOT NULL,
  `role_id` bigint(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_role
-- ----------------------------
BEGIN;
INSERT INTO `user_role` VALUES (1, 1, 1);
INSERT INTO `user_role` VALUES (3, 2, 2);
INSERT INTO `user_role` VALUES (4, 2, 3);
INSERT INTO `user_role` VALUES (5, 3, 3);
INSERT INTO `user_role` VALUES (6, 4, 3);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

 

 

 

 

3、 实例项目activity2069

  jdk8

  1)、pom.xml
  <properties>
    <java.version>1.8</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.3.0</version>
    </dependency>
    <dependency><!--mysql-->
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
      <version>8.0.29</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-engine</artifactId>
      <version>7.1.0.M6</version>
    </dependency>
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-spring</artifactId>
      <version>7.1.0.M6</version>
    </dependency>
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-bpmn-model</artifactId>
      <version>7.1.0.M6</version>
     </dependency>

      <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-bpmn-converter</artifactId>
        <version>7.1.0.M6</version>
      </dependency>

      <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-json-converter</artifactId>
        <version>7.1.0.M6</version>
      </dependency>

      <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-bpmn-layout</artifactId>
        <version>7.1.0.M6</version>
      </dependency>

      <dependency>
        <groupId>org.activiti.cloud</groupId>
        <artifactId>activiti-cloud-services-api</artifactId>
        <version>7.0.0.Beta1</version>
      </dependency>
      <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter</artifactId>
        <version>7.1.0.M6</version>
      </dependency>
      <!--引入spring-boot-starter-security 依赖 -->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
      </dependency>
    </dependencies>

 

  2)、application.properties


    server.port=2069
    # 数据源名称
    spring.datasource.name=test
    # 数据库连接地址
    spring.datasource.url=jdbc:mysql://localhost:3306/activiti?characterEncoding=UTF-8&serverTimezone=UTC&nullCatalogMeansCurrent=true
    # 数据库用户名&密码:
    spring.datasource.username=root
    spring.datasource.password=root
    # 数据库驱动:
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver

    #spring.activiti.check-process-definitions=false


    #启用项目检测表,不存则创建
    spring.activiti.database-schema-update=true
    #启用历史表
    spring.activiti.db-history-used=true
    #历史记录级别
    spring.activiti.history-level=full
    #关闭springAutoDelployment
    spring.activiti.database-schema=never-fail
    #spring.thymeleaf.prefix=classpath:/view/


  3)、config//全部放开-----免登录


    import com.sc.activity2069.entity.Permission;
    import com.sc.activity2069.reposity.PermissionMapper;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
    import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.SecurityFilterChain;
    import javax.annotation.Resource;
    import java.util.List;

    @Configuration
    @Slf4j
    public class SecurityConfig {

      @Resource
      private PermissionMapper permissionMapper;

      @Bean
      public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
        authorizeRequests = http.csrf().disable().authorizeRequests();
          // 方式二:配置来源于数据库
        // 1.查询到所有的权限
          List<Permission> allPermission = permissionMapper.findAllPermission();
        // 2.分别添加权限规则
        allPermission.forEach((p -> {
          authorizeRequests.antMatchers(p.getUrl()).hasAnyAuthority(p.getName()) ;
        }));

        authorizeRequests.antMatchers("/**").fullyAuthenticated()
          .anyRequest().authenticated().and().formLogin();
        return http.build();
      }

    @Bean
    WebSecurityCustomizer webSecurityCustomizer() {
    return web -> {
      web.ignoring().antMatchers("/css/**");
      web.ignoring().antMatchers("/js/**");
      web.ignoring().antMatchers("/img/**");
      web.ignoring().antMatchers("/plugins/**");
      web.ignoring().antMatchers("/login.html");
      web.ignoring().antMatchers("/**");//全部放开-----免登录
      };
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
    }

  }

  4)、enity

  import lombok.Data;
  @Data
  public class Permission {
    private Integer id;

    private String url;

    private String name;

    private String description;

  }


  import lombok.Data;
  import lombok.NoArgsConstructor;
  @Data
  @NoArgsConstructor
  public class ResponseResult {

    private Integer status;

    private String message;

    private Object data;

    public ResponseResult(Integer status,String message,Object data){
      this(status,message);
      this.data = data;
    }

    public static ResponseResult getSuccessResult(Object data){
      ResponseResult result = new ResponseResult(200, "成功!");
      result.data = data;
      return result;

    }

    public ResponseResult(Integer status,String message){
      this.status = status;
      this.message = message;
    }
  }


  import lombok.Data;

  @Data
  public class Role {
    private Integer id;
    private String name;
  }


  import lombok.Data;
  import org.springframework.security.core.GrantedAuthority;
  import org.springframework.security.core.userdetails.UserDetails;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.List;

  @Data
  public class User implements UserDetails {
    private Integer id;
    private String username;
    private String password;
    private String role;

    // 用户所有权限
    private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

    public Collection<? extends GrantedAuthority> getAuthorities() {

      return authorities;
    }

    @Override
    public boolean isAccountNonExpired() {
      return true;
    }

    @Override
    public boolean isAccountNonLocked() {
      return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
      return true;
    }

    @Override
    public boolean isEnabled() {
      return true;
    }
  }

 

  5)、reposity
  import com.sc.activity2069.entity.Permission;
  import org.apache.ibatis.annotations.Select;
  import java.util.List;

  public interface PermissionMapper {

    /**
    * 查询用户的权限根据用户查询权限
    *
    * @return
    */
    @Select("select * from permission")
    List<Permission> findAllPermission();
  }


  import com.sc.activity2069.entity.Permission;
  import com.sc.activity2069.entity.User;
  import org.apache.ibatis.annotations.Param;
  import org.apache.ibatis.annotations.Select;
  import java.util.List;

  public interface UserMapper {

    /**
    * 根据用户名称查询
    *
    * @param userName
    * @return
    */
    @Select(" select * from user where username = #{userName}")
    User findByUsername(@Param("userName") String userName);

    /**
    * 查询用户的权限根据用户查询权限
    *
    * @param userName
    * @return
    */
    @Select(" SELECT d.*\n" +
    "from user a,user_role b,role_permission c,permission d\n" +
    "WHERE \n" +
    "a.id = b.user_id\n" +
    "and b.role_id = c.role_id\n" +
    "and c.permission_id = d.id\n" +
    "and \n" +
    "a.username= #{userName};")
    List<Permission> findPermissionByUsername(@Param("userName") String userName);
  }

 


  6)、controller

  import com.sc.activity2069.entity.ResponseResult;
  import lombok.extern.slf4j.Slf4j;
  import org.activiti.engine.RepositoryService;
  import org.activiti.engine.RuntimeService;
  import org.activiti.engine.TaskService;
  import org.activiti.engine.repository.Deployment;
  import org.activiti.engine.repository.ProcessDefinition;
  import org.activiti.engine.repository.ProcessDefinitionQuery;
  import org.activiti.engine.runtime.ProcessInstance;
  import org.activiti.engine.task.Task;
  import org.springframework.web.bind.annotation.*;
  import javax.annotation.Resource;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.stream.Collectors;

  @Slf4j
  @RestController
  @RequestMapping("/process")
  public class ActivitiController {

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private TaskService taskService;


    /**
    * 部署流程定义
    * @param name
    * @param filePath
    * @return
    */
    @PostMapping("deploy")
    public ResponseResult deployProcess(@RequestParam(name = "name") String name,
      @RequestParam(name= "filePath") String filePath){
      Deployment deploy = repositoryService.createDeployment()
      .addClasspathResource(filePath)
      .deploy();
      log.info("{} 流程定义完成部署",deploy.getName());
      return ResponseResult.getSuccessResult(deploy);
    }

    /**
    * 查询流程
    * @param key
    * @return
    */
    @GetMapping(value = {"/list/{key}","/list"})
    public ResponseResult getProcessList(@PathVariable(name = "key",required = false) String key) {
      ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
      List<ProcessDefinition> definitionList;
      if (key!=null){
        definitionList = definitionQuery
        .processDefinitionKey(key)
        .list();
      }

      definitionList = definitionQuery.list();

      List<String> processList = new ArrayList<>();
      for (ProcessDefinition processDefinition : definitionList) {
        processList.add(processDefinition.getName());
      }
      return ResponseResult.getSuccessResult(processList);
    }

    /**
      * 启动流程定义(由流程定义-》流程实例)
      * @param key
      * @return
    */
    @PostMapping("start/{key}")
    public ResponseResult startProcess(@PathVariable(name = "key") String key){
      Map<String,Object> map = new HashMap<>();
      map.put("assignee0","Jack");
      map.put("assignee1","Marry");
      ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key,map);
      ResponseResult result =ResponseResult.getSuccessResult(processInstance.getProcessDefinitionName());
      log.info("流程实例的内容:{}",processInstance);
      return result;

    }


    /**
      * 查看任务列表
    * @return
    */
    @GetMapping("/task/list")
    public ResponseResult getMyTaskList(){
      /* Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
      //获取当前登录的用户名
      String username = "";
      if (principal instanceof UserDetails) {
        username = ((UserDetails) principal).getUsername();
      }

      if (principal instanceof Principal) {
        username = ((Principal) principal).getName();
      }*/
      //获取任务
      List<Task> tasks = taskService.createTaskQuery()
      .taskAssignee("Jack")
      .list();
      //获取任务名称列表
      List<String> TaskList = tasks.stream()
      .map(Task::getName)
      .collect(Collectors.toList());

      return ResponseResult.getSuccessResult(TaskList);
    }

    /**
    * 完成任务
    * @param key
    * @param assigne
    * @return
    */
    @PostMapping("complete")
    public ResponseResult doTask(@RequestParam(name = "key") String key, @RequestParam(name = "assignee")String assigne){
      List<Task> tasks = taskService.createTaskQuery().processDefinitionKey(key)
      .taskAssignee(assigne)
      .list();
      if (tasks!=null && tasks.size()>0){
        for (Task task : tasks) {
          log.info("任务名称:{}",task.getName());
            taskService.complete(task.getId());
            log.info("{},任务已完成",task.getName());

        }
      }
      return ResponseResult.getSuccessResult(null);

    }

    /**
    * 删除部署
    * @param deploymentId
    * @return
    */
    @PostMapping("delete/{id}")
    public ResponseResult deleteDeployment(@PathVariable(name = "id") String deploymentId){
      /**
      * deleteDeployment() 方法的第二个参数 cascade 设置为 true,表示需要进行级联删除,从而可以删除掉未完成的任务
      */
      repositoryService.deleteDeployment(deploymentId,true);
      return ResponseResult.getSuccessResult(null);
    }
  }

 

 

  import org.springframework.web.bind.annotation.GetMapping;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.RequestParam;
  import org.springframework.web.bind.annotation.RestController;

  @RestController
  @RequestMapping("/user")
  public class UserController {

    @GetMapping("/common")
    public String common() {
      return "hello~ common";
    }

    @GetMapping("/admin")
    public String admin() {
      return "hello~ admin";
    }

    @GetMapping("/test")
    public String test() {
      return "hello~ test";
    }

    @GetMapping("/hello")
    public String hello(@RequestParam("code") String code) {
      return "hello~ 授权码 code 为:" + code;
    }
  }


  7)、Activity2069Application

  import org.mybatis.spring.annotation.MapperScan;
  import org.springframework.boot.SpringApplication;
  import org.springframework.boot.autoconfigure.SpringBootApplication;

  @MapperScan("com.sc.activity2069.reposity")
  //@SpringBootApplication(exclude = {SecurityAutoConfiguration.class,ManagementWebSecurityAutoConfiguration.class})
  @SpringBootApplication
  public class Activity2069Application {

    public static void main(String[] args) {
      SpringApplication.run(Activity2069Application.class, args);
    }
  }


  8)、流程图
    resources/processes/leaveApplication.bpmn20.xml
    resources/processes/myEvection.bpmn20.xml

                https://files.cnblogs.com/files/smallfa/processes.zip?t=1682306923&download=true

 

 

 

4、 实例项目activity2069启动

项目启动之后,会发现,我们所配置的 activiti_spring 数据库中,便增加了 25 张 ACT 开头的表

 

5、流程启动

  1)、查询流程

 

 

 

 

2)、启动 请假申请(leaveApplication)流程

 查旬任务---------------

 

 3)、请假申请审核(leaveApplication)流程

 查旬任务---------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

参考版本问题https://www.cnblogs.com/cjsblog/p/16962719.html

https://juejin.cn/post/7122381449206071327

https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fhelemile%2FSpring-Boot-Notes%2Ftree%2Fmaster%2Factiviti%2Factiviti

posted @ 2023-04-24 11:57  cn2023  阅读(32)  评论(0编辑  收藏  举报