SpringBoot整合Activiti的項目中實現(xiàn)抄送功能
1、實現(xiàn)思路
在Activiti工作流中,抄送功能通常不是直接提供的,但可以通過擴展來實現(xiàn)。抄送功能可以理解為將某個任務的信息發(fā)送給相關人員,而不需要他們直接處理任務。在Spring Boot整合Activiti的項目中,我們可以通過以下方式實現(xiàn)抄送功能:
- 自定義抄送表:記錄抄送的任務、抄送給誰、抄送時間等信息。
- 在任務創(chuàng)建或完成時觸發(fā)抄送邏輯,將任務信息插入抄送表。
- 提供接口供用戶查看自己被抄送的任務。
在Spring Boot項目中整合Activiti工作流的抄送功能,可以通過以下方案實現(xiàn):
2、在Spring Boot中集成Activiti
在pom.xml中添加Activiti依賴:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M6</version>
</dependency>2.1、設計抄送表
創(chuàng)建抄送表,表結(jié)構(gòu)如下:
CREATE TABLE `act_cc_task` ( `id` varchar(64) NOT NULL COMMENT '主鍵', `task_id` varchar(64) DEFAULT NULL COMMENT '任務ID', `proc_inst_id` varchar(64) DEFAULT NULL COMMENT '流程實例ID', `proc_def_id` varchar(64) DEFAULT NULL COMMENT '流程定義ID', `title` varchar(255) DEFAULT NULL COMMENT '抄送標題', `content` text COMMENT '抄送內(nèi)容', `from_user_id` varchar(64) DEFAULT NULL COMMENT '發(fā)起人', `to_user_ids` text COMMENT '接收人(多個用逗號分隔)', `status` int(1) DEFAULT '0' COMMENT '狀態(tài)(0:未讀,1:已讀)', `create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時間', `read_time` datetime DEFAULT NULL COMMENT '讀取時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.2、抄送實體類
@Data
@TableName("act_cc_task")
public class CcTask {
@TableId(type = IdType.ASSIGN_ID)
private String id;
private String taskId;
private String procInstId;
private String procDefId;
private String title;
private String content;
private String fromUserId;
private String toUserIds; // 多個用戶用逗號分隔
private Integer status;
private Date createTime;
private Date readTime;
@TableField(exist = false)
private List<String> toUserList; // 接收人列表
}2.3、實現(xiàn)抄送服務
創(chuàng)建一個抄送服務,用于處理抄送邏輯。例如,在任務完成時,將任務抄送給指定人員。
服務接口:
public interface CcTaskService {
/**
* 創(chuàng)建抄送任務
*/
void createCcTask(String taskId, List<String> toUserIds,
String title, String content);
/**
* 獲取用戶的抄送列表
*/
PageInfo<CcTask> getUserCcTasks(String userId, Integer pageNum,
Integer pageSize, Integer status);
/**
* 標記為已讀
*/
void markAsRead(String ccTaskId, String userId);
/**
* 批量抄送
*/
void batchCcTask(List<String> taskIds, List<String> toUserIds,
String reason);
}服務實現(xiàn):
在任務完成時觸發(fā)抄送,可以在任務完成事件監(jiān)聽器中觸發(fā)抄送。例如,創(chuàng)建一個任務監(jiān)聽器
@Service
@Slf4j
public class CcTaskServiceImpl implements CcTaskService {
@Autowired
private CcTaskMapper ccTaskMapper;
@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
@Override
@Transactional
public void createCcTask(String taskId, List<String> toUserIds,
String title, String content) {
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
if (task == null) {
throw new BusinessException("任務不存在");
}
// 獲取當前登錄用戶
String currentUserId = SecurityUtils.getCurrentUserId();
CcTask ccTask = new CcTask();
ccTask.setId(IdUtil.fastSimpleUUID());
ccTask.setTaskId(taskId);
ccTask.setProcInstId(task.getProcessInstanceId());
ccTask.setProcDefId(task.getProcessDefinitionId());
ccTask.setTitle(title);
ccTask.setContent(content);
ccTask.setFromUserId(currentUserId);
ccTask.setToUserIds(StringUtils.join(toUserIds, ","));
ccTask.setStatus(0);
ccTask.setCreateTime(new Date());
ccTaskMapper.insert(ccTask);
// 發(fā)送通知(可集成消息推送)
sendNotification(ccTask);
}
/**
* 使用監(jiān)聽器自動抄送
*/
@Component
public static class TaskCcListener implements TaskListener {
@Autowired
private CcTaskService ccTaskService;
@Override
public void notify(DelegateTask delegateTask) {
String eventName = delegateTask.getEventName();
// 在任務創(chuàng)建時自動抄送
if ("create".equals(eventName)) {
Object ccUsers = delegateTask.getVariable("ccUsers");
if (ccUsers != null) {
List<String> userIds = (List<String>) ccUsers;
if (!CollectionUtils.isEmpty(userIds)) {
String taskName = delegateTask.getName();
String content = String.format("任務【%s】需要您知曉", taskName);
ccTaskService.createCcTask(
delegateTask.getId(),
userIds,
taskName,
content
);
}
}
}
}
}
}然后在流程定義中,在任務完成事件上綁定這個監(jiān)聽器??梢栽贐PMN文件中配置,也可以通過代碼配置。
控制器層:
@RestController
@RequestMapping("/api/cc")
@Api(tags = "抄送管理")
public class CcTaskController {
@Autowired
private CcTaskService ccTaskService;
@PostMapping("/create")
@ApiOperation("創(chuàng)建抄送")
public Result createCcTask(@RequestBody CcTaskCreateDTO dto) {
ccTaskService.createCcTask(
dto.getTaskId(),
dto.getToUserIds(),
dto.getTitle(),
dto.getContent()
);
return Result.success();
}
@GetMapping("/list")
@ApiOperation("獲取抄送列表")
public Result<PageInfo<CcTask>> getCcList(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) Integer status) {
String userId = SecurityUtils.getCurrentUserId();
PageInfo<CcTask> result = ccTaskService.getUserCcTasks(
userId, pageNum, pageSize, status
);
return Result.success(result);
}
@PostMapping("/read/{id}")
@ApiOperation("標記已讀")
public Result markAsRead(@PathVariable String id) {
String userId = SecurityUtils.getCurrentUserId();
ccTaskService.markAsRead(id, userId);
return Result.success();
}
}3、前端集成
3.1、抄送組件
<template>
<div class="cc-task-container">
<!-- 抄送按鈕 -->
<el-button type="text" @click="showCcDialog">
<i class="el-icon-s-promotion"></i> 抄送
</el-button>
<!-- 抄送對話框 -->
<el-dialog title="任務抄送" :visible.sync="ccDialogVisible">
<el-form :model="ccForm">
<el-form-item label="接收人">
<el-select
v-model="ccForm.userIds"
multiple
filterable
placeholder="請選擇接收人">
<el-option
v-for="user in userList"
:key="user.id"
:label="user.name"
:value="user.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="抄送說明">
<el-input
type="textarea"
v-model="ccForm.content"
placeholder="請輸入抄送說明"
rows="4">
</el-input>
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="ccDialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitCc">確定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
taskId: String,
taskName: String
},
data() {
return {
ccDialogVisible: false,
userList: [],
ccForm: {
userIds: [],
content: ''
}
}
},
methods: {
showCcDialog() {
this.ccDialogVisible = true
this.loadUserList()
},
async loadUserList() {
const res = await this.$api.user.getUserList()
this.userList = res.data
},
async submitCc() {
const params = {
taskId: this.taskId,
toUserIds: this.ccForm.userIds,
title: `任務【${this.taskName}】抄送`,
content: this.ccForm.content
}
await this.$api.cc.create(params)
this.$message.success('抄送成功')
this.ccDialogVisible = false
this.$emit('cc-success')
}
}
}
</script>3.2、抄送列表頁面
<template>
<div class="cc-task-list">
<el-tabs v-model="activeStatus" @tab-click="handleTabClick">
<el-tab-pane label="未讀" name="0"></el-tab-pane>
<el-tab-pane label="已讀" name="1"></el-tab-pane>
<el-tab-pane label="全部" name=""></el-tab-pane>
</el-tabs>
<el-table :data="ccList" v-loading="loading">
<el-table-column prop="title" label="標題" width="200">
<template slot-scope="{row}">
<span :class="{'unread': row.status === 0}">
{{ row.title }}
</span>
</template>
</el-table-column>
<el-table-column prop="content" label="內(nèi)容"></el-table-column>
<el-table-column prop="fromUserName" label="發(fā)起人" width="100">
</el-table-column>
<el-table-column prop="createTime" label="時間" width="180">
<template slot-scope="{row}">
{{ formatDate(row.createTime) }}
</template>
</el-table-column>
<el-table-column label="操作" width="120">
<template slot-scope="{row}">
<el-button
v-if="row.status === 0"
type="text"
@click="markAsRead(row.id)">
標記已讀
</el-button>
<el-button
type="text"
@click="viewProcess(row.procInstId)">
查看流程
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pagination.pageNum"
:page-sizes="[10, 20, 50, 100]"
:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
</template>前端可以調(diào)用上述接口展示抄送列表,并允許用戶標記已讀。
注意事項
- 抄送功能可以根據(jù)實際需求進行擴展,例如增加抄送類型(任務創(chuàng)建時抄送、任務完成時抄送等)。
- 抄送人員可以從任務變量、流程變量、固定配置或者從用戶選擇中獲取。
- 抄送任務可能不需要處理,但需要記錄,因此抄送表的設計可以根據(jù)業(yè)務需求調(diào)整。
4、高級功能擴展
4.1、郵件通知集成
@Component
public class EmailCcNotifier {
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String from;
public void sendCcNotification(CcTask ccTask, User user) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(user.getEmail());
message.setSubject("工作流抄送通知:" + ccTask.getTitle());
message.setText(buildEmailContent(ccTask));
mailSender.send(message);
}
private String buildEmailContent(CcTask ccTask) {
return String.format(
"您收到一條工作流抄送:\n" +
"標題:%s\n" +
"內(nèi)容:%s\n" +
"發(fā)起人:%s\n" +
"時間:%s\n" +
"請登錄系統(tǒng)查看詳情。",
ccTask.getTitle(),
ccTask.getContent(),
ccTask.getFromUserId(),
DateUtil.formatDateTime(ccTask.getCreateTime())
);
}
}4.2、消息推送集成(WebSocket)
@ServerEndpoint("/websocket/cc")
@Component
public class CcWebSocket {
private static Map<String, Session> sessions = new ConcurrentHashMap<>();
@OnOpen
public void onOpen(Session session) {
String userId = getUserIdFromSession(session);
sessions.put(userId, session);
}
/**
* 向指定用戶推送抄送消息
*/
public static void sendCcMessage(String userId, CcTask ccTask) {
Session session = sessions.get(userId);
if (session != null && session.isOpen()) {
try {
String message = JSON.toJSONString(
Map.of("type", "cc", "data", ccTask)
);
session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("發(fā)送WebSocket消息失敗", e);
}
}
}
}4.3、 抄送規(guī)則配置
@Component
public class CcRuleEngine {
/**
* 根據(jù)規(guī)則自動抄送
* 規(guī)則示例:
* 1. 特定節(jié)點自動抄送
* 2. 金額大于閾值抄送
* 3. 特定部門任務抄送
*/
public List<String> getCcUsersByRule(
String processDefinitionId,
String taskDefinitionKey,
Map<String, Object> variables) {
List<String> userIds = new ArrayList<>();
// 示例:根據(jù)任務節(jié)點配置抄送
if ("approve".equals(taskDefinitionKey)) {
// 審批節(jié)點抄送給部門經(jīng)理
String deptId = (String) variables.get("deptId");
userIds.addAll(getDeptManagers(deptId));
}
// 示例:根據(jù)金額閾值抄送
Double amount = (Double) variables.get("amount");
if (amount != null && amount > 10000) {
userIds.addAll(getFinanceUsers());
}
return userIds.stream().distinct().collect(Collectors.toList());
}
}4.4、 應用配置文件
# application.yml
activiti:
cc:
enabled: true
# 是否啟用郵件通知
email-notify: true
# 是否啟用站內(nèi)信
message-notify: true
# 默認抄送人(角色)
default-cc-roles: ROLE_DEPT_MANAGER,ROLE_ADMIN4.5、 流程定義中的抄送配置
<!-- 在BPMN文件中添加抄送配置 -->
<userTask id="approveTask" name="審批任務">
<extensionElements>
<activiti:taskListener event="create"
class="com.xxx.listener.AutoCcTaskListener"/>
<activiti:formProperty id="ccUsers"
name="抄送人" type="users"/>
</extensionElements>
</userTask>5、總結(jié)
抄送功能的實現(xiàn)要點:
- 數(shù)據(jù)持久化:設計抄送表記錄抄送信息
- 業(yè)務邏輯:提供抄送CRUD服務
- 流程集成:通過監(jiān)聽器自動觸發(fā)抄送
- 用戶通知:集成多種通知方式(站內(nèi)信、郵件、推送)
- 權(quán)限控制:確保用戶只能操作自己的抄送記錄
- 配置靈活:支持規(guī)則引擎和動態(tài)配置
這種實現(xiàn)方式既保持了工作流引擎的純凈性,又通過擴展實現(xiàn)了業(yè)務需要的抄送功能。
到此這篇關于SpringBoot整合Activiti的項目中實現(xiàn)抄送功能的文章就介紹到這了,更多相關SpringBoot Activiti抄送內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
WebUploader+SpringMVC實現(xiàn)文件上傳功能
WebUploader是由Baidu團隊開發(fā)的一個簡單的以HTML5為主,F(xiàn)LASH為輔的現(xiàn)代文件上傳組件。這篇文章主要介紹了WebUploader+SpringMVC實現(xiàn)文件上傳功能,需要的朋友可以參考下2017-06-06
SpringCloud Config使用本地倉庫及map注入
這篇文章主要介紹了SpringCloud Config使用本地倉庫及map注入,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09
使用BigDecimal進行精確運算(實現(xiàn)加減乘除運算)
這篇文章主要介紹了如何使用BigDecimal進行精確運算,最后提供了一個工具類,該工具類提供加,減,乘,除運算2013-11-11
基于Spring Security前后端分離的權(quán)限控制系統(tǒng)問題
本文給大家分享基于Spring Security前后端分離的權(quán)限控制系統(tǒng)問題,需要了解權(quán)限如何加載,權(quán)限匹配規(guī)則和登錄的實現(xiàn)代碼,對Spring Security權(quán)限控制系統(tǒng)相關知識感興趣的朋友一起看看吧2021-06-06
Reactor 多任務并發(fā)執(zhí)行且結(jié)果按順序返回第一個
這篇文章主要介紹了Reactor 多任務并發(fā)執(zhí)行且結(jié)果按順序返回第一個,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下2022-09-09
Java class文件格式之數(shù)據(jù)類型(二)_動力節(jié)點Java學院整理
這篇文章主要介紹了Java class文件格式之數(shù)據(jù)類型(二)的相關資料,需要的朋友可以參考下2017-06-06

