news 2026/4/3 3:48:05

Spring Boot整合Activiti的项目中实现抄送功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot整合Activiti的项目中实现抄送功能

目录

1、实现思路

2、在Spring Boot中集成Activiti

2.1、设计抄送表

2.2、抄送实体类

2.3、实现抄送服务

3、前端集成

3.1、抄送组件

3.2、抄送列表页面

4、高级功能扩展

4.1、邮件通知集成

4.2、消息推送集成(WebSocket)

4.3、 抄送规则配置

4.4、 应用配置文件

4.5、 流程定义中的抄送配置

5、总结


1、实现思路

在Activiti工作流中,抄送功能通常不是直接提供的,但可以通过扩展来实现。抄送功能可以理解为将某个任务的信息发送给相关人员,而不需要他们直接处理任务。在Spring Boot整合Activiti的项目中,我们可以通过以下方式实现抄送功能:

  1. 自定义抄送表:记录抄送的任务、抄送给谁、抄送时间等信息。
  2. 在任务创建或完成时触发抄送逻辑,将任务信息插入抄送表。
  3. 提供接口供用户查看自己被抄送的任务。

在Spring Boot项目中整合Activiti工作流的抄送功能,可以通过以下方案实现:

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、设计抄送表

创建抄送表,表结构如下:

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 '抄送内容', `from_user_id` varchar(64) DEFAULT NULL COMMENT '发起人', `to_user_ids` text COMMENT '接收人(多个用逗号分隔)', `status` int(1) DEFAULT '0' COMMENT '状态(0:未读,1:已读)', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `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、实现抄送服务

创建一个抄送服务,用于处理抄送逻辑。例如,在任务完成时,将任务抄送给指定人员。

服务接口:

public interface CcTaskService { /** * 创建抄送任务 */ 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); }

服务实现:

在任务完成时触发抄送,可以在任务完成事件监听器中触发抄送。例如,创建一个任务监听器

@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); // 发送通知(可集成消息推送) sendNotification(ccTask); } /** * 使用监听器自动抄送 */ @Component public static class TaskCcListener implements TaskListener { @Autowired private CcTaskService ccTaskService; @Override public void notify(DelegateTask delegateTask) { String eventName = delegateTask.getEventName(); // 在任务创建时自动抄送 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 ); } } } } } }

然后在流程定义中,在任务完成事件上绑定这个监听器。可以在BPMN文件中配置,也可以通过代码配置。

控制器层:

@RestController @RequestMapping("/api/cc") @Api(tags = "抄送管理") public class CcTaskController { @Autowired private CcTaskService ccTaskService; @PostMapping("/create") @ApiOperation("创建抄送") 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="内容"></el-table-column> <el-table-column prop="fromUserName" label="发起人" 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>

前端可以调用上述接口展示抄送列表,并允许用户标记已读。

注意事项

  • 抄送功能可以根据实际需求进行扩展,例如增加抄送类型(任务创建时抄送、任务完成时抄送等)。

  • 抄送人员可以从任务变量、流程变量、固定配置或者从用户选择中获取。

  • 抄送任务可能不需要处理,但需要记录,因此抄送表的设计可以根据业务需求调整。

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" + "内容:%s\n" + "发起人:%s\n" + "时间:%s\n" + "请登录系统查看详情。", 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("发送WebSocket消息失败", e); } } } }

4.3、 抄送规则配置

@Component public class CcRuleEngine { /** * 根据规则自动抄送 * 规则示例: * 1. 特定节点自动抄送 * 2. 金额大于阈值抄送 * 3. 特定部门任务抄送 */ public List<String> getCcUsersByRule( String processDefinitionId, String taskDefinitionKey, Map<String, Object> variables) { List<String> userIds = new ArrayList<>(); // 示例:根据任务节点配置抄送 if ("approve".equals(taskDefinitionKey)) { // 审批节点抄送给部门经理 String deptId = (String) variables.get("deptId"); userIds.addAll(getDeptManagers(deptId)); } // 示例:根据金额阈值抄送 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 # 是否启用站内信 message-notify: true # 默认抄送人(角色) default-cc-roles: ROLE_DEPT_MANAGER,ROLE_ADMIN

4.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、总结

抄送功能的实现要点:

  1. 数据持久化:设计抄送表记录抄送信息

  2. 业务逻辑:提供抄送CRUD服务

  3. 流程集成:通过监听器自动触发抄送

  4. 用户通知:集成多种通知方式(站内信、邮件、推送)

  5. 权限控制:确保用户只能操作自己的抄送记录

  6. 配置灵活:支持规则引擎和动态配置

这种实现方式既保持了工作流引擎的纯净性,又通过扩展实现了业务需要的抄送功能。


“人的一生会经历很多痛苦,但回头想想,都是传奇”。



版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/1 11:57:39

Simditor:轻量级所见即所得编辑器的完整指南

Simditor&#xff1a;轻量级所见即所得编辑器的完整指南 【免费下载链接】simditor An Easy and Fast WYSIWYG Editor 项目地址: https://gitcode.com/gh_mirrors/si/simditor Simditor是一款专为现代Web应用设计的轻量级所见即所得编辑器&#xff0c;以其简洁的界面设计…

作者头像 李华
网站建设 2026/4/2 4:33:34

如何快速在ThinkPad X230上安装macOS:终极Hackintosh指南

ThinkPad X230作为一款经典的商务笔记本电脑&#xff0c;凭借其出色的性能和稳定的硬件配置&#xff0c;成为Hackintosh爱好者的热门选择。本教程将带你一步步完成在X230上安装macOS的全过程&#xff0c;无需复杂的技术知识即可轻松上手。 【免费下载链接】X230-Hackintosh REA…

作者头像 李华
网站建设 2026/4/1 7:45:20

HYPE分布式水文模型建模方法与案例分析实践技术应用

HYPE(Hydrological Predictions for the Environment, HYPE)是由瑞典皇家水文气象局&#xff08;SMHI&#xff09;在HBV和HBV-NP模型基础上开发的新一代分布式水文模型&#xff0c;已经在全球众多地区得到广泛应用。该模型功能强大且简单易用&#xff0c; 能满足在无测量数据时…

作者头像 李华
网站建设 2026/4/3 2:43:08

摆脱局域网!Logseq 搭配cpolar公网访问让笔记管理更自由

前言&#xff1a;Logseq 的核心功能是帮助用户构建结构化知识库&#xff0c;通过双向链接将零散笔记关联起来&#xff0c;支持本地文件夹存储和多格式导出&#xff0c;无论是写日记、列计划还是整理专业资料&#xff0c;都能快速找到内容间的联系。 作为每天都用的笔记工具&…

作者头像 李华
网站建设 2026/4/1 3:10:39

3步快速配置Obsidian极致美化方案:从新手到专家的完全指南

3步快速配置Obsidian极致美化方案&#xff1a;从新手到专家的完全指南 【免费下载链接】awesome-obsidian &#x1f576;️ Awesome stuff for Obsidian 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-obsidian 想要打造一个既美观又高效的Obsidian笔记环境吗&a…

作者头像 李华