集成Flowable,并自定义IDM用户及组的管理功能

集成Flowable,并自定义IDM用户及组的管理功能

首先集成flowable-ui,官网目前最新的是6.8.0,这里使用6.7.2,核心依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.boge.flowable</groupId>
    <artifactId>boge-flowable-ui</artifactId>
    <version>6.7.2</version>
    <name>flowableDemo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <project.version>6.7.2</project.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-common</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-admin-logic</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-admin-rest</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-admin-conf</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-admin-frontend</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-idm-logic</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-idm-rest</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-idm-conf</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-idm-frontend</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-modeler-logic</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-modeler-rest</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-modeler-conf</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-modeler-frontend</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-task-logic</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-task-rest</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-task-conf</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-ui-task-frontend</artifactId>
            <version>${project.version}</version>
        </dependency>

        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-ui-admin</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-ui-idm</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-ui-modeler</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-ui-task</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.6.2</version>
        </dependency>
    </dependencies>

    <!-- BUILD -->
    <build>

        <finalName>flowable-ui</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>

        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

核心配置文件如下:

#server.port=8080
server.servlet.context-path=/flowable-ui
spring.jmx.unique-names=true
# This is needed to force use of JDK proxies instead of using CGLIB
spring.aop.proxy-target-class=false
spring.aop.auto=false
spring.application.name=flowable-ui
spring.banner.location=classpath:/org/flowable/spring/boot/flowable-banner.txt
# The default domain for generating ObjectNames must be specified. Otherwise when multiple Spring Boot applications start in the same servlet container
# all would be created with the same name (com.zaxxer.hikari:name=dataSource,type=HikariDataSource) for example
spring.jmx.default-domain=${spring.application.name}
#
# SECURITY
#
spring.security.filter.dispatcher-types=REQUEST,FORWARD,ASYNC

# Expose all actuator endpoints to the web
# They are exposed, but only authenticated users can see /info and /health abd users with access-admin can see the others
management.endpoints.web.exposure.include=*
# Full health details should only be displayed when a user is authorized
management.endpoint.health.show-details=when_authorized
# Only users with role access-admin can access full health details
management.endpoint.health.roles=access-admin
# Spring prefixes the roles with ROLE_. However, Flowable does not have that concept yet, so we need to override that with an empty string
flowable.common.app.role-prefix=

#
# SECURITY OAuth2
# Examples are for Keycloak
#
#spring.security.oauth2.resourceserver.jwt.issuer-uri=<keycloakLocation>/auth/realms/<realmName>
#spring.security.oauth2.client.registration.keycloak.client-id=<clientId>
#spring.security.oauth2.client.registration.keycloak.client-secret=<clientSecret>
#spring.security.oauth2.client.registration.keycloak.client-name=Flowable UI Keycloak
#spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
#spring.security.oauth2.client.provider.keycloak.issuer-uri=<keycloakLocation>/auth/realms/<realmName>
#spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username

#flowable.common.app.security.type=oauth2
#flowable.common.app.security.oauth2.authorities-attribute=groups
#flowable.common.app.security.oauth2.groups-attribute=userGroups
#flowable.common.app.security.oauth2.default-authorities=access-task
#flowable.common.app.security.oauth2.default-groups=flowableUser
#flowable.common.app.security.oauth2.full-name-attribute=name
#flowable.common.app.security.oauth2.email-attribute=email

#
# DATABASE
#

#spring.datasource.driver-class-name=org.h2.Driver
# spring.datasource.url=jdbc:h2:~/flowable-db/engine-db;AUTO_SERVER=TRUE;AUTO_SERVER_PORT=9093;DB_CLOSE_DELAY=-1

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/flowable?serverTimezone=UTC&nullCatalogMeansCurrent=true

#spring.datasource.driver-class-name=org.postgresql.Driver
#spring.datasource.url=jdbc:postgresql://localhost:5432/flowable

#spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
#spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=flowablea

#spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
#spring.datasource.url=jdbc:oracle:thin:@localhost:1521:FLOWABLE

#spring.datasource.driver-class-name=com.ibm.db2.jcc.DB2Driver
#spring.datasource.url=jdbc:db2://localhost:50000/flowable

spring.datasource.username=root
spring.datasource.password=admin@210513

# JNDI CONFIG

# If uncommented, the datasource will be looked up using the configured JNDI name.
# This will have preference over any datasource configuration done below that doesn't use JNDI
#
# Eg for JBoss: java:jboss/datasources/flowableDS
#
#spring.datasource.jndi-name==jdbc/flowableDS

