增加flowable模块

This commit is contained in:
jinqiming 2020-11-19 19:12:49 +08:00
parent dcf5314847
commit fa5c1ac507
16 changed files with 562 additions and 70 deletions

View File

@ -22,7 +22,12 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -3,6 +3,7 @@ package com.snow.web.controller.dingtalk;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.oapi.lib.aes.DingTalkEncryptor;
import com.snow.common.constant.Constants;
import com.snow.common.enums.DingTalkListenerType;
import com.snow.dingtalk.common.EventNameEnum;
import com.snow.dingtalk.sync.ISyncSysInfo;
@ -12,6 +13,7 @@ import com.snow.system.service.impl.DingtalkCallBackServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@ -31,6 +33,10 @@ public class DingTalkCallBackController {
private DingtalkCallBackServiceImpl dingtalkCallBackService;
private static final String EVENT_TYPE="EventType";
private static final String ENCRYPT="encrypt";
/**
* 钉钉回调
* @param signature
@ -49,45 +55,34 @@ public class DingTalkCallBackController {
DingtalkCallBack dingtalkCallBack=new DingtalkCallBack();
dingtalkCallBack.setFlag(true);
List<DingtalkCallBack> dingtalkCallBacks = dingtalkCallBackService.selectDingtalkCallBackList(dingtalkCallBack);
if(!CollectionUtils.isEmpty(dingtalkCallBacks)){
dingtalkCallBack=dingtalkCallBacks.get(0);
}else {
return "fail";
if(CollectionUtils.isEmpty(dingtalkCallBacks)){
return Constants.CALL_BACK_FAIL_RETURN;
}
String params = "signature:" + signature + " timestamp:" + timestamp + " nonce:" + nonce + " body:" + body;
dingtalkCallBack=dingtalkCallBacks.get(0);
try {
log.info("begin callback:" + params);
log.info("begin callback------》 signature:{},timestamp:{},nonce:{},body:{}" ,signature,timestamp,nonce,body);
DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(dingtalkCallBack.getToken(),dingtalkCallBack.getAesKey(),dingtalkCallBack.getCorpId());
// 从post请求的body中获取回调信息的加密数据进行解密处理
String encrypt = body.getString("encrypt");
String encrypt = body.getString(ENCRYPT);
String plainText = dingTalkEncryptor.getDecryptMsg(signature, timestamp.toString(), nonce, encrypt);
JSONObject callBackContent = JSON.parseObject(plainText);
// 根据回调事件类型做不同的业务处理
String eventType = callBackContent.getString("EventType");
SyncSysInfoFactory syncSysInfoFactory = new SyncSysInfoFactory();
if (DingTalkListenerType.DEPARTMENT_CREATE.getInfo().equals(eventType)) {
ISyncSysInfo iSyncSysInfo = syncSysInfoFactory.getSyncSysInfoService(DingTalkListenerType.DEPARTMENT_CREATE);
iSyncSysInfo.SyncSysInfo(DingTalkListenerType.DEPARTMENT_CREATE, callBackContent);
log.info("部门创建回调数据: " + callBackContent);
} else if (EventNameEnum.org_dept_modify.equals(eventType)) {
log.info("验证更新回调URL有效性: " + plainText);
} else if (EventNameEnum.org_dept_remove.equals(eventType)) {
// suite_ticket用于用签名形式生成accessToken(访问钉钉服务端的凭证)需要保存到应用的db
// 钉钉会定期向本callback url推送suite_ticket新值用以提升安全性
// 应用在获取到新的时值时保存db成功后返回给钉钉success加密串如本demo的return
log.info("应用suite_ticket数据推送: " + plainText);
} else {
// 其他类型事件处理
String eventType = callBackContent.getString(EVENT_TYPE);
DingTalkListenerType type = DingTalkListenerType.getType(eventType);
if(StringUtils.isEmpty(type)){
return Constants.CALL_BACK_FAIL_RETURN;
}
//调用工厂模式异步处理数据
SyncSysInfoFactory syncSysInfoFactory = new SyncSysInfoFactory();
ISyncSysInfo iSyncSysInfo = syncSysInfoFactory.getSyncSysInfoService(type);
iSyncSysInfo.SyncSysInfo(type, callBackContent);
// 返回success的加密信息表示回调处理成功
return dingTalkEncryptor.getEncryptedMap("success", timestamp, nonce);
return dingTalkEncryptor.getEncryptedMap(Constants.CALL_BACK_SUCCESS_RETURN, timestamp, nonce);
} catch (Exception e) {
//失败的情况应用的开发者应该通过告警感知并干预修复
log.error("process callback fail." + params, e);
return "fail";
//todo 失败短信或者邮件通知并记录下数据
log.error("process callback fail------》 signature:{},timestamp:{},nonce:{},body:{}" ,signature,timestamp,nonce,body, e);
return Constants.CALL_BACK_FAIL_RETURN;
}
}
}

View File

@ -0,0 +1,28 @@
package com.snow;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/10/27 9:23
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class JunitTestApplication {
@Before
public void init() {
System.out.println("SNOW_TEST begin--------------------------------------------------------");
}
@After
public void after() {
System.out.println("SNOW_TEST end----------------------------------------------------------");
}
}

View File

@ -0,0 +1,38 @@
package com.snow.flowable;
import com.alibaba.fastjson.JSON;
import com.snow.JunitTestApplication;
import com.snow.flowable.domain.ClassDeploymentDTO;
import com.snow.flowable.domain.DeploymentDTO;
import com.snow.flowable.service.impl.FlowAblePublishServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.repository.Deployment;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/19 16:02
*/
@Slf4j
public class DeploymentTests extends JunitTestApplication {
@Autowired
private FlowAblePublishServiceImpl flowAblePublishService;
@Test
public void createClassDeployment() throws Exception{
InputStream in = new BufferedInputStream(new FileInputStream("D:\\请假流程.bpmn20.xml"));
DeploymentDTO classDeploymentDTO=new DeploymentDTO();
classDeploymentDTO.setKey("snow_leave");
classDeploymentDTO.setName("请假流程");
// classDeploymentDTO.setClassPathResource("D:\\flowable\\leave.bpmn20.xml");
Deployment classDeployment = flowAblePublishService.createInputStreamDeployment(classDeploymentDTO,in);
log.info("发布结果:{}",JSON.toJSONString(classDeployment));
}
}

View File

@ -113,4 +113,12 @@ public class Constants
* 通讯录事件type_key
*/
public static final String ADDRESS_BOOK="address_book";
/**
* 钉钉回调成功返回
*/
public static final String CALL_BACK_SUCCESS_RETURN="success";
/**
* 钉钉回调失败返回
*/
public static final String CALL_BACK_FAIL_RETURN="fail";
}

