springboot flowable工作流(一、flowable-ui使用)

3,570 阅读1分钟

流程图工具有很多,但是为了方便管理,我推荐使用flowable-ui进行流程图创建编辑、可以更方便我们使用。

项目配置

pom.xml配置

<dependencies>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <!--健康检查-->
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>
 <!--工作流-->
 <dependency>
  <groupId>org.flowable</groupId>
  <artifactId>flowable-ui-common</artifactId>
  <version>6.5.0</version>
 </dependency>
 <dependency>
  <groupId>org.flowable</groupId>
  <artifactId>flowable-ui-modeler-conf</artifactId>
  <version>6.5.0</version>
 </dependency>
 <dependency>
  <groupId>org.flowable</groupId>
  <artifactId>flowable-ui-modeler-rest</artifactId>
  <version>6.5.0</version>
 </dependency>
 <dependency>
  <groupId>org.flowable</groupId>
  <artifactId>flowable-ui-modeler-logic</artifactId>
  <version>6.5.0</version>
 </dependency>
 <!--mysql依赖-->
 <dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
 </dependency>
</dependencies>

<build>
 <plugins>
  <plugin>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-maven-plugin</artifactId>
  </plugin>
 </plugins>
 <resources>
  <resource>
   <directory>src/main/java</directory>
   <includes>
    <include>**/*.xml</include>
   </includes>
  </resource>
  <resource>
   <directory>src/main/resources</directory>
   <includes>
    <include>**/*.*</include>
   </includes>
  </resource>
 </resources>

</build>

UI的静态文件复制到本地 地址 modeler文件夹下载下来

application.yml配置

server:
  port: 8081

spring:
  datasource:
    url: jdbc:mysql://192.168.137.100:3306/spring_boot_flowable?characterEncoding=UTF-8
    username: root
    password: Root@123

flowable:
  rest:
    app:
      authentication-mode: verify-privilege
  common:
    app:
      idm-admin:
        password: test
        user: admin
      role-prefix:
      idm-url: http://localhost:8081/flowable-idm
  modeler:
    app:
      rest-enabled: true
      deployment-api-url: http://localhost:8081/flowable-task/app-api

type: modeler
version:
  minor: 4
  major: 6
  edition: Flowable
  revision: 2

按照下图建立这些包,因为我这里重写了一些配置,不需要登录就可以使用,

image.png

@Import({
        ApplicationConfiguration.class,
        AppDispatcherServletConfiguration.class
})
@SpringBootApplication(scanBasePackages="com.huzhihui.flowable")
public class ModelerApplication {

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

}

@RestController
@RequestMapping("/app")
public class RemoteAccountResource {

    @Autowired
    private RemoteIdmService remoteIdmService;

    /**
     * GET /rest/account -> get the current user.
     */
    @RequestMapping(value = "/rest/account", method = RequestMethod.GET, produces = "application/json")
    public UserRepresentation getAccount() {
//        UserRepresentation userRepresentation = null;
//        String currentUserId = SecurityUtils.getCurrentUserId();
//        if (currentUserId != null) {
//            RemoteUser remoteUser = remoteIdmService.getUser(currentUserId);
//            if (remoteUser != null) {
//                userRepresentation = new UserRepresentation(remoteUser);
//
//                if (remoteUser.getGroups() != null && remoteUser.getGroups().size() > 0) {
//                    List<GroupRepresentation> groups = new ArrayList<>();
//                    for (RemoteGroup remoteGroup : remoteUser.getGroups()) {
//                        groups.add(new GroupRepresentation(remoteGroup));
//                    }
//                    userRepresentation.setGroups(groups);
//                }
//
//                if (remoteUser.getPrivileges() != null && remoteUser.getPrivileges().size() > 0) {
//                    userRepresentation.setPrivileges(remoteUser.getPrivileges());
//                }
//
//            }
//        }
        UserRepresentation userRepresentation = new UserRepresentation();
        userRepresentation.setFirstName("admin");
        userRepresentation.setLastName("admin");
        userRepresentation.setFullName("admin");
        userRepresentation.setId("admin");
        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);
        userRepresentation.setPrivileges(pris);

        if (userRepresentation != null) {
            return userRepresentation;
        } else {
            throw new NotFoundException();
        }
    }
}


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;
        }

//        User user = null;
//        FlowableAppUser appUser = getCurrentFlowableAppUser();
//        if (appUser != null) {
//            user = appUser.getUserObject();
//        }

        RemoteUser user = new RemoteUser();