# Set whether the lookup occurs in a J2EE container, i.e. if the prefix "java:comp/env/" needs to be added if the JNDI
# name doesn't already contain it. Default is "true".
#datasource.jndi.resourceRef=true

#
# Connection pool (see https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby)
#

spring.datasource.hikari.poolName=${spring.application.name}
# 10 minutes
spring.datasource.hikari.maxLifetime=600000
# 5 minutes
spring.datasource.hikari.idleTimeout=300000
spring.datasource.hikari.minimumIdle=10
spring.datasource.hikari.maximumPoolSize=50
# test query for H2, MySQL, PostgreSQL and Microsoft SQL Server
#spring.datasource.hikari.connection-test-query=select 1
# test query for Oracle
#spring.datasource.hikari.connection-test-query=SELECT 1 FROM DUAL
# test query for DB2
#spring.datasource.hikari.connection-test-query=SELECT current date FROM sysibm.sysdummy1

#
# Default Task Executor (will be used for @Async)
#
spring.task.execution.pool.core-size=2
spring.task.execution.pool.max-size=50
spring.task.execution.pool.queue-capacity=10000
spring.task.execution.thread-name-prefix=flowable-ui-task-Executor-

#
# Task scheduling
#
spring.task.scheduling.pool.size=5

#
# EMAIL
#

#flowable.mail.server.host=localhost
#flowable.mail.server.port=1025
#flowable.mail.server.username=
#flowable.mail.server.password=

#
# FLOWABLE
#

flowable.process.definition-cache-limit=512
#flowable.dmn.strict-mode=false
flowable.process.async.executor.default-async-job-acquire-wait-time=PT5S
flowable.process.async.executor.default-timer-job-acquire-wait-time=PT5S

flowable.cmmn.async.executor.default-async-job-acquire-wait-time=PT5S
flowable.cmmn.async.executor.default-timer-job-acquire-wait-time=PT5S

# The maximum file upload limit. Set to -1 to set to 'no limit'. Expressed in bytes
spring.servlet.multipart.max-file-size=10MB
# The maximum request size limit. Set to -1 to set to 'no limit'.
# When multiple files can be uploaded this needs to be more than the 'max-file-size'.
spring.servlet.multipart.max-request-size=10MB

# For development purposes, data folder is created inside the sources ./data folder
flowable.content.storage.root-folder=data/
flowable.content.storage.create-root=true

#flowable.common.app.idm-admin.user=admin
#flowable.common.app.idm-admin.password=test

flowable.experimental.debugger.enabled=false

# Rest API in task application

# If false, disables the rest api in the task app
flowable.task.app.rest-enabled=true

# Configures the way user credentials are verified when doing a REST API call:
# 'any-user' : the user needs to exist and the password need to match. Any user is allowed to do the call (this is the pre 6.3.0 behavior)
# 'verify-privilege' : the user needs to exist, the password needs to match and the user needs to have the 'rest-api' privilege
# If nothing set, defaults to 'verify-privilege'
flowable.rest.app.authentication-mode=verify-privilege

# Enable form field validation after form submission on the engine side
flowable.form-field-validation-enabled=false

# Flowable Admin Properties

# Passwords for rest endpoints and master configs are stored encrypted in the database using AES/CBC/PKCS5PADDING
# It needs a 128-bit initialization vector (http://en.wikipedia.org/wiki/Initialization_vector)
# and a 128-bit secret key represented as 16 ascii characters below
#
# Do note that if these properties are changed after passwords have been saved, all existing passwords
# will not be able to be decrypted and the password would need to be reset in the UI.
flowable.admin.app.security.encryption.credentials-i-v-spec=j8kdO2hejA9lKmm6
flowable.admin.app.security.encryption.credentials-secret-spec=9FGl73ngxcOoJvmL
#flowable.admin.app.security.preemptive-basic-authentication=true

# Flowable IDM Properties