View File

@ -61,4 +61,13 @@ public enum DingTalkListenerType {
return type;
}
public static DingTalkListenerType getType(String info) {
for (DingTalkListenerType dingTalkListenerType:DingTalkListenerType.values()){
if(dingTalkListenerType.getInfo().equals(info)){
return dingTalkListenerType;
}
}
return null;
}
}

View File

@ -15,13 +15,23 @@
<!-- 通用工具-->
<dependency>
<groupId>com.snow</groupId>
<artifactId>snow-common</artifactId>
<artifactId>snow-framework</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.4.0</version>
<version>6.4.1</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-json-converter</artifactId>
<version>6.4.1</version>
</dependency>
</dependencies>
</project>

View File

@ -1,39 +0,0 @@
package com.snow.flowable;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/18 19:16
*/
//@Configuration
public class ProcessEngineConfig {
/**
* ProcessEngine 配置其中DataSourceTransactionManager和DataSource自动注入
* @param dataSourceTransactionManager
* @param dataSource
* @return
*/
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public SpringProcessEngineConfiguration springProcessEngineConfiguration(DataSourceTransactionManager dataSourceTransactionManager, DataSource dataSource) {
SpringProcessEngineConfiguration springProcessEngineConfiguration = new SpringProcessEngineConfiguration();
springProcessEngineConfiguration.setDataSource(dataSource);
springProcessEngineConfiguration.setTransactionManager(dataSourceTransactionManager);
//不添加此项配置在没创建表时会抛出FlowableWrongDbException异常
springProcessEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
return springProcessEngineConfiguration;
}
}

View File

