基于Spring Cloud应用activiti流程框架
Published in:2023-08-29 |
Words: 4.2k | Reading time: 23min | reading:

基于Spring Cloud应用activiti流程框架

activiti工作流简介

Activiti 是一个开源架构的工作流引擎,基于bpmn2.0 标准进行流程定义。其前身是JBPM,Activiti 通过嵌入到业务系统开发中进行使用。

引入与使用

  • 1.maven pom.xml文件引入
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <!-- 引入Activiti7 -->
    <dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter</artifactId>
    <version>7.1.0.M4</version>
    <!-- 7.1.0版本排除mybatis 防止冲突 -->
    <exclusions>
    <exclusion>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    <dependency>
    <groupId>org.activiti.dependencies</groupId>
    <artifactId>activiti-dependencies</artifactId>
    <version>7.1.0.M4</version>
    <type>pom</type>
    </dependency>
    <!-- 生成流程图 -->
    <dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-image-generator</artifactId>
    <version>7.1.0.M4</version>
    </dependency>
  • 2.yml配置文件编写
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    server:
    port: 16666

    spring:
    application:
    name: activity
    datasource:
    name: test
    url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/activity?useUnicode=true&characterEncoding=UTF8&useSSL=false
    username: activity
    password: activity
    # 使用druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat
    maxActive: 20
    initialSize: 1
    maxWait: 60000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20
    activiti:
    #关闭activiti自动部署(使用流程设计器部署,不使用具体文件访问方式)
    check-process-definitions: false
    #设置流程引擎启动和关闭时数据库执行的策略
    #false:false为默认值,设置为该值后,Activiti在启动时,会对比数据库表中保存的版本,如果版本不匹配时,将在启动时抛出异常。
    #true:设置为该值后,Activiti会对数据库中所有的表进行更新,如果表不存在,则Activiti会自动创建。
    #create-drop:Activiti启动时,会执行数据库表的创建操作,在Activiti关闭时,执行数据库表的删除操作。
    #drop-create:Activiti启动时,执行数据库表的删除操作在Activiti关闭时,会执行数据库表的创建操作。
    database-schema-update: true
    #保存历史数据级别设置为full最高级别,便于历史数据的追溯
    #none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
    #activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
    #audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
    #full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。
    history-level: full

    management:
    endpoints:
    web:
    base-path: /

    logging:
    level:
    com.acti: DEBUG
  • 3.启动类配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package com.acti;

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

    /**
    * @Desc activity
    * @Author jx111
    * @Date 2019/11/29-16:28
    */
    @SpringBootApplication(exclude = { SecurityAutoConfiguration.class})
    public class ActivityApplication {
    public static void main(String[] args) {
    SpringApplication.run(ActivityApplication.class, args);
    }

    }

    注:@SpringBootApplication(exclude = { SecurityAutoConfiguration.class}) 排除注解,取消登陆限制。
    启动服务后,可在数据库中观察到表名以act_为首的25张表生成。

整合发布