#
# LDAP
#
#flowable.idm.ldap.enabled=true
#flowable.idm.ldap.server=ldap://localhost
#flowable.idm.ldap.port=10389
#flowable.idm.ldap.user=uid=admin, ou=system
#flowable.idm.ldap.password=secret
#flowable.idm.ldap.base-dn=o=flowable
#flowable.idm.ldap.query.user-by-id=(&(objectClass=inetOrgPerson)(uid={0}))
#flowable.idm.ldap.query.user-by-full-name-like=(&(objectClass=inetOrgPerson)(|({0}=*{1}*)({2}=*{3}*)))
#flowable.idm.ldap.query.all-users=(objectClass=inetOrgPerson)
#flowable.idm.ldap.query.groups-for-user=(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))
#flowable.idm.ldap.query.all-groups=(objectClass=groupOfUniqueNames)
#flowable.idm.ldap.query.group-by-id=(&(objectClass=groupOfUniqueNames)(uniqueId={0}))
#flowable.idm.ldap.attribute.user-id=uid
#flowable.idm.ldap.attribute.first-name=cn
#flowable.idm.ldap.attribute.last-name=sn
#flowable.idm.ldap.attribute.email=mail
#flowable.idm.ldap.attribute.group-id=cn
#flowable.idm.ldap.attribute.group-name=cn
#flowable.idm.ldap.cache.group-size=10000
#flowable.idm.ldap.cache.group-expiration=180000

#
# Keycloak
#
#flowable.idm.app.keycloak.enabled=true
#flowable.idm.app.keycloak.server=<keycloakLocation>
#flowable.idm.app.keycloak.authentication-realm=master
#flowable.idm.app.keycloak.authentication-user=admin
#flowable.idm.app.keycloak.authentication-password=admin
#flowable.idm.app.keycloak.realm=<realm>

#
# DEFAULT ADMINISTRATOR ACCOUNT
#

#flowable.idm.app.admin.user-id=admin
#flowable.idm.app.admin.password=test
#flowable.idm.app.admin.first-name=Test
#flowable.idm.app.admin.last-name=Administrator
#flowable.idm.app.admin.email=test-admin@example-domain.tld

# Enable and configure JMS
#flowable.task.app.jms-enabled=true
#spring.activemq.broker-url=tcp://localhost:61616

# Enable and configure RabbitMQ
#flowable.task.app.rabbit-enabled=true
#spring.rabbitmq.addresses=localhost:5672
#spring.rabbitmq.username=guest
#spring.rabbitmq.password=guest

# Enable and configure Kafka
#flowable.task.app.kafka-enabled=true
#spring.kafka.bootstrap-servers=localhost:9092

主要还是配置一些数据库连接,其他的都暂时使用默认配置,启动后即可访问flowable页面。
创建配置类:

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.flowable.ui.application;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;
import org.springframework.boot.autoconfigure.AutoConfigurationMetadata;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @author Filip Hrisafov
 */
public class FlowableUiAppEventRegistryCondition extends SpringBootCondition
    implements AutoConfigurationImportFilter, BeanFactoryAware, Condition, EnvironmentAware {

    // This is deliberately in the flowable-ui-task-app since it is only needed to enable / disable the dependency on the out of the box app
    // if the Task UI Spring Boot Starter is used then people need to add the appropriate Kafka, JMS or RabbitMQ for the event registry

    protected BeanFactory beanFactory;

    protected Environment environment;

    @Override
    public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
        ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
        Map<String, ConditionOutcome> conditions = getConditionOutcomes();

        ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, conditions);
        boolean[] match = new boolean[outcomes.length];
        for (int i = 0; i < outcomes.length; i++) {
            match[i] = (outcomes[i] == null || outcomes[i].isMatch());
            if (!match[i] && outcomes[i] != null) {
                logOutcome(autoConfigurationClasses[i], outcomes[i]);
                if (report != null) {
                    report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
                }
            }
        }
        return match;
    }

    protected Map<String, ConditionOutcome> getConditionOutcomes() {
        boolean jmsEnabled = environment.getProperty("flowable.task.app.jms-enabled", Boolean.class, false);
        boolean kafkaEnabled = environment.getProperty("flowable.task.app.kafka-enabled", Boolean.class, false);
        boolean rabbitEnabled = environment.getProperty("flowable.task.app.rabbit-enabled", Boolean.class, false);
        Map<String, ConditionOutcome> conditions = new HashMap<>();

        if (!jmsEnabled) {
            conditions.put("org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration",
                ConditionOutcome.noMatch("Property flowable.task.app.jms-enabled was not set to true")
            );
        }

        if (!kafkaEnabled) {
            conditions.put("org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration",
                ConditionOutcome.noMatch("Property flowable.task.app.kafka-enabled was not set to true")
            );
        }

        if (!rabbitEnabled) {
            conditions.put("org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration",
                ConditionOutcome.noMatch("Property flowable.task.app.rabbit-enabled was not set to true")
            );
        }
        return conditions;
    }

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return ConditionOutcome.noMatch(ConditionMessage.empty());
    }

    protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, Map<String, ConditionOutcome> conditionOutcomes) {
        ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];

        for (int i = 0; i < autoConfigurationClasses.length; i++) {
            outcomes[i] = conditionOutcomes.get(autoConfigurationClasses[i]);
        }

        return outcomes;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.flowable.ui.application;

