写在前面
需要提前了解的内容有:
springboot、springSecurity、activiti基本使用
关于activiti
Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),面对新技术的机遇,诸如互操作性和云架构,提供技术实现。
activiti主要应用场景
需要动态地改变流程的业务流程场景。例如请假流程、项目审批流程等。
正题
第一步:
新建一个springboot项目,引入activiti-spring-boot-starter和你所使用的数据库驱动器。本文采用Mysql 8.
读者也可以直接复制下面的pom文件
<?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.0modelVersion> <parent> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-parentartifactId> <version>2.3.3.RELEASEversion> <relativePath/> parent> <groupId>pers.lbfgroupId> <artifactId>springboot-activitiartifactId> <version>0.0.1-SNAPSHOTversion> <name>springboot-activitiname> <description>Demo project for Spring Bootdescription> <properties> <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding> <java.version>1.8java.version> properties> <dependencies> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starterartifactId> dependency> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-testartifactId> <scope>testscope> <exclusions> <exclusion> <groupId>org.junit.vintagegroupId> <artifactId>junit-vintage-engineartifactId> exclusion> exclusions> dependency> <dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-jdbcartifactId> dependency> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>8.0.12version> dependency> <dependency> <groupId>com.baomidougroupId> <artifactId>mybatis-plus-boot-starterartifactId> <version>3.3.2version> dependency> <dependency> <groupId>org.activitigroupId> <artifactId>activiti-spring-boot-starterartifactId> <version>7.0.0.Beta2version> dependency> dependencies> <build> <plugins> <plugin> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-maven-pluginartifactId> plugin> plugins> build>project>
第二步,修改application.yml配置文件
spring: datasource: url: jdbc:mysql://127.0.0.1:3306/你的数据库?userSSL=false&serverTimezone=GMT%2B8 username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver
第三步,添加springSecurity的相关配置。
因为activiti7与springboot整合之后,默认情况下集成了springSecurity框架,所以我们需要配置一下springSecurity。本文的核心不在springSecurity,所以这一步将通过添加一个工具类的方式来完成。
package pers.lbf.springbootactiviti.utils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.Authentication;import org.springframework.security.core.GrantedAuthority;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.stereotype.Component;import javax.security.auth.Subject;import javax.vecmath.Tuple2d;import java.util.Collection;/** * @author 赖柄沣 bingfengdev@aliyun.com * @date 2020-08-18 11:27:31 * @version 1.0 */@Componentpublic class SecurityUtil { @Autowired private UserDetailsService userDetailsService; 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"); } Authentication authentication = new Authentication() { @Override public String getName() { return user.getUsername(); } @Override public boolean implies(Subject subject) { return false; } @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 b) throws IllegalArgumentException { } }; SecurityContextImpl securityContext = new SecurityContextImpl(); securityContext.setAuthentication(authentication); SecurityContextHolder.setContext(securityContext); org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username); }}
第四步,添加权限配置信息。
正常项目中,权限信息存储于数据库当中。本文为了陈述方便,直接将权限信息定义在配置类当中。
package pers.lbf.springbootactiviti.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;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 java.util.Arrays;import java.util.List;import java.util.stream.Collectors;/** * @author 赖柄沣 bingfengdev@aliyun.com * @version 1.0 * @date 2020/8/18 11:40 */@Configurationpublic class ApplicationConfig { @Bean public UserDetailsService getUserDetailsService(){ InMemoryUserDetailsManager userDetailsManager = 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"}, {"system", "password", "ROLE_ACTIVITI_USER"}, {"admin", "password", "ROLE_ACTIVITI_ADMIN"} }; for (String[] user : usersGroupsAndRoles) { List authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user,2,user.length)); userDetailsManager.createUser(new User( user[0], passwordEncoder().encode(user[1]), authoritiesStrings.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()) ) ); } return userDetailsManager; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }}
第五步,整合Junit,验证是否整合成功
首先,添加Junit依赖
<dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <scope>testscope> dependency>
编写测试类
package pers.lbf.springbootactiviti.activititest;import org.activiti.api.process.model.ProcessDefinition;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.ClaimTaskPayloadBuilder;import org.activiti.api.task.model.builders.CompleteTaskPayloadBuilder;import org.activiti.api.task.runtime.TaskRuntime;import org.activiti.engine.ProcessEngine;import org.activiti.engine.RepositoryService;import org.activiti.engine.repository.Deployment;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import pers.lbf.springbootactiviti.utils.SecurityUtil;import java.util.List;/** * @author 赖柄沣 bingfengdev@aliyun.com * @version 1.0 * @date 2020/8/18 12:10 */@RunWith(SpringRunner.class)@SpringBootTestpublic class Activiti7SpringbootTest { @Autowired private ProcessRuntime processRuntime; @Autowired private TaskRuntime taskRuntime; @Autowired private SecurityUtil securityUtil; @Autowired private ProcessEngine processEngine; @Before public void init() { //认证 securityUtil.logInAs("system"); } /**部署流程 * @author 赖柄沣 bingfengdev@aliyun.com * @date 2020-08-18 12:53:51 * @version 1.0 */ @Test public void repositoryProcess(){ RepositoryService repositoryService = processEngine.getRepositoryService(); Deployment deployment = repositoryService.createDeployment() .addClasspathResource("holiday.bpmn") .name("请假流程") .deploy(); System.out.println(deployment.getName()); System.out.println(deployment.getDeploymentTime()); } /**分页查询系统中所有可用的流程定义 * @author 赖柄沣 bingfengdev@aliyun.com * @date 2020-08-18 13:32:36 * @version 1.0 */ @Test public void findProcessList(){ Page processDefinitionPage = processRuntime .processDefinitions(Pageable.of(0, 10)); List content = processDefinitionPage.getContent(); for (ProcessDefinition processDefinition : content) { System.out.println(processDefinition.getName()); } } /**启动流程 * @author 赖柄沣 bingfengdev@aliyun.com * @date 2020-08-18 13:21:12 * @version 1.0 */ @Test public void startProcess(){ StartProcessPayload myProcess = ProcessPayloadBuilder .start() .withProcessDefinitionId("myProcess_1:1:5c5e0de3-e112-11ea-a73b-287fcf13e373") .build(); myProcess.setProcessInstanceName("张三请假"); processRuntime.start(myProcess); System.out.println("流程实例"+myProcess.getId()); } /**查询并完成任务 * @author 赖柄沣 bingfengdev@aliyun.com * @date 2020-08-18 13:41:40 * @version 1.0 */ @Test public void findAndFinishTask() { Page taskPage = taskRuntime.tasks(Pageable.of(0, 10)); if (taskPage.getTotalItems()>0){ List content = taskPage.getContent(); for (Task task : content) { //拾取任务 taskRuntime.claim(new ClaimTaskPayloadBuilder() .withTaskId(task.getId()) .build()); //完成任务 taskRuntime.complete(new CompleteTaskPayloadBuilder() .withTaskId(task.getId()) .build()); } } }}
End
本文仅介绍如何将activiti7集成到springboot中.具体的activiti使用请参考其他博文。
本文代码github地址:
https://github.com/code81192/springboot-activiti7/tree/master