Springboot integrated flowable modeler is logon-free and queries users/groups to change to their own number of systems

Previously, flowcharts were started with tomcat, but this startup did not allow you to query the data in your system when assigning task users/user groups.So now you need to integrate the flowable modeler into your project.

Previously, I also searched a lot of articles, and they didn't feel very clear, probably because I just came into contact soon.Now that you have integrated it yourself, write down the results of your studies.

  1. First, you need to create a springboot application that incorporates relevant jar packages into the pom file:
    <properties>
    <java.version>1.8</java.version>
    <flowable.version>6.4.1</flowable.version>
    <lombok.version>1.18.0</lombok.version>
    <fastjson.version>1.2.9</fastjson.version>
    </properties>

     <dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-dependencies</artifactId>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
         <!--Spring Cloud-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-dependencies</artifactId>
             <type>pom</type>
             <scope>import</scope>
         </dependency>
     </dependencies>
     </dependencyManagement>
    
     <dependencies>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter</artifactId>
     </dependency>
    
     <!-- Profile Processor -->
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-configuration-processor</artifactId>
     </dependency>
     <!-- lombok -->
     <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
         <version>${lombok.version}</version>
         <scope>provided</scope>
     </dependency>
     <!-- fastjson -->
     <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>fastjson</artifactId>
         <version>${fastjson.version}</version>
     </dependency>
     <!-- Druid -->
     <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>druid</artifactId>
         <version>1.1.9</version>
     </dependency>
    
     <!-- Generic Tool Class -->
    
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
    
     <!-- mysql drive -->
     <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>5.1.47</version>
     </dependency>
     <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-pool2</artifactId>
         <version>2.6.1</version>
     </dependency>
     <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-lang3</artifactId>
         <version>3.8.1</version>
     </dependency>
    
     <!-- Flowable spring-boot Edition Package -->
     <dependency>
         <groupId>org.flowable</groupId>
         <artifactId>flowable-spring-boot-starter</artifactId>
         <version>${flowable.version}</version>
     </dependency>
    
     <!-- Flowable Internal Logging Using SLF4J -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.7.21</version>
     </dependency>
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-log4j12</artifactId>
         <version>1.7.21</version>
     </dependency>
    
     <!-- app rely on Contain rest,logic,conf -->
     <dependency>
         <groupId>org.flowable</groupId>
         <artifactId>flowable-ui-modeler-rest</artifactId>
         <version>6.4.1</version>
     </dependency>
     <dependency>
         <groupId>org.flowable</groupId>
         <artifactId>flowable-ui-modeler-logic</artifactId>
         <version>6.4.1</version>
     </dependency>
     <dependency>
         <groupId>org.flowable</groupId>
         <artifactId>flowable-ui-modeler-conf</artifactId>
         <version>6.4.1</version>
     </dependency>
    
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
         <exclusions>
             <exclusion>
                 <groupId>org.junit.vintage</groupId>
                 <artifactId>junit-vintage-engine</artifactId>
             </exclusion>
         </exclusions>
     </dependency>

    </dependencies>

  2. Then you need to copy the files from the following pictures in the flowable modeler folder launched in tomcat described in the previous article to the resources folder in the springboot project:

    4.png


    Here is my project structure:

    5.png


    Under this folder is the Chinese file.

  1. Here are the three files we need to override: AppDispatcher Servlet Configuration, ApplicationConfiguration, FlowableStencilSetResource, which can be in any path

Com.springcloud.flowable.Conf.AppDispatcher Servlet ConfigurationThe following:

import org.flowable.ui.modeler.rest.app.EditorGroupsResource;
import org.flowable.ui.modeler.rest.app.EditorUsersResource;
import org.flowable.ui.modeler.rest.app.StencilSetResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import 
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
//www.1b23.com @Configuration @ComponentScan(value = { "org.flowable.ui.modeler.rest.app",    },excludeFilters = {        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = EditorUsersResource.class),        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = EditorGroupsResource.class),        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = StencilSetResource.class),    } ) @EnableAsync public class AppDispatcherServletConfiguration implements WebMvcRegistrations {    private static final Logger LOGGER = LoggerFactory.getLogger(AppDispatcherServletConfiguration.class); @Bean public SessionLocaleResolver localeResolver() {    return new SessionLocaleResolver(); } @Bean public LocaleChangeInterceptor localeChangeInterceptor() {    LOGGER.debug("Configuring localeChangeInterceptor");    LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();    localeChangeInterceptor.setParamName("language");    return localeChangeInterceptor; } @Override public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {    LOGGER.debug("Creating requestMappingHandlerMapping");    RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();    requestMappingHandlerMapping.setUseSuffixPatternMatch(false);    requestMappingHandlerMapping.setRemoveSemicolonContent(false);    Object[] interceptors = { localeChangeInterceptor() };    requestMappingHandlerMapping.setInterceptors(interceptors);    return requestMappingHandlerMapping; }

}
Com.springcloud.flowable.Conf.ApplicationConfigurationThe following:

 import org.flowable.ui.common.service.idm.RemoteIdmService;
 import org.flowable.ui.modeler.properties.FlowableModelerAppProperties;
 import org.flowable.ui.modeler.servlet.ApiDispatcherServletConfiguration;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.web.servlet.ServletRegistrationBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.FilterType;
 import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
 import org.springframework.web.servlet.DispatcherServlet;
//www.1b23.com@Configuration @EnableConfigurationProperties(FlowableModelerAppProperties.class) @ComponentScan(basePackages = { //        "org.flowable.ui.modeler.conf",        "org.flowable.ui.modeler.repository",        "org.flowable.ui.modeler.service", // * TheOrg.flowable.ui.Modeler.security", //Authorization is not required // * TheOrg.flowable.ui.Common.conf", // flowable development environment built-in database connections // * TheOrg.flowable.ui.Common.filter", // IDM-side filters        "org.flowable.ui.common.service",      "org.flowable.ui.common.repository",    // // * TheOrg.flowable.ui.Common.security", //Authorization is not required "org.flowable.ui.common.tenant" },excludeFilters = { // Remove RemoteIdmService @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = RemoteIdmService.class), } ) public class ApplicationConfiguration { @Bean public ServletRegistrationBean modelerApiServlet(ApplicationContext applicationContext) {    AnnotationConfigWebApplicationContext dispatcherServletConfiguration = new AnnotationConfigWebApplicationContext();    dispatcherServletConfiguration.setParent(applicationContext);    dispatcherServletConfiguration.register(ApiDispatcherServletConfiguration.class);    DispatcherServlet servlet = new DispatcherServlet(dispatcherServletConfiguration);    ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet, "/api/*");    registrationBean.setName("Flowable Modeler App API Servlet");    registrationBean.setLoadOnStartup(1);    registrationBean.setAsyncSupported(true);    return registrationBean; }

}
Com.springcloud.flowable.Conf.FlowableStencilSetResourceThe following:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.flowable.ui.common.service.exception.InternalServerErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

//www.1b23.com@RestController @RequestMapping("/app") public class FlowableStencilSetResource { private static final Logger LOGGER = LoggerFactory.getLogger(FlowableStencilSetResource.class); @Autowired protected ObjectMapper objectMapper; @RequestMapping(value = "/rest/stencil-sets/editor", method = RequestMethod.GET, produces = "application/json") public JsonNode getStencilSetForEditor() { try {         JsonNode stencilNode objectMapper.readTree(this.getClass().getClassLoader(). getResourceAsStream("stencilset/stencilse   t_bpmn.json"));        return stencilNode;    } catch (Exception e) {        LOGGER.error("Error reading bpmn stencil set json", e);        throw new InternalServerErrorException("Error reading bpmn stencil set json");        }    }    @RequestMapping(value = "/rest/stencil-sets/cmmneditor", method = RequestMethod.GET, produces = "application/json")   public JsonNode getCmmnStencilSetForEditor() {    try {        JsonNode stencilNode = objectMapper.readTree(this.getClass().getClassLoader(). getResourceAsStream("stencilset/stencilse t_cmmn.json"));        return stencilNode;    } catch (Exception e) {        LOGGER.error("Error reading bpmn stencil set json", e);        throw new InternalServerErrorException("Error reading bpmn stencil set json");    }    } }

com.springcloud.flowable.controller.FlowableController: Rewrite the interface for flowable modeler login

7.png