@ -0,0 +1,40 @@
package com.snow.flowable.config;
import org.flowable.common.engine.impl.EngineDeployer;
import org.flowable.engine.impl.rules.RulesDeployer;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.util.ArrayList;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/18 19:16
*/
@Configuration
public class FlowableConfig {
@Primary
@Bean(name = "processEngineConfiguration")
public SpringProcessEngineConfiguration getSpringProcessEngineConfiguration(DataSource dataSource, DataSourceTransactionManager transactionManager) {
SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
configuration.setDataSource(dataSource);
configuration.setTransactionManager(transactionManager);
configuration.setDatabaseSchemaUpdate("false");
configuration.setAsyncExecutorActivate(true);
configuration.setCustomPostDeployers(new ArrayList<EngineDeployer>(){
private static final long serialVersionUID = 4041439225480991716L;
{
add(new RulesDeployer());
}
});
return configuration;
}
}

View File

@ -0,0 +1,14 @@
package com.snow.flowable.domain;
import lombok.Data;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/19 15:13
*/
@Data
public class ClassDeploymentDTO extends DeploymentDTO {
private String classPathResource;
}

View File

@ -0,0 +1,35 @@
package com.snow.flowable.domain;
import lombok.Data;
import java.io.Serializable;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/19 15:11
*/
@Data
public class DeploymentDTO implements Serializable {
/**
* 租户ID
*/
private String tenantId;
/**
* key
*/
private String key;
/**
* 分类
*/
private String category;
/**
* 名称
*/
private String name;
/**
* 文件名
*/
private String resourceName;
}

View File

@ -0,0 +1,68 @@
package com.snow.flowable.domain;
import lombok.Data;
import org.flowable.identitylink.api.IdentityLinkInfo;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/19 17:53
*/
@Data
public class Task implements Serializable {
private String id;
String getName;
String getDescription;
int getPriority;
String getOwner;
String getAssignee;
String getProcessInstanceId;
String getExecutionId;
String getTaskDefinitionId;
String getProcessDefinitionId;
String getScopeId;
String getSubScopeId;
String getScopeType;
String getScopeDefinitionId;
Date getCreateTime;
String getTaskDefinitionKey;
Date getDueDate;
String getCategory;
String getParentTaskId;
String getTenantId;
String getFormKey;
Map<String, Object> getTaskLocalVariables;
Map<String, Object> getProcessVariables;
List<? extends IdentityLinkInfo> getIdentityLinks;
Date getClaimTime;
}

View File

@ -0,0 +1,52 @@
package com.snow.flowable.service;
import com.snow.flowable.domain.ClassDeploymentDTO;
import com.snow.flowable.domain.DeploymentDTO;
import org.flowable.engine.repository.Deployment;
import java.io.InputStream;
/**
* @author qimingjin
* @Title: 发布接口
* @Description:
* @date 2020/11/19 14:57
*/
public interface FlowAblePublishService {
/**
*class部署
* @return
*/
Deployment createClassDeployment(ClassDeploymentDTO classDeploymentDTO);
/**
* 文本部署
* @param filePath
* @return
*/
Deployment createStringDeployment(DeploymentDTO deploymentDTO,String filePath);
/**
* 流部署
* @param deploymentDTO
* @param inputStream
* @return
*/
Deployment createInputStreamDeployment(DeploymentDTO deploymentDTO,InputStream inputStream);
/**
* 压缩流部署
* @param deploymentDTO
* @param inputZipStream
* @return
*/
Deployment createZipInputStreamDeployment(DeploymentDTO deploymentDTO,InputStream inputZipStream);
/**
* 字节形式部署
* @param deploymentDTO
* @param bytes
* @return
*/
Deployment createBytesDeployment(DeploymentDTO deploymentDTO,byte[] bytes );
}

View File

@ -0,0 +1,41 @@
package com.snow.flowable.service;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.util.List;
import java.util.Map;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/19 17:27
*/
public interface FlowableService {
/**
* 通过processDefinitionKey开始流程
* @param processDefinitionKey
* @return
*/
ProcessInstance startProcessInstanceByKey(String processDefinitionKey);
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey);
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables);
ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String tenantId);
/**
* 根据流程实例查询任务
* @param processInstanceId
* @return
*/
List<TaskEntity> findTasksByProcessInstanceId(String processInstanceId);
TaskEntity getTask(String id);
List<TaskEntity> findTasksByUserId(String userId);
}

View File

