一、环境
- IDEA
- spring2.1.5
- Activiti7
- Swagger 2.9.2
- Druid 1.1.16
- mysql 5.7
- JAVA 8
二、新建Spring Boot项目
略~~~
三、maven pom.xml配置明细
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.reanod.workflow</groupId>
<artifactId>reanod_workflow</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>reanod_workflow</name>
<description>Reanod Workflow</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 阿里 druid 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.activiti.dependencies/activiti-dependencies -->
<dependency>
<groupId>org.activiti.dependencies</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.1.0.M1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M1</version>
</dependency>
<!-- Activiti生成流程图 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-image-generator</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
四、配置文件application.yml
spring:
#Activiti property configuration
activiti:
database-schema-update: true
job-executor-activate: true # asyncExecutorEnabled属性设置设置true后将代替那些老的Job executor
history-level: full
db-history-used: true
check-process-definitions: false # 自动部署验证设置:true-开启(默认)、false-关闭
datasource:
url: jdbc:mysql://localhost:3306/reanod_workflow?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC&nullCatalogMeansCurrent=true
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
initialization-mode: always
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
logging:
level:
com.ascendant: debug
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} %clr(-%5p) %clr(${PID:- }){magenta} --- %clr([%15.15t]){faint} %highlight(%-80.80logger{300}){cyan} %clr(:) %m %n%wEx"
swagger:
enabled: true
因为activiti例子中使用了 org.springframework.security,所以数据库中,需要建表
DROP TABLE IF EXISTS users ;
CREATE TABLE users (
username VARCHAR(20) NOT NULL,
PASSWORD VARCHAR(150) NOT NULL,
enabled TINYINT(1) DEFAULT NULL,
PRIMARY KEY (username)
) ENGINE=INNODB DEFAULT CHARSET=utf8 ;
DROP TABLE IF EXISTS authorities;
CREATE TABLE authorities (
id BIGINT(20) NOT NULL AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
authority VARCHAR(50) NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
配置修改,使用JdbcUserDetailsManager类,即使用数据库获取用户信息
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
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.JdbcUserDetailsManager;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.List;
@Configuration
public class ApplicationConfiguration extends WebSecurityConfigurerAdapter {
private Logger logger = LoggerFactory.getLogger(ApplicationConfiguration.class);
@Autowired
private DataSource dataSource;
@Bean
public UserDetailsService myUserDetailsService() {
JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager(dataSource);
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 + "]");
// jdbcUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
// authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
}
return jdbcUserDetailsManager;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
五、集成Druid
/*
* @author xugj<br>
* @version 1.0<br>
* @createDate 2019/05/30 14:51 <br>
* @Description <p> </p>
*/
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DruidConfiguration {
// 将所有前缀为spring.datasource下的配置项都加载到DataSource中
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource() {
return new DruidDataSource();
}
@Bean
public ServletRegistrationBean druidStatViewServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String, String> initParams = new HashMap<>();
// 可配的属性都在 StatViewServlet 和其父类下
initParams.put("loginUsername", "admin-druid");
initParams.put("loginPassword", "111111");
servletRegistrationBean.setInitParameters(initParams);
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean druidWebStatFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
Map<String, String> initParams = new HashMap<>();
initParams.put("exclusions", "*.js,*.css,/druid/*");
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
}
六、集成Swagger
package com.reanod.workflow.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author xugj<br>
* @version 1.0<br>
* @createDate 2019/05/29 17:37 <br>
* @Description <p> Swagger2 配置文件 </p>
*/
@EnableSwagger2
@Configuration
public class SwaggerConfig {
//是否开启swagger,正式环境一般是需要关闭的,可根据springboot的多环境配置进行设置
@Value(value = "${swagger.enabled}")
Boolean swaggerEnabled;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
// 是否开启
.enable(swaggerEnabled).select()
.apis(RequestHandlerSelectors.basePackage("com.reanod.workflow.controller"))
.paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Reanod工作流API")
.description("xugj | 高效码农")
// 作者信息
.contact(new Contact("高效码农", "https://www.xugj520.cn", "514583562@qq.com"))
.version("1.0.0")
.build();
}
}
七、创建processes bpmn文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1559179417530" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="myProcess_1" isClosed="false" isExecutable="true" processType="None">
<startEvent id="startevent1" name="StartEvent"/>
<userTask activiti:exclusive="true" id="usertask1" name="填写请假申请"/>
<sequenceFlow id="_2" sourceRef="startevent1" targetRef="usertask1"/>
<exclusiveGateway gatewayDirection="Unspecified" id="exclusivegateway1" name="请假时间判断(排他网关)"/>
<sequenceFlow id="_4" sourceRef="usertask1" targetRef="exclusivegateway1"/>
<userTask activiti:assignee="test" activiti:exclusive="true" id="usertask2" name="经理审批"/>
<userTask activiti:assignee="test2" activiti:exclusive="true" id="usertask3" name="总监审批"/>
<exclusiveGateway gatewayDirection="Unspecified" id="exclusivegateway2" name="请假时间判断(排他网关)"/>
<endEvent id="endevent1" name="End"/>
<sequenceFlow id="_9" name="大于3天" sourceRef="exclusivegateway1" targetRef="usertask3">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${days>3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_10" name="小于等于3天" sourceRef="exclusivegateway1" targetRef="usertask2">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${days<=3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_11" sourceRef="usertask2" targetRef="exclusivegateway2"/>
<sequenceFlow id="_12" sourceRef="usertask3" targetRef="exclusivegateway2"/>
<sequenceFlow id="_13" sourceRef="exclusivegateway2" targetRef="endevent1"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="myProcess_1">
<bpmndi:BPMNShape bpmnElement="startevent1" id="Shape-startevent1">
<omgdc:Bounds height="32.0" width="32.0" x="160.0" y="125.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="Shape-usertask1">
<omgdc:Bounds height="55.0" width="85.0" x="305.0" y="110.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="Shape-exclusivegateway1" isMarkerVisible="false">
<omgdc:Bounds height="32.0" width="32.0" x="445.0" y="115.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask2" id="Shape-usertask2">
<omgdc:Bounds height="55.0" width="85.0" x="540.0" y="55.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask3" id="Shape-usertask3">
<omgdc:Bounds height="55.0" width="85.0" x="535.0" y="165.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="exclusivegateway2" id="Shape-exclusivegateway2" isMarkerVisible="false">
<omgdc:Bounds height="32.0" width="32.0" x="710.0" y="125.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="Shape-endevent1">
<omgdc:Bounds height="32.0" width="32.0" x="830.0" y="135.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="exclusivegateway2" targetElement="endevent1">
<omgdi:waypoint x="742.0" y="141.0"/>
<omgdi:waypoint x="830.0" y="151.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="usertask3" targetElement="exclusivegateway2">
<omgdi:waypoint x="620.0" y="192.5"/>
<omgdi:waypoint x="710.0" y="141.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_2" id="BPMNEdge__2" sourceElement="startevent1" targetElement="usertask1">
<omgdi:waypoint x="192.0" y="141.0"/>
<omgdi:waypoint x="305.0" y="137.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_4" id="BPMNEdge__4" sourceElement="usertask1" targetElement="exclusivegateway1">
<omgdi:waypoint x="390.0" y="137.5"/>
<omgdi:waypoint x="445.0" y="131.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="exclusivegateway1" targetElement="usertask3">
<omgdi:waypoint x="477.0" y="131.0"/>
<omgdi:waypoint x="535.0" y="192.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="usertask2" targetElement="exclusivegateway2">
<omgdi:waypoint x="625.0" y="82.5"/>
<omgdi:waypoint x="710.0" y="141.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="exclusivegateway1" targetElement="usertask2">
<omgdi:waypoint x="477.0" y="131.0"/>
<omgdi:waypoint x="540.0" y="82.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
八、编写业务代码
部署流程、删除流程
import com.reanod.workflow.utils.RestMessgae;
import io.swagger.annotations.*;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipInputStream;
/**
* @author xugj<br>
* @version 1.0<br>
* @createDate 2019/05/29 17:34 <br>
* @Description <p> 部署流程、删除流程 </p>
*/
@RestController
@Api(tags="部署流程、删除流程")
public class DeployController {
private final RepositoryService repositoryService;
public DeployController(RepositoryService repositoryService) {
this.repositoryService = repositoryService;
}
@PostMapping(path = "deploy")
@ApiOperation(value = "根据bpmnName部署流程",notes = "根据bpmnName部署流程")
@ApiImplicitParams({
@ApiImplicitParam(name = "bpmnName",value = "设计的流程图名称",dataType = "String",paramType = "query",example = "myProcess")
})
public RestMessgae deploy(@RequestParam("bpmnName") String bpmnName){
RestMessgae restMessgae = new RestMessgae();
//创建一个部署对象
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().name("请假流程");
Deployment deployment = null;
try {
deployment = deploymentBuilder
.addClasspathResource("processes/"+ bpmnName +".bpmn")
.addClasspathResource("processes/"+ bpmnName +".png")
.deploy();
} catch (Exception e) {
restMessgae = RestMessgae.fail("部署失败", e.getMessage());
e.printStackTrace();
}
if (deployment != null) {
Map<String, String> result = new HashMap<>(2);
result.put("deployID", deployment.getId());
result.put("deployName", deployment.getName());
restMessgae = RestMessgae.success("部署成功", result);
}
return restMessgae;
}
@PostMapping(path = "deployZIP")
@ApiOperation(value = "根据ZIP压缩包部署流程",notes = "根据ZIP压缩包部署流程")
@ApiImplicitParams({
@ApiImplicitParam(name = "zipName",value = "设计的流程图和图片的压缩包名称",dataType = "String",paramType = "query",example = "myProcess")
})
public RestMessgae deployZIP(@RequestParam("zipName") String zipName){
RestMessgae restMessgae = new RestMessgae();
Deployment deployment = null;
try {
InputStream in = this.getClass().getClassLoader().getResourceAsStream("processes/leaveProcess.zip");
ZipInputStream zipInputStream = new ZipInputStream(in);
deployment = repositoryService.createDeployment()
.name("请假流程2")
//指定zip格式的文件完成部署
.addZipInputStream(zipInputStream)
.deploy();//完成部署
zipInputStream.close();
} catch (Exception e) {
restMessgae = RestMessgae.fail("部署失败", e.getMessage());
// TODO 上线时删除
e.printStackTrace();
}
if (deployment != null) {
Map<String, String> result = new HashMap<>(2);
result.put("deployID", deployment.getId());
result.put("deployName", deployment.getName());
restMessgae = RestMessgae.success("部署成功", result);
}
return restMessgae;
}
@PostMapping(path = "deleteProcess")
@ApiOperation(value = "根据部署ID删除流程",notes = "根据部署ID删除流程")
@ApiImplicitParams({
@ApiImplicitParam(name = "deploymentId",value = "部署ID",dataType = "String",paramType = "query",example = "")
})
public RestMessgae deleteProcess(@RequestParam("deploymentId") String deploymentId){
RestMessgae restMessgae = new RestMessgae();
/**不带级联的删除:只能删除没有启动的流程,如果流程启动,就会抛出异常*/
try {
repositoryService.deleteDeployment(deploymentId);
} catch (Exception e) {
restMessgae = RestMessgae.fail("删除失败", e.getMessage());
// TODO 上线时删除
e.printStackTrace();
}
/**级联删除:不管流程是否启动,都能可以删除(emmm大概是一锅端)*/
// repositoryService.deleteDeployment(deploymentId, true);
restMessgae = RestMessgae.success("删除成功", null);
return restMessgae;
}
}
启动流程实例
import com.reanod.workflow.utils.RestMessgae;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author xugj<br>
* @version 1.0<br>
* @createDate 2019/05/30 10:31 <br>
* @Description <p> 启动流程实例 </p>
*/
@RestController
@Api(tags="启动流程实例")
public class StartController {
private final RuntimeService runtimeService;
public StartController(RuntimeService runtimeService) {
this.runtimeService = runtimeService;
}
@PostMapping(path = "start")
@ApiOperation(value = "根据流程key启动流程",notes = "每一个流程有对应的一个key这个是某一个流程内固定的写在bpmn内的")
@ApiImplicitParams({
@ApiImplicitParam(name = "processKey",value = "流程key",dataType = "String",paramType = "query",example = ""),
@ApiImplicitParam(name = "user",value = "启动流程的用户",dataType = "String",paramType = "query",example = "")
})
public RestMessgae start(@RequestParam("user") String userKey,
@RequestParam("processKey") String processKey) {
HashMap<String, Object> variables=new HashMap<>(1);
variables.put("userKey", userKey);
RestMessgae restMessgae = new RestMessgae();
ProcessInstance instance = null;
try {
instance = runtimeService
.startProcessInstanceByKey(processKey, variables);
} catch (Exception e) {
restMessgae = RestMessgae.fail("启动失败", e.getMessage());
e.printStackTrace();
}
if (instance != null) {
Map<String, String> result = new HashMap<>(2);
// 流程实例ID
result.put("processID", instance.getId());
// 流程定义ID
result.put("processDefinitionKey", instance.getProcessDefinitionId());
restMessgae = RestMessgae.success("启动成功", result);
}
return restMessgae;
}
@PostMapping(path = "searchByKey")
@ApiOperation(value = "根据流程key查询流程实例",notes = "查询流程实例")
@ApiImplicitParams({
@ApiImplicitParam(name = "processKey",value = "流程key",dataType = "String",paramType = "query",example = ""),
})
public RestMessgae searchProcessInstance(@RequestParam("processKey") String processDefinitionKey){
RestMessgae restMessgae = new RestMessgae();
List<ProcessInstance> runningList = new ArrayList<>();
try {
ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
runningList = processInstanceQuery.processDefinitionKey(processDefinitionKey).list();
} catch (Exception e) {
restMessgae = RestMessgae.fail("查询失败", e.getMessage());
e.printStackTrace();
}
int size = runningList.size();
if (size > 0) {
List<Map<String, String>> resultList = new ArrayList<>();
for (int i = 0; i < size; i++) {
ProcessInstance pi = runningList.get(i);
Map<String, String> resultMap = new HashMap<>(2);
// 流程实例ID
resultMap.put("processID", pi.getId());
// 流程定义ID
resultMap.put("processDefinitionKey", pi.getProcessDefinitionId());
resultList.add(resultMap);
}
restMessgae = RestMessgae.success("查询成功", resultList);
}
return restMessgae;
}
@PostMapping(path = "searchByID")
@ApiOperation(value = "根据流程key查询流程实例",notes = "查询流程实例")
@ApiImplicitParams({
@ApiImplicitParam(name = "processID",value = "流程实例ID",dataType = "String",paramType = "query",example = ""),
})
public RestMessgae searchByID(@RequestParam("processID") String processDefinitionID){
RestMessgae restMessgae = new RestMessgae();
ProcessInstance pi = null;
try {
pi = runtimeService.createProcessInstanceQuery()
.processInstanceId(processDefinitionID)
.singleResult();
} catch (Exception e) {
restMessgae = RestMessgae.fail("查询失败", e.getMessage());
e.printStackTrace();
}
if (pi != null) {
Map<String, String> resultMap = new HashMap<>(2);
// 流程实例ID
resultMap.put("processID", pi.getId());
// 流程定义ID
resultMap.put("processDefinitionKey", pi.getProcessDefinitionId());
restMessgae = RestMessgae.success("查询成功", resultMap);
}
return restMessgae;
}
@PostMapping(path = "deleteProcessInstanceByKey")
@ApiOperation(value = "根据流程实例key删除流程实例",notes = "根据流程实例key删除流程实例")
@ApiImplicitParams({
@ApiImplicitParam(name = "processKey",value = "流程实例Key",dataType = "String",paramType = "query",example = ""),
})
public RestMessgae deleteProcessInstanceByKey(@RequestParam("processKey") String processDefinitionKey){
RestMessgae restMessgae = new RestMessgae();
List<ProcessInstance> runningList = new ArrayList<>();
try {
ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
runningList = processInstanceQuery.processDefinitionKey(processDefinitionKey).list();
} catch (Exception e) {
restMessgae = RestMessgae.fail("删除失败", e.getMessage());
e.printStackTrace();
}
int size = runningList.size();
if (size > 0) {
List<Map<String, String>> resultList = new ArrayList<>();
for (int i = 0; i < size; i++) {
ProcessInstance pi = runningList.get(i);
runtimeService.deleteProcessInstance(pi.getId(),"删除");
}
restMessgae = RestMessgae.success("删除成功", resultList);
}
return restMessgae;
}
@PostMapping(path = "deleteProcessInstanceByID")
@ApiOperation(value = "根据流程实例ID删除流程实例",notes = "根据流程实例ID删除流程实例")
@ApiImplicitParams({
@ApiImplicitParam(name = "processID",value = "流程实例ID",dataType = "String",paramType = "query",example = ""),
})
public RestMessgae deleteProcessInstanceByID(@RequestParam("processID") String processDefinitionID){
RestMessgae restMessgae = new RestMessgae();
try {
runtimeService.deleteProcessInstance(processDefinitionID,"删除" + processDefinitionID);
} catch (Exception e) {
restMessgae = RestMessgae.fail("删除失败", e.getMessage());
return restMessgae;
}
restMessgae = RestMessgae.success("删除成功", "");
return restMessgae;
}
}
任务相关接口
import com.reanod.workflow.utils.RestMessgae;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author xugj<br>
* @version 1.0<br>
* @createDate 2019/05/30 11:59 <br>
* @Description <p> 任务相关接口 </p>
*/
@RestController
@Api(tags = "任务相关接口")
public class TaskController {
private final TaskService taskService;
public TaskController(TaskService taskService) {
this.taskService = taskService;
}
@PostMapping(path = "findTaskByAssignee")
@ApiOperation(value = "根据流程assignee查询当前人的个人任务", notes = "根据流程assignee查询当前人的个人任务")
@ApiImplicitParams({
@ApiImplicitParam(name = "assignee", value = "代理人(当前用户)", dataType = "String", paramType = "query", example = ""),
})
public RestMessgae findTaskByAssignee(@RequestParam("assignee") String assignee) {
RestMessgae restMessgae = new RestMessgae();
//创建任务查询对象
List<Task> taskList;
try {
taskList = taskService.createTaskQuery()
//指定个人任务查询
.taskAssignee(assignee)
.list();
} catch (Exception e) {
restMessgae = RestMessgae.fail("查询失败", e.getMessage());
e.printStackTrace();
return restMessgae;
}
if (taskList != null && taskList.size() > 0) {
List<Map<String, String>> resultList = new ArrayList<>();
for (Task task : taskList) {
Map<String, String> resultMap = new HashMap<>(7);
/* 任务ID */
resultMap.put("taskID", task.getId());
/* 任务名称 */
resultMap.put("taskName", task.getName());
/* 任务的创建时间 */
resultMap.put("taskCreateTime", task.getCreateTime().toString());
/* 任务的办理人 */
resultMap.put("taskAssignee", task.getAssignee());
/* 流程实例ID */
resultMap.put("processInstanceId", task.getProcessInstanceId());
/* 执行对象ID */
resultMap.put("executionId", task.getExecutionId());
/* 流程定义ID */
resultMap.put("processDefinitionId", task.getProcessDefinitionId());
resultList.add(resultMap);
}
restMessgae = RestMessgae.success("查询成功", resultList);
} else {
restMessgae = RestMessgae.success("查询成功", null);
}
return restMessgae;
}
@PostMapping(path = "completeTask")
@ApiOperation(value = "完成任务", notes = "完成任务,任务进入下一个节点")
@ApiImplicitParams({
@ApiImplicitParam(name = "taskId", value = "任务ID", dataType = "String", paramType = "query", example = ""),
@ApiImplicitParam(name = "days", value = "请假天数", dataType = "int", paramType = "query", example = ""),
})
public RestMessgae completeTask(@RequestParam("taskId") String taskId,
@RequestParam("days") int days) {
RestMessgae restMessgae = new RestMessgae();
try {
HashMap<String, Object> variables = new HashMap<>(1);
variables.put("days", days);
taskService.complete(taskId, variables);
} catch (Exception e) {
restMessgae = RestMessgae.fail("提交失败", e.getMessage());
e.printStackTrace();
return restMessgae;
}
restMessgae = RestMessgae.fail("提交成功", taskId);
return restMessgae;
}
}
源码地址:https://github.com/xugj-gits/SpringBoot2_Activiti7
官方实例:https://community.alfresco.com/community/bpm/blog/2018/12/10/activiti-7-deep-dive-series-using-the-core-libraries
访问swagger需要输入帐号密码,这问题怎么跳过
{"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"},
密码不对呢
前端在哪呢 后台起来了
账户和秘密是多少
https://www.xugj520.cn/archives/activiti_issues.html 第三个问题
大神您好,为啥登录不上去呢 弹窗输入什么呢
看控制台
账号密码是啥了 看不出来....
https://www.xugj520.cn/archives/activiti_issues.html . 第三个问题
纠结好久了 .....能告诉下吗 账号:salaboy 密码 password? 这个不对啊
启动起来了,但是弹出框,出现一个需要输入用户名和密码,输入什么都不对?
用户名密码是???
你解决了吗 老哥
看控制台
别闹!权限那块压根就没用起来。
报错。org.activiti.engine.ActivitiObjectNotFoundException: no processes deployed with key 'myProcess_1'
at org.activiti.engine.impl.persistence.deploy.DeploymentManager.findDeployedLatestProcessDefinitionByKey(DeploymentManager.java:85) ~[activiti-engine-7.1.0.M1.jar:na]
at org.activiti.engine.impl.cmd.StartProcessInstanceCmd.execute(StartProcessInstanceCmd.java:85) ~[activiti-engine-7.1.0.M1.jar:na]
at org.activiti.engine.impl.cmd.StartProcessInstanceCmd.execute(StartProcessInstanceCmd.java:37) ~[activiti-engine-7.1.0.M1.jar:na]
at org.activiti.engine.impl.interceptor.CommandInvoker$1.run(CommandInvoker.java:37) ~[activiti-engine-7.1.0.M1.jar:na]
[ERROR] Tests run: 3, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 12.599 s
在init里发布流程,再测试
repositoryService.createDeployment().addClasspathResource("processes/testProcess.bpmn").deploy();
在 src/main/resources 下新建目录: processes/myProcess_1.bpmn