//        FlowableAppUser appUser = getCurrentFlowableAppUser();
//        if (appUser != null) {
//            user = appUser.getUserObject();
//        }
        user.setId("admin");
        user.setDisplayName("admin");
        user.setFirstName("admin");
        user.setLastName("admin");
        user.setEmail("admin@admin.com");
        user.setPassword("test");
        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;
    }

}


@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(org.flowable.ui.modeler.conf.SecurityConfiguration.class);

    public static final String REST_ENDPOINTS_PREFIX = "/app/rest";

    @Autowired
    protected RemoteIdmAuthenticationProvider authenticationProvider;

//    @Bean
//    public FlowableCookieFilterRegistrationBean flowableCookieFilterRegistrationBean(RemoteIdmService remoteIdmService, FlowableCommonAppProperties properties) {
//        FlowableCookieFilterRegistrationBean filter = new FlowableCookieFilterRegistrationBean(remoteIdmService, properties);
//        filter.addUrlPatterns("/app/*");
//        filter.setRequiredPrivileges(Collections.singletonList(DefaultPrivileges.ACCESS_MODELER));
//        return filter;
//    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {

        // Default auth (database backed)
        try {
            auth.authenticationProvider(authenticationProvider);
        } catch (Exception e) {
            LOGGER.error("Could not configure authentication mechanism:", e);
        }
    }

    @Configuration
    @Order(10)
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

//        @Autowired
//        protected FlowableCookieFilterRegistrationBean flowableCookieFilterRegistrationBean;

        @Autowired
        protected AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
//                    .addFilterBefore(flowableCookieFilterRegistrationBean.getFilter(), UsernamePasswordAuthenticationFilter.class)
                    .logout()
                    .logoutUrl("/app/logout")
                    .logoutSuccessHandler(ajaxLogoutSuccessHandler)
                    .addLogoutHandler(new ClearFlowableCookieLogoutHandler())
                    .and()
                    .csrf()
                    .disable() // Disabled, cause enabling it will cause sessions
                    .headers()
                    .frameOptions()
                    .sameOrigin()
                    .addHeaderWriter(new XXssProtectionHeaderWriter())
                    .and()
                    .authorizeRequests()
//                    .antMatchers(REST_ENDPOINTS_PREFIX + "/**").hasAuthority(DefaultPrivileges.ACCESS_MODELER);
                    .antMatchers(REST_ENDPOINTS_PREFIX + "/**").permitAll();
        }
    }

    //
    // BASIC AUTH
    //

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        protected final FlowableRestAppProperties restAppProperties;
        protected final FlowableModelerAppProperties modelerAppProperties;

        public ApiWebSecurityConfigurationAdapter(FlowableRestAppProperties restAppProperties,
                                                  FlowableModelerAppProperties modelerAppProperties) {
            this.restAppProperties = restAppProperties;
            this.modelerAppProperties = modelerAppProperties;
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .csrf()
                    .disable();

            http.antMatcher("/api/**").authorizeRequests().antMatchers("/api/**").permitAll();

//            if (modelerAppProperties.isRestEnabled()) {
//
//                if (restAppProperties.isVerifyRestApiPrivilege()) {
//                    http.antMatcher("/api/**").authorizeRequests().antMatchers("/api/**").hasAuthority(DefaultPrivileges.ACCESS_REST_API).and().httpBasic();
//                } else {
//                    http.antMatcher("/api/**").authorizeRequests().antMatchers("/api/**").authenticated().and().httpBasic();
//
//                }
//
//            } else {
//                http.antMatcher("/api/**").authorizeRequests().antMatchers("/api/**").denyAll();
//
//            }

        }
    }

    //
    // Actuator
    //

    @ConditionalOnClass(EndpointRequest.class)
    @Configuration
    @Order(5)
    public static class ActuatorWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .csrf()
                    .disable();

            http
                    .requestMatcher(new ActuatorRequestMatcher())
                    .authorizeRequests()
                    .requestMatchers(EndpointRequest.to(InfoEndpoint.class, HealthEndpoint.class)).authenticated()
                    .requestMatchers(EndpointRequest.toAnyEndpoint()).hasAnyAuthority(DefaultPrivileges.ACCESS_ADMIN)
                    .and().httpBasic();
        }
    }
}

运行项目就可以进行流程编辑了

image.png