@ -0,0 +1,108 @@
package com.snow.flowable.service.impl;
import com.snow.flowable.domain.ClassDeploymentDTO;
import com.snow.flowable.domain.DeploymentDTO;
import com.snow.flowable.service.FlowAblePublishService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.repository.Deployment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.util.zip.ZipInputStream;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/19 14:59
*/
@Service
@Slf4j
public class FlowAblePublishServiceImpl implements FlowAblePublishService {
/**
* 仓库服务类
* 仓库指的是流程第定义文档的两个文件bpmn文件和流程图片
* DeploymentBuilder:用来定义流程部署的相关参数
*
* ProcessDefinitionQuery:用来构造查询流程定义相关参数
*
* NativeProcessDefinitionQuery:用来构造本地Sql查询流程定义相关参数
*
* DeploymentQuery:用来构造查询部署对象相关参数
*/
@Autowired
private RepositoryService repositoryService;
/**
* class部署
* @return
*/
@Override
public Deployment createClassDeployment(ClassDeploymentDTO classDeploymentDTO) {
Deployment deploy = repositoryService.createDeployment()
.tenantId(classDeploymentDTO.getTenantId())
.category(classDeploymentDTO.getCategory())
.name(classDeploymentDTO.getName())
.key(classDeploymentDTO.getKey())
.addClasspathResource(classDeploymentDTO.getClassPathResource())
.deploy();
return deploy;
}
@Override
public Deployment createStringDeployment(DeploymentDTO deploymentDTO, String filePath) {
String text= IoUtil.readFileAsString(filePath);
Deployment deploy = repositoryService.createDeployment()
.tenantId(deploymentDTO.getTenantId())
.category(deploymentDTO.getCategory())
.name(deploymentDTO.getName())
.key(deploymentDTO.getKey())
.addString(filePath,text)
.deploy();
return deploy;
}
@Override
public Deployment createInputStreamDeployment(DeploymentDTO deploymentDTO, InputStream inputStream) {
Deployment deploy = repositoryService.createDeployment()
.tenantId(deploymentDTO.getTenantId())
.category(deploymentDTO.getCategory())
.name(deploymentDTO.getName())
.key(deploymentDTO.getKey())
.addInputStream(deploymentDTO.getResourceName(),inputStream)
.deploy();
return deploy;
}
@Override
public Deployment createZipInputStreamDeployment(DeploymentDTO deploymentDTO, InputStream inputZipStream) {
ZipInputStream zipInputStream = new ZipInputStream(inputZipStream);
Deployment deploy = repositoryService.createDeployment()
.tenantId(deploymentDTO.getTenantId())
.category(deploymentDTO.getCategory())
.name(deploymentDTO.getName())
.key(deploymentDTO.getKey())
.addZipInputStream(zipInputStream)
.deploy();
return deploy;
}
@Override
public Deployment createBytesDeployment(DeploymentDTO deploymentDTO, byte[] bytes) {
Deployment deploy = repositoryService.createDeployment()
.tenantId(deploymentDTO.getTenantId())
.category(deploymentDTO.getCategory())
.name(deploymentDTO.getName())
.key(deploymentDTO.getKey())
.addBytes(deploymentDTO.getResourceName(),bytes)
.deploy();
return deploy;
}
}

View File

@ -0,0 +1,80 @@
package com.snow.flowable.service.impl;
import com.snow.flowable.service.FlowableService;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author qimingjin
* @Title:
* @Description:
* @date 2020/11/19 17:27
*/
@Slf4j
@Service
public class FlowableServiceImpl implements FlowableService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Override
public ProcessInstance startProcessInstanceByKey(String processDefinitionKey) {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
return processInstance;
}
@Override
public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey) {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey);
return processInstance;
}
@Override
public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables) {
return null;
}
@Override
public ProcessInstance startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables) {
return null;
}
@Override
public ProcessInstance startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String tenantId) {
return null;
}
@Override
public List<TaskEntity> findTasksByProcessInstanceId(String processInstanceId) {
return null;
}
@Override
public TaskEntity getTask(String id) {
return null;
}
@Override
public List<TaskEntity> findTasksByUserId(String userId) {
List<Task> tasks = taskService.createTaskQuery()
.or().taskCandidateOrAssigned(userId)
.or().taskCandidateGroupIn(new ArrayList<>())
.endOr()
.listPage(1, 10);
return null;
}
}