import com.boge.flowable.idm.MyIdmIdentityServiceImpl;
import org.flowable.idm.engine.IdmEngineConfiguration;
import org.flowable.idm.spring.SpringIdmEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author Filip Hrisafov
 */
@Configuration
public class FlowableUiApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(FlowableUiApplication.class);
    }
}

启动器扫描:

@ComponentScan(basePackages = {"org.flowable.ui.application"})
@SpringBootApplication
public class BogeFlowableUiApplication {

    public static void main(String[] args) {
        SpringApplication.run(BogeFlowableUiApplication.class, args);
        IdmEngineConfiguration idmEngineConfiguration = new IdmEngineConfiguration();
    }

}

启动即可访问ui界面:
http://localhost:8082/flowable-ui/#/

Flowable-IDM功能

提供用户管理功能:可以添加用户、编辑用户、删除用户和密码修改功能
提供用户分组功能:提供用户组的创建、用户组的删除、添加删除用户到组功能,方便统一管理用户权限,是一个简化版的角色处理
提供权限管理功能:权限简单分为idm/admin/modeler/workflow/rest的访问权限控制,通过配置用户和组来管理用户的访问权限。
提供单点登录管理:modeler、admin等用户需要登录到idm完成用户的验证

需求

在实际项目使用flowable时,一般公司都有自己的人员权限系统,并不会直接使用flowable的idm模块,本节内容记录,如何让flowable调用自己的权限系统

人员权限认证服务官方的默认实现类:

public class IdmIdentityServiceImpl extends CommonEngineServiceImpl<IdmEngineConfiguration> implements IdmIdentityService

官方默认的实现类是UserQueryImpl,和GroupQueryImpl

为了实现简单,只需要修改自定义业务用的方法,所以我们可以直接继承这两个类就可以。

代码改造

继承 UserQueryImpl 和 GroupQueryImpl。

GroupQueryImpl:用来管理组信息包括:add、query、update等;
UserQueryImpl:用来管理用户信息包括:add、query、update等
示例代码:

MyGroup

package com.boge.flowable.idm;

import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.idm.api.Group;
import org.flowable.idm.engine.impl.GroupQueryImpl;
import org.flowable.idm.engine.impl.persistence.entity.GroupEntityImpl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class MyGroup extends GroupQueryImpl {

    @Override
    public long executeCount(CommandContext commandContext) {
        return executeList(commandContext).size();
    }

    @Override
    public List<Group> executeList(CommandContext commandContext) {
        System.out.println("开始获取组信息***********************************");
        if (getUserId() != null) {
            return findGroupsByUser(getUserId());
        } else if (getId() != null) {
            List<Group> groups = new ArrayList<>();
            groups.add(findGroupById(getId()));
            return groups;
        } else if (getIds() != null) {
            return findGroupsByIds(getIds());
        }
        return null;
    }

    private static Map<Long, List<String>> SHIP = new HashMap<>();
    static {
        SHIP.put(8L, Arrays.asList("aaa"));
        SHIP.put(9L, Arrays.asList("aaa"));
        SHIP.put(10L, Arrays.asList("bbb"));
        SHIP.put(11L, Arrays.asList("bbb","ccc"));
        SHIP.put(12L, Arrays.asList("bbb"));
        SHIP.put(13L, Arrays.asList("ddd"));
        SHIP.put(14L, Arrays.asList("eee"));
    }

    private static Map<String, String> GROUPS = new HashMap<>();
    static {
        GROUPS.put("aaa", "权限1");
        GROUPS.put("bbb", "权限2");
        GROUPS.put("ccc", "权限3");
        GROUPS.put("ddd", "权限4");
        GROUPS.put("eee", "权限5");
    }

    private List<Group> findGroupsByUser(String userId) {
        List<String> strings = SHIP.get(Long.valueOf(userId));
        return strings.stream().map(g -> {
            Group group = new GroupEntityImpl();
            group.setId(g);
            group.setName(GROUPS.get(g));
            return group;
        }).collect(Collectors.toList());
    }

    private Group findGroupById(String id) {
        if(!GROUPS.containsKey(id)) {
            return null;
        }
        Group group = new GroupEntityImpl();
        group.setId(id);
        group.setName(GROUPS.get(id));
        return group;
    }

    private List<Group> findGroupsByIds(List<String> ids) {
        return ids.stream().map(this::findGroupById).collect(Collectors.toList());
    }
}