spring cloud整合SpringSecurity

  • 1.添加工具类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    package com.czq.image.util;

    //import com.czq.image.dao.UserRepository.java;
    import com.czq.image.dao.SysUserRepository;
    //import com.czq.image.service.impl.MyUserD??etailsService;
    import com.czq.model.image.entity.SysUserEntity;
    import io.swagger.annotations.AuthorizationScope;
    import lombok.RequiredArgsConstructor;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.AuthorityUtils;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.core.context.SecurityContextImpl;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Component;

    import java.security.Permission;
    import java.util.*;


    @Component
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    public class SecurityUtil {


    private final UserDetailsService userDetailsService;

    // public SecurityUtil() {
    //
    // }

    public void logInAs(String username) {

    UserDetails user = userDetailsService.loadUserByUsername(username);
    if (user == null) {
    throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
    }

    SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
    return user.getAuthorities();
    }

    @Override
    public Object getCredentials() {
    return user.getPassword();
    }

    @Override
    public Object getDetails() {
    return user;
    }

    @Override
    public Object getPrincipal() {
    return user;
    }

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

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {

    }

    @Override
    public String getName() {
    return user.getUsername();
    }
    }));
    org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
    }
    }


  • 2.添加配置类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    package com.czq.image.config;

    //import com.czq.image.service.impl.MyUserDetailsService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.builders.WebSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.provisioning.InMemoryUserDetailsManager;
    import org.springframework.security.web.firewall.HttpFirewall;
    import org.springframework.security.web.firewall.StrictHttpFirewall;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

    import java.util.Arrays;
    import java.util.List;
    import java.util.stream.Collectors;
    @Configuration
    @EnableWebSecurity
    public class DemoApplicationConfiguration extends WebSecurityConfigurerAdapter {

    private final Logger logger = LoggerFactory.getLogger(DemoApplicationConfiguration.class);

    @Override
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(myUserDetailsService());
    }

    @Bean
    public UserDetailsService myUserDetailsService() {

    InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();

    String[][] usersGroupsAndRoles = {
    {"salaboy", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
    {"ryandawsonuk", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
    {"erdemedeiros", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
    {"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
    {"admin", "password", "ROLE_ACTIVITI_ADMIN"},
    };

    for (String[] user : usersGroupsAndRoles) {
    List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
    logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
    inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
    authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
    }


    return inMemoryUserDetailsManager;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http
    //
    .csrf().disable()
    .authorizeRequests()
    .anyRequest().permitAll()
    // .authenticated()
    .and()
    // .cors()

    // .and().
    .httpBasic();
    // .and()
    // .cors(c -> {
    //            CorsConfigurationSource source = request -> {
    //                CorsConfiguration config = new CorsConfiguration();
    //                config.setAllowedOrigins(Arrays.asList("*"));
    //                config.setAllowedMethods(Arrays.asList("*"));
    //                return config;
    //            };
    //            c.configurationSource(source);
    //        });
    }

    @Override
    public void configure(WebSecurity web) throws Exception {

    web.ignoring().antMatchers("/css/**", "/js/**","/resources/**","/templates/**","/lib/**","/file/**","/img/**","/swagger-ui.html");
    }
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("*"));
    configuration.setAllowedMethods(Arrays.asList("PUT", "DELETE", "GET", "POST", "OPTIONS", "HEAD"));
    configuration.setAllowCredentials(true);
    configuration.setExposedHeaders(Arrays.asList( "access-control-allow-headers",
    "access-control-allow-methods",
    "access-control-allow-origin",
    "access-Control-allow-credentials",
    "access-control-max-age",
    "X-Frame-Options"));
    configuration.setAllowedHeaders(Arrays.asList("Content-Type", "X-Requested-With", "accept", "Authorization", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"));
    configuration.setMaxAge(3600L);
    // configuratio
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
    }

    @Bean
    public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowUrlEncodedSlash(true);
    return firewall;
    }

    }

bpnm文件绘制生成

  • 1.demo.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    <?xml version="1.0" encoding="UTF-8"?>
    <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
    <process id="myProcess_1" name="My process" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="one" activiti:candidateGroups="activitiTeam"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="two" activiti:candidateGroups="activitiTeam"></userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="endevent1"></sequenceFlow>
    </process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess_1">
    <bpmndi:BPMNPlane bpmnElement="myProcess_1" id="BPMNPlane_myProcess_1">
    <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
    <omgdc:Bounds height="35.0" width="35.0" x="50.0" y="160.0"></omgdc:Bounds>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
    <omgdc:Bounds height="55.0" width="105.0" x="130.0" y="150.0"></omgdc:Bounds>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
    <omgdc:Bounds height="55.0" width="105.0" x="280.0" y="150.0"></omgdc:Bounds>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
    <omgdc:Bounds height="35.0" width="35.0" x="430.0" y="160.0"></omgdc:Bounds>
    </bpmndi:BPMNShape>
    <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
    <omgdi:waypoint x="85.0" y="177.0"></omgdi:waypoint>
    <omgdi:waypoint x="130.0" y="177.0"></omgdi:waypoint>
    </bpmndi:BPMNEdge>
    <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
    <omgdi:waypoint x="235.0" y="177.0"></omgdi:waypoint>
    <omgdi:waypoint x="280.0" y="177.0"></omgdi:waypoint>
    </bpmndi:BPMNEdge>
    <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
    <omgdi:waypoint x="385.0" y="177.0"></omgdi:waypoint>
    <omgdi:waypoint x="430.0" y="177.0"></omgdi:waypoint>
    </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
    </definitions>

接口定义与使用

  • 1.接口定义

    API文件接口编写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    package com.czq.api.image;


    //import com.czq.common.model.response.Result;
    import com.czq.model.image.entity.Result;
    import com.czq.model.image.request.AddXMLRequest;
    //import com.czq.model.image.response.Result;
    import com.czq.model.user.UserMessage;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.web.multipart.MultipartFile;

    import javax.servlet.http.HttpServletResponse;

    @Api(value = "BPMN XML文件处理接口", description = "BPMN XML处理公共接口")
    public interface BPMNControllerApi {

    @ApiOperation("上传BPMN内容字符串部署")
    public Result postBPMNAndDeployment(AddXMLRequest addXMLRequest);

    @ApiOperation("XML文件上传部署")
    public Result uploadFileAndDeployment(
    MultipartFile processFile,
    String processName);

    @ApiOperation("获取流程资源文件")
    public void getProcessDefineXML(String deploymentId, String resourceName, HttpServletResponse response);

    @ApiOperation("启动流程")
    public Result startProcess(
    String processDefinitionKey,
    String instanceName,
    UserMessage userDetail);

    @ApiOperation("挂起流程")
    public Result suspendInstance(String instanceId);

    @ApiOperation("激活流程")
    public Result resumeInstance(String instanceId);

    @ApiOperation("完成任务")
    public Result completeTask(String taskId);

    @ApiOperation("获取任务")
    public Result getTasks();

    @ApiOperation("activiti流程测试")
    public Result testActiviti();

    }
  • 2.controller中调用service实现功能
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    package com.czq.image.controller;

    import com.czq.api.image.BPMNControllerApi;
    //import com.czq.common.model.response.Result;
    import com.czq.image.service.BPMNService;
    import com.czq.model.image.entity.Result;
    import com.czq.model.image.request.AddXMLRequest;
    //import com.czq.model.image.response.Result;v/
    import com.czq.model.user.UserMessage;
    import org.activiti.api.task.model.Task;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;

    import javax.servlet.http.HttpServletResponse;

    @RestController
    @RequestMapping("/bpmn")
    public class BPMNController implements BPMNControllerApi {

    @Autowired
    BPMNService bpmnService;

    @Override
    @PostMapping("/postBPMNAndDeployment")
    public Result postBPMNAndDeployment(@RequestBody AddXMLRequest addXMLRequest) {
    return bpmnService.postBPMNAndDeployment(addXMLRequest);
    }

    @Override
    @PostMapping("/uploadFileAndDeployment")
    public Result uploadFileAndDeployment(
    @RequestParam("processFile")MultipartFile processFile,
    @RequestParam(value = "processName",required = false) String processName){
    return bpmnService.uploadFileAndDeployment(processFile,processName);
    }

    @Override
    @GetMapping("/getProcessDefineXML")
    public void getProcessDefineXML(String deploymentId, String resourceName, HttpServletResponse response) {
    bpmnService.getProcessDefineXML(deploymentId,resourceName,response);
    }

    @Override
    @PostMapping("/startProcess")
    public Result startProcess(String processDefinitionKey, String instanceName, UserMessage userDetail) {
    return bpmnService.startProcess(processDefinitionKey,instanceName,userDetail);
    }

    @Override
    @PostMapping("/suspendInstance/{instanceId}")
    public Result suspendInstance(@PathVariable String instanceId){
    return bpmnService.suspendInstance(instanceId);
    }

    @Override
    @PostMapping("/resumeInstance/{instanceId}")
    public Result resumeInstance(@PathVariable String instanceId){
    return bpmnService.resumeInstance(instanceId);
    }

    @Override
    @PostMapping("/completeTask/{taskId}")
    public Result completeTask(@PathVariable String taskId){
    return bpmnService.completeTask(taskId);
    }

    @Override
    @GetMapping("/getTasks")
    public Result getTasks() {
    return bpmnService.getTasks();
    }

    @Override
    @GetMapping("/testActiviti")
    public Result testActiviti() {
    return bpmnService.testActiviti();
    }
    }

  • 3.编写Controller调用的服务,服务通过调用activiti框架提供接口完成各项功能
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277

    package com.czq.image.service.impl;

    import com.czq.common.model.response.CommonCode;
    //import com.czq.common.model.response.Result;
    import com.czq.image.service.BPMNService;
    import com.czq.image.util.SecurityUtil;
    import com.czq.model.image.entity.Result;
    import com.czq.model.image.entity.vo.HistoricActivityInstanceVO;
    import com.czq.model.image.entity.vo.TaskVO;
    import com.czq.model.image.entity.vo.VOConverter;
    import com.czq.model.image.request.AddXMLRequest;
    //import com.czq.model.image.response.Result;/
    import com.czq.model.user.UserMessage;
    import org.activiti.api.process.model.ProcessDefinition;
    import org.activiti.api.process.model.ProcessInstance;
    import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
    import org.activiti.api.process.model.payloads.StartProcessPayload;
    import org.activiti.api.process.runtime.ProcessRuntime;
    import org.activiti.api.runtime.shared.query.Page;
    import org.activiti.api.runtime.shared.query.Pageable;
    import org.activiti.api.task.model.Task;
    import org.activiti.api.task.model.builders.TaskPayloadBuilder;
    import org.activiti.api.task.runtime.TaskRuntime;
    import org.activiti.engine.HistoryService;
    import org.activiti.engine.RepositoryService;
    import org.activiti.engine.RuntimeService;
    import org.activiti.engine.history.*;
    import org.activiti.engine.repository.Deployment;
    import org.apache.commons.io.FilenameUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.access.annotation.Secured;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;

    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    import java.util.zip.ZipInputStream;

    @Service
    public class BPMNServiceImpl implements BPMNService {

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    ProcessRuntime processRuntime;

    @Autowired
    TaskRuntime taskRuntime;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    HistoryService historyService;

    private final Logger logger = LoggerFactory.getLogger(BPMNServiceImpl.class);

    // @Autowired
    // private ProcessRuntime processRuntime;

    // @Autowired
    // private TaskRuntime taskRuntime;


    @Override
    public Result postBPMNAndDeployment(AddXMLRequest addXMLRequest) {
    Deployment deploy = repositoryService.createDeployment()
    // .addString 第一次参数的名字如果没有添加.bpmn的话,不会插入到 ACT_RE_DEPLOYMENT 表中
    .addString(addXMLRequest.getProcessName() + ".bpmn", addXMLRequest.getBpmnContent())
    .name(addXMLRequest.getProcessName())
    .deploy();
    return Result.ok(deploy);
    }

    @Override
    public Result uploadFileAndDeployment(MultipartFile processFile,
    String processName) {

    String originalFilename = processFile.getOriginalFilename();
    String extension = FilenameUtils.getExtension(originalFilename);
    if (processName != null) {
    processName = originalFilename;
    }
    try {
    InputStream inputStream = processFile.getInputStream();
    Deployment deployment = null;
    if ("zip".equals(extension)) {
    // 压缩包部署方式
    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).name(processName).deploy();
    } else if ("bpmn".equals(extension)) {
    // bpmn文件部署方式
    deployment = repositoryService.createDeployment().addInputStream(originalFilename, inputStream).name(processName).deploy();
    }
    return Result.ok(deployment);
    } catch (IOException e) {
    e.printStackTrace();
    }
    return Result.error("deployment object null !");
    }

    @Override
    public void getProcessDefineXML(String deploymentId, String resourceName, HttpServletResponse response) {
    try {
    InputStream inputStream = repositoryService.getResourceAsStream(deploymentId, resourceName);
    int count = inputStream.available();
    byte[] bytes = new byte[count];
    response.setContentType("text/xml");
    OutputStream outputStream = response.getOutputStream();
    while (inputStream.read(bytes) != -1) {
    outputStream.write(bytes);
    }
    inputStream.close();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    @Override
    public Result startProcess(String processDefinitionKey, String instanceName, UserMessage userDetail) {
    ProcessInstance processInstance = null;
    try {
    StartProcessPayload startProcessPayload = ProcessPayloadBuilder.start().withProcessDefinitionKey(processDefinitionKey)
    .withBusinessKey("businessKey")
    .withVariable("sponsor", userDetail.getUsername())
    .withName(instanceName).build();
    processInstance = processRuntime.start(startProcessPayload);
    } catch (Exception e) {
    e.printStackTrace();
    // System.out.println(e);
    return Result.error(e.getMessage());
    }
    return Result.ok(processInstance);
    }

    @Override
    public Result suspendInstance(String instanceId) {
    ProcessInstance processInstance = processRuntime.suspend(ProcessPayloadBuilder.suspend().withProcessInstanceId(instanceId).build());
    return Result.ok(processInstance);
    }

    @Override
    public Result resumeInstance(String instanceId) {
    ProcessInstance processInstance = processRuntime
    .resume(ProcessPayloadBuilder.resume().withProcessInstanceId(instanceId).build());
    return Result.ok(processInstance);
    }

    @Override
    public Result completeTask(String taskId) {
    Task task = taskRuntime.task(taskId);
    if (task.getAssignee() == null) {
    // 说明任务需要拾取
    taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(taskId).build());
    }
    taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(taskId).build());
    return Result.ok(task);
    }

    @Override
    public Result getTasks() {
    // SecurityUtil securityUtil = new SecurityUtil();
    // securityUtil.logInAs("jack");
    // Page<Task> taskPage = runtimeService.(Pageable.of(0,100));
    Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0, 100));
    List<Task> tasks = taskPage.getContent();
    List<TaskVO> taskVOS = new ArrayList<>();
    for (Task task : tasks) {
    TaskVO taskVO = (TaskVO) task;
    // TaskVO taskVO = TaskVO.o/ftask;
    ProcessInstance instance = processRuntime.processInstance(task.getProcessInstanceId());
    taskVO.setInstanceName(instance.getName());
    taskVOS.add(taskVO);
    }
    return Result.ok(taskVOS);
    }

    @Override
    public UserDetails createLoginUser(UserMessage user) {
    // Set<String> postCode = sysPostService.selectPostCodeByUserId(user.getId());
    // postCode = postCode.parallelStream().map( s -> "GROUP_" + s).collect(Collectors.toSet());
    // postCode.add("ROLE_ACTIVITI_USER");
    // List<SimpleGrantedAuthority> collect = postCode.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList());
    // return new LoginUser(user, permissionService.getMenuPermission(user), collect);
    return null;
    }

    @Override
    public Result testActiviti() {
    // 首先,取出项目中的最多 10 个流程定义
    Page<ProcessDefinition> processDefinitionPage = processRuntime.processDefinitions(Pageable.of(0, 10));
    if (processDefinitionPage.getTotalItems() > 0) {
    // 然后,对取出的流程进行启动
    for (ProcessDefinition definition : processDefinitionPage.getContent()) {
    logger.info(" 流程定义信息:" + definition);
    processRuntime.start(ProcessPayloadBuilder
    .start()
    .withProcessDefinitionId(definition.getId())
    .build());
    }
    }
    // 完成流程启动后,由于当前项目中只有 other.bpmn 一个流程,且该流程在设计时,已分配给activitiTeam 组
    // 因此我们登录一个 activitiTeam 组成员 , 该账号信息会被设置到 security 上下文中,activiti会对其信息进行读取
    // 获取当前用户任务,最多 10 个
    Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0, 10));
    // 由于目前只有一个流程,两个任务,我们尝试一下完成一个,看看会发生什么变化
    if (taskPage.getTotalItems() > 0) {
    for (Task task : taskPage.getContent()) {
    logger.info(" 任务信息1:" + task);
    // 注意,完成任务前必须先声明
    taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(task.getId()).build());
    // 完成任务
    taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build()
    );
    }
    }
    // 上一轮任务完成,再看一下,现在流程是否走到了 second ?
    taskPage = taskRuntime.tasks(Pageable.of(0, 10));
    if (taskPage.getTotalItems() > 0) {
    for (Task task : taskPage.getContent()) {
    logger.info("任务2: " + task);
    }
    }
    return Result.ok(taskPage);
    }


    /**
    * @param businessKey
    * @desc 查询历史记录
    **/
    public List<HistoricActivityInstanceVO> getProcessHistoryByBusinessKey(String businessKey) {
    ProcessInstance instance = (ProcessInstance) runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
    List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(instance.getId())
    .orderByHistoricActivityInstanceStartTime().asc().list();
    List<HistoricActivityInstanceVO> historicActivityInstanceVOList = new ArrayList<>();
    historicActivityInstanceList.forEach(historicActivityInstance -> historicActivityInstanceVOList.add(VOConverter.getHistoricActivityInstanceVO(historicActivityInstance)));

    String instanceId = "111";
    String taskId = "111";
    // 详情查询+
    HistoricDetailQuery historicDetailQuery = historyService.createHistoricDetailQuery();
    List<HistoricDetail> historicDetails = historicDetailQuery.processInstanceId(instanceId).orderByTime().list();
    for (HistoricDetail hd : historicDetails) {
    System.out.println("流程实例ID:" + hd.getProcessInstanceId());
    System.out.println("活动实例ID:" + hd.getActivityInstanceId());
    System.out.println("执行ID:" + hd.getTaskId());
    System.out.println("记录时间:" + hd.getTime());
    }

    // 任务历史流程查询
    HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
    List<HistoricTaskInstance> taskInstances = historicTaskInstanceQuery.taskId(taskId).list();
    for (HistoricTaskInstance hti : taskInstances) {
    System.out.println("开始时间:" + hti.getStartTime());
    System.out.println("结束时间:" + hti.getEndTime());
    System.out.println("任务拾取时间:" + hti.getClaimTime());
    System.out.println("删除原因:" + hti.getDeleteReason());
    }


    return historicActivityInstanceVOList;
    }


    }

测试

  • 1.demo
    1
    curl -l http://localhost:16666/api/v1.0.1/bpmn/gettask
  • 2.返回值
    1
    2
    3
    4
    5
    6
    {
    "msg": "Success!",
    "code": 200,
    "obj": [],
    "success": true
    }
Prev:
使用python 读写 ini config 文件
Next:
基于Nginx的http_sssl_cert双向认证配置