import org.flowable.ui.common.model.UserRepresentation;
import org.flowable.ui.common.security.DefaultPrivileges;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * Flowable Related Interfaces
 *  www.1b23.com
 */
@RestController
@RequestMapping("/login")
public class FlowableController {

  /**
   * Get default administrator information
   * @return
   */
   @RequestMapping(value = "/rest/account", method = RequestMethod.GET, produces = 
 "application/json")
    public UserRepresentation getAccount() {
      UserRepresentation userRepresentation = new UserRepresentation();
    userRepresentation.setId("admin");
    userRepresentation.setEmail("admin@flowable.org");
    userRepresentation.setFullName("Administrator");
//        userRepresentation.setLastName("Administrator");
    userRepresentation.setFirstName("Administrator");
    List<String> privileges = new ArrayList<>();
    privileges.add(DefaultPrivileges.ACCESS_MODELER);
    privileges.add(DefaultPrivileges.ACCESS_IDM);
    privileges.add(DefaultPrivileges.ACCESS_ADMIN);
    privileges.add(DefaultPrivileges.ACCESS_TASK);
    privileges.add(DefaultPrivileges.ACCESS_REST_API);
    userRepresentation.setPrivileges(privileges);
    return userRepresentation;
    }
}

User id is used when adding process, refactoring here SecurityUtils.getCurrentUserObject To get user information, this file path must match the original path:
org.flowable.ui.common.security.SecurityUtils

import org.flowable.idm.api.User;
import org.flowable.ui.common.model.RemoteUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.ArrayList;
import java.util.List;
 /**
 * Utility class for Spring Security.  
*  www.1b23.com
*/ public class SecurityUtils {   private static User assumeUser;    private SecurityUtils() {    }    /**    * Get the login of the current user.    */    public static String getCurrentUserId() {      User user = getCurrentUserObject();      if (user != null) {        return user.getId();      }     return null;  }  /**  * @return the {@link User} object associated with the current logged in user.  */ public static User getCurrentUserObject() {     if (assumeUser != null) {         return assumeUser;     }    RemoteUser user = new RemoteUser();    user.setId("admin");    user.setDisplayName("Administrator");    user.setFirstName("Administrator");    user.setLastName("Administrator");    user.setEmail("admin@flowable.com");    user.setPassword("123456");    List<String> pris = new ArrayList<>();    pris.add(DefaultPrivileges.ACCESS_MODELER);    pris.add(DefaultPrivileges.ACCESS_IDM);    pris.add(DefaultPrivileges.ACCESS_ADMIN);    pris.add(DefaultPrivileges.ACCESS_TASK);    pris.add(DefaultPrivileges.ACCESS_REST_API);    user.setPrivileges(pris);     return user;  } public static FlowableAppUser getCurrentFlowableAppUser() {    FlowableAppUser user = null;    SecurityContext securityContext = SecurityContextHolder.getContext();    if (securityContext != null && securityContext.getAuthentication() != null) {        Object principal = securityContext.getAuthentication().getPrincipal();        if (principal instanceof FlowableAppUser) {            user = (FlowableAppUser) principal;        }     }     return user; } public static boolean currentUserHasCapability(String capability) {    FlowableAppUser user = getCurrentFlowableAppUser();    for (GrantedAuthority grantedAuthority : user.getAuthorities()) {        if (capability.equals(grantedAuthority.getAuthority())) {            return true;        }     }     return false; } public static void assumeUser(User user) {     assumeUser = user; } public static void clearAssumeUser() {     assumeUser = null; }

}

Profile:application.yml:

server:
port: 8087
spring:
datasource:
  url: jdbc:mysql://127.0.0.1:3306/pyj?useUnicode=true&characterEncoding=utf8
  username: root
  password: 123456
  driverClassName: com.mysql.jdbc.Driver
  resources:
 mybatis:
 mapper-locations: mapper/*/*.xml, classpath*:mapper/*.xml
 configuration:
  log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

Startup class: SpringCloudApplication

import com.springcloud.flowable.conf.AppDispatcherServletConfiguration;
import com.springcloud.flowable.conf.ApplicationConfiguration;
import org.flowable.ui.modeler.conf.DatabaseConfiguration;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

@Import(value={
    //Introduction of modified configuration
    ApplicationConfiguration.class,
    AppDispatcherServletConfiguration.class,
    //Introduction of DatabaseConfiguration Table Update Conversion
    DatabaseConfiguration.class})
//Eureka client
@ComponentScan(basePackages = {"com.springcloud.*"})
@MapperScan("com.springcloud.*.dao")
//Remove Security AutoConfiguration
@SpringBootApplication(exclude={SecurityAutoConfiguration.class})
public class SpringcloudApplication {

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

}

This configuration is important @SpringBootApplication (exclude={Secur)ItyAutoConfiguration.class}: Exclude springsecurity authentication

Start the project next: Enter:localhost:8087

8.png

Last rewrite Get Users, User Group Interface

import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.ManagementService;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.IdmIdentityService;
import org.flowable.idm.api.User;
import org.flowable.ui.common.model.GroupRepresentation;
import org.flowable.ui.common.model.ResultListDataRepresentation;
import org.flowable.ui.common.model.UserRepresentation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
//www.1b23.com@RestController @RequestMapping("app") public class UserAndGroupResourceController { @Autowired protected ManagementService managementService; @Autowired protected IdmIdentityService idmIdentityService; @RequestMapping(value = "/rest/editor-groups", method = RequestMethod.GET) public ResultListDataRepresentation getGroups(@RequestParam(required = false, value = "filter") String filter) {    if (StringUtils.isNotBlank(filter)) {        filter = filter.trim();        String sql = "select * from ACT_ID_GROUP where NAME_ like #{name}";        filter = "%" + filter + "%";        List<Group> groups = idmIdentityService.createNativeGroupQuery().sql(sql).parameter("name", filter).listPage(0, 10);        List<GroupRepresentation> result = new ArrayList<>();        for (Group group : groups) {            result.add(new GroupRepresentation(group));        }        return new ResultListDataRepresentation(result);    }    return null; } @RequestMapping(value = "/rest/editor-users", method = RequestMethod.GET) public ResultListDataRepresentation getUsers(@RequestParam(value = "filter", required = false) String filter) {    if (StringUtils.isNotBlank(filter)) {        filter = filter.trim();        String sql = "select * from ACT_ID_USER where ID_ like #{id} or LAST_ like #{name}";        filter = "%"+filter+"%";        List<User> matchingUsers = idmIdentityService.createNativeUserQuery().sql(sql). parameter("id",filter).parameter("name",filter).listPage(0, 10);List<UserRepresentation> userRepresentations = new ArrayList<>(matchingUsers.size());        for (User user : matchingUsers) {            userRepresentations.add(new UserRepresentation(user));        }        return new ResultListDataRepresentation(userRepresentations);    }    return null;  }

}

Table built by itself when flowable starts: ACT_ID_MEMBERSHIP,ACT _ID_GROUP, ACT_ID_USER Delete
The self-built view queries the user/privilege/role table in its own system:

-- User table
CREATE VIEW ACT_ID_USER AS SELECT SU.USER_ID AS ID_,1 AS REV_,SU.REAL_NM AS 
FIRST_,
concat('',SU.USER_ID) AS LAST_ ,'000000' AS PWD_ , SUL.LOGIN_EMAIL AS EMAIL_, 
SU.WEB_FACE AS PICTURE_ID_
FROM SYS_USER AS SU INNER JOIN sys_manager.SYS_USER_LOGIN AS 
SUL
ON SU.USER_ID = SUL.USER_ID;
-- Grouping table
CREATE VIEW ACT_ID_GROUP AS SELECT SR.ROLE_ID AS ID_ , 1 AS REV_, SR.ROLE_NM 
AS NAME_,
CASE WHEN SR.IS_ADMIN=1 then 'admin' else 'ordinary' end as TYPE_ FROM 
SYS_ROLE AS SR;
-- Relational table
CREATE VIEW ACT_ID_MEMBERSHIP AS SELECT SUR.USER_ID AS USER_ID_,
SUR.ROLE_ID AS GROUP_ID_ FROM SYS_USER_ROLE AS SUR;

Task node selects user/user group:


9.png


Tags: Java Spring REST JSON

Posted on Tue, 09 Jun 2020 16:29:52 -0400 by hogleg