MyUser:

package com.boge.flowable.idm;

import org.apache.commons.lang3.ObjectUtils;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.idm.api.User;
import org.flowable.idm.engine.impl.UserQueryImpl;
import org.flowable.idm.engine.impl.persistence.entity.UserEntity;
import org.flowable.idm.engine.impl.persistence.entity.UserEntityImpl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class MyUser extends UserQueryImpl {

    @Override
    public long executeCount(CommandContext commandContext) {
        return executeList(commandContext).size();
    }

    @Override
    public List<User> executeList(CommandContext commandContext) {
        System.out.println("开始获取人员信息***********************************");
        if (getId() != null) {
            List<User> users = new ArrayList<>();
            users.add(findById(getId()));
            return users;
        } else if (getIds() != null) {
            return findByIds(getIds());
        } else if (getGroupId() != null) {
            return findByGroup(getGroupId());
        } else if (getGroupIds() != null) {
            return findByGroups(getGroupIds());
        }
        return null;
    }

    private static Map<String, List<Long>> SHIP = new HashMap<>();

    static {
        SHIP.put("aaa", Arrays.asList(9L));
        SHIP.put("bbb", Arrays.asList(10L, 11L, 12L));
        SHIP.put("ccc", Arrays.asList(11L));
        SHIP.put("ddd", Arrays.asList(13L));
        SHIP.put("eee", Arrays.asList(14L));
    }

//    public QtUser getQtUser(String userId) {
//        if(USERS.containsKey(Long.valueOf(userId))) {
//            QtUser user = new QtUser();
//            user.setId(Long.valueOf(userId));
//            user.setName(USERS.get(Long.valueOf(userId)));
//            user.setTenantId(1L);
//            return user;
//        }
//        return null;
//    }

    private static Map<Long, String> USERS = new HashMap<>();

    static {
        USERS.put(8L, "ie");
        USERS.put(9L, "he");
        USERS.put(10L, "tom");
        USERS.put(11L, "cat");
        USERS.put(12L, "java");
        USERS.put(13L, "python");
        USERS.put(111L, "li");
        USERS.put(222L, "qa");
    }

    private User findById(final String userId) {
        if (!USERS.containsKey(Long.valueOf(userId))) {
            return null;
        }
        UserEntity userEntity = new UserEntityImpl();
        userEntity.setId(userId);
        userEntity.setDisplayName(USERS.get(Long.valueOf(userId)));
        userEntity.setTenantId("1");
        return userEntity;
    }

    private List<User> findByIds(List<String> userIds) {
        return userIds.stream().map(this::findById).collect(Collectors.toList());
    }

    private List<User> findByGroup(final String groupId) {
        List<Long> userIds = SHIP.get(groupId);
        if (ObjectUtils.isNotEmpty(userIds)) {
            return findByIds(userIds.stream().map(String::valueOf).collect(Collectors.toList()));
        }
        return null;
    }

    private List<User> findByGroups(List<String> groupIds) {
        List<User> users = new ArrayList<>();
        groupIds.forEach(g -> users.addAll(findByGroup(g)));
        return users;
    }
}

重写IdmIdentityServiceImpl

IdmIdentityServiceImpl为构建查询的默认实现类,需要重写一个类,使idm调用自定义的MyUser和MyGroup

package com.boge.flowable.idm;

import org.flowable.idm.api.GroupQuery;
import org.flowable.idm.api.UserQuery;
import org.flowable.idm.engine.IdmEngineConfiguration;
import org.flowable.idm.engine.impl.IdmIdentityServiceImpl;

public class MyIdmIdentityServiceImpl extends IdmIdentityServiceImpl {

    public MyIdmIdentityServiceImpl(IdmEngineConfiguration idmEngineConfiguration) {
        super(idmEngineConfiguration);
    }

    @Override
    public UserQuery createUserQuery() {
        return new MyUser();
    }

    @Override
    public GroupQuery createGroupQuery() {
        return new MyGroup();
    }
}

使flowable加载自定义实现的Idm

在FlowableUiApplication中添加配置信息,将我们自定义的业务类注入

@Bean
public EngineConfigurationConfigurer<SpringIdmEngineConfiguration> idmEngineConfigurationConfigurer() {
    return idmEngineConfiguration -> idmEngineConfiguration.setIdmIdentityService(new MyIdmIdentityServiceImpl(new IdmEngineConfiguration()));
}

启动,发现输出内容,后续即可根据自己的业务来实现

 (http) with context path '/flowable-ui'
开始获取人员信息***********************************
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