垅上泷 發表於 2026-1-9 08:32:17

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

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>1、实现思路</li><li>2、在Spring Boot中集成Activiti</li><ul class="second_class_ul"><li>2.1、设计抄送表</li><li>2.2、抄送实体类</li><li>2.3、实现抄送服务</li></ul><li>3、前端集成</li><ul class="second_class_ul"><li>3.1、抄送组件</li><li>3.2、抄送列表页面</li></ul><li>4、高级功能扩展</li><ul class="second_class_ul"><li>4.1、邮件通知集成</li><li>4.2、消息推送集成(WebSocket)</li><li>4.3、&nbsp;抄送规则配置</li><li>4.4、 应用配置文件</li><li>4.5、&nbsp;流程定义中的抄送配置</li></ul><li>5、总结</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>1、实现思路</h2>
<p>在Activiti工作流中,抄送功能通常不是直接提供的,但可以通过扩展来实现。抄送功能可以理解为将某个任务的信息发送给相关人员,而不需要他们直接处理任务。在Spring Boot整合Activiti的项目中,我们可以通过以下方式实现抄送功能:</p>
<ol><li>自定义抄送表:记录抄送的任务、抄送给谁、抄送时间等信息。</li><li>在任务创建或完成时触发抄送逻辑,将任务信息插入抄送表。</li><li>提供接口供用户查看自己被抄送的任务。</li></ol>
<p>在Spring Boot项目中整合Activiti工作流的抄送功能,可以通过以下方案实现:</p>
<p class="maodian"></p><h2>2、在Spring Boot中集成Activiti</h2>
<p>在<code>pom.xml</code>中添加Activiti依赖:</p>
<div class="jb51code"><pre class="brush:xml;">&lt;dependency&gt;
    &lt;groupId&gt;org.activiti&lt;/groupId&gt;
    &lt;artifactId&gt;activiti-spring-boot-starter&lt;/artifactId&gt;
    &lt;version&gt;7.1.0.M6&lt;/version&gt;
&lt;/dependency&gt;</pre></div>
<p class="maodian"></p><h3>2.1、设计抄送表</h3>
<p>创建抄送表,表结构如下:</p>
<div class="jb51code"><pre class="brush:sql;">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;</pre></div>
<p class="maodian"></p><h3>2.2、抄送实体类</h3>
<div class="jb51code"><pre class="brush:java;">@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&lt;String&gt; toUserList;// 接收人列表
}</pre></div>
<p class="maodian"></p><h3>2.3、实现抄送服务</h3>
<p>创建一个抄送服务,用于处理抄送逻辑。例如,在任务完成时,将任务抄送给指定人员。</p>
<p>服务接口:</p>
<div class="jb51code"><pre class="brush:java;">public interface CcTaskService {
   
    /**
   * 创建抄送任务
   */
    void createCcTask(String taskId, List&lt;String&gt; toUserIds,
                     String title, String content);
   
    /**
   * 获取用户的抄送列表
   */
    PageInfo&lt;CcTask&gt; getUserCcTasks(String userId, Integer pageNum,
                                 Integer pageSize, Integer status);
   
    /**
   * 标记为已读
   */
    void markAsRead(String ccTaskId, String userId);
   
    /**
   * 批量抄送
   */
    void batchCcTask(List&lt;String&gt; taskIds, List&lt;String&gt; toUserIds,
                  String reason);
}</pre></div>
<p>服务实现:</p>
<p>在任务完成时触发抄送,可以在任务完成事件监听器中触发抄送。例如,创建一个任务监听器</p>
<div class="jb51code"><pre class="brush:java;">@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&lt;String&gt; 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&lt;String&gt; userIds = (List&lt;String&gt;) ccUsers;
                  if (!CollectionUtils.isEmpty(userIds)) {
                        String taskName = delegateTask.getName();
                        String content = String.format("任务【%s】需要您知晓", taskName);
                        
                        ccTaskService.createCcTask(
                            delegateTask.getId(),
                            userIds,
                            taskName,
                            content
                        );
                  }
                }
            }
      }
    }
}</pre></div>
<p>然后在流程定义中,在任务完成事件上绑定这个监听器。可以在BPMN文件中配置,也可以通过代码配置。</p>
<p>控制器层:</p>
<div class="jb51code"><pre class="brush:java;">@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&lt;PageInfo&lt;CcTask&gt;&gt; getCcList(
            @RequestParam(defaultValue = "1") Integer pageNum,
            @RequestParam(defaultValue = "10") Integer pageSize,
            @RequestParam(required = false) Integer status) {
      
      String userId = SecurityUtils.getCurrentUserId();
      PageInfo&lt;CcTask&gt; 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();
    }
}</pre></div>
<p class="maodian"></p><h2>3、前端集成</h2>
<p class="maodian"></p><h3>3.1、抄送组件</h3>
<div class="jb51code"><pre class="brush:js;">&lt;template&gt;
&lt;div class="cc-task-container"&gt;
    &lt;!-- 抄送按钮 --&gt;
    &lt;el-button type="text" @click="showCcDialog"&gt;
      &lt;i class="el-icon-s-promotion"&gt;&lt;/i&gt; 抄送
    &lt;/el-button&gt;
   
    &lt;!-- 抄送对话框 --&gt;
    &lt;el-dialog title="任务抄送" :visible.sync="ccDialogVisible"&gt;
      &lt;el-form :model="ccForm"&gt;
      &lt;el-form-item label="接收人"&gt;
          &lt;el-select
            v-model="ccForm.userIds"
            multiple
            filterable
            placeholder="请选择接收人"&gt;
            &lt;el-option
            v-for="user in userList"
            :key="user.id"
            :label="user.name"
            :value="user.id"&gt;
            &lt;/el-option&gt;
          &lt;/el-select&gt;
      &lt;/el-form-item&gt;
      
      &lt;el-form-item label="抄送说明"&gt;
          &lt;el-input
            type="textarea"
            v-model="ccForm.content"
            placeholder="请输入抄送说明"
            rows="4"&gt;
          &lt;/el-input&gt;
      &lt;/el-form-item&gt;
      &lt;/el-form&gt;
      
      &lt;div slot="footer"&gt;
      &lt;el-button @click="ccDialogVisible = false"&gt;取消&lt;/el-button&gt;
      &lt;el-button type="primary" @click="submitCc"&gt;确定&lt;/el-button&gt;
      &lt;/div&gt;
    &lt;/el-dialog&gt;
&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
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')
    }
}
}
&lt;/script&gt;</pre></div>
<p class="maodian"></p><h3>3.2、抄送列表页面</h3>
<div class="jb51code"><pre class="brush:js;">&lt;template&gt;
&lt;div class="cc-task-list"&gt;
    &lt;el-tabs v-model="activeStatus" @tab-click="handleTabClick"&gt;
      &lt;el-tab-pane label="未读" name="0"&gt;&lt;/el-tab-pane&gt;
      &lt;el-tab-pane label="已读" name="1"&gt;&lt;/el-tab-pane&gt;
      &lt;el-tab-pane label="全部" name=""&gt;&lt;/el-tab-pane&gt;
    &lt;/el-tabs&gt;
   
    &lt;el-table :data="ccList" v-loading="loading"&gt;
      &lt;el-table-column prop="title" label="标题" width="200"&gt;
      &lt;template slot-scope="{row}"&gt;
          &lt;span :class="{'unread': row.status === 0}"&gt;
            {{ row.title }}
          &lt;/span&gt;
      &lt;/template&gt;
      &lt;/el-table-column&gt;
      
      &lt;el-table-column prop="content" label="内容"&gt;&lt;/el-table-column&gt;
      
      &lt;el-table-column prop="fromUserName" label="发起人" width="100"&gt;
      &lt;/el-table-column&gt;
      
      &lt;el-table-column prop="createTime" label="时间" width="180"&gt;
      &lt;template slot-scope="{row}"&gt;
          {{ formatDate(row.createTime) }}
      &lt;/template&gt;
      &lt;/el-table-column&gt;
      
      &lt;el-table-column label="操作" width="120"&gt;
      &lt;template slot-scope="{row}"&gt;
          &lt;el-button
            v-if="row.status === 0"
            type="text"
            @click="markAsRead(row.id)"&gt;
            标记已读
          &lt;/el-button&gt;
          &lt;el-button
            type="text"
            @click="viewProcess(row.procInstId)"&gt;
            查看流程
          &lt;/el-button&gt;
      &lt;/template&gt;
      &lt;/el-table-column&gt;
    &lt;/el-table&gt;
   
    &lt;el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="pagination.pageNum"
      :page-sizes=""
      :page-size="pagination.pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="pagination.total"&gt;
    &lt;/el-pagination&gt;
&lt;/div&gt;
&lt;/template&gt;</pre></div>
<p>前端可以调用上述接口展示抄送列表,并允许用户标记已读。</p>
<p>注意事项</p>
<ul><li>抄送功能可以根据实际需求进行扩展,例如增加抄送类型(任务创建时抄送、任务完成时抄送等)。</li><li>抄送人员可以从任务变量、流程变量、固定配置或者从用户选择中获取。</li><li>抄送任务可能不需要处理,但需要记录,因此抄送表的设计可以根据业务需求调整。</li></ul>
<p class="maodian"></p><h2>4、高级功能扩展</h2>
<p class="maodian"></p><h3>4.1、邮件通知集成</h3>
<div class="jb51code"><pre class="brush:java;">@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())
      );
    }
}</pre></div>
<p class="maodian"></p><h3>4.2、消息推送集成(WebSocket)</h3>
<div class="jb51code"><pre class="brush:java;">@ServerEndpoint("/websocket/cc")
@Component
public class CcWebSocket {
   
    private static Map&lt;String, Session&gt; sessions = new ConcurrentHashMap&lt;&gt;();
   
    @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 &amp;&amp; session.isOpen()) {
            try {
                String message = JSON.toJSONString(
                  Map.of("type", "cc", "data", ccTask)
                );
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                log.error("发送WebSocket消息失败", e);
            }
      }
    }
}</pre></div>
<p class="maodian"></p><h3>4.3、&nbsp;抄送规则配置</h3>
<div class="jb51code"><pre class="brush:java;">@Component
public class CcRuleEngine {
   
    /**
   * 根据规则自动抄送
   * 规则示例:
   * 1. 特定节点自动抄送
   * 2. 金额大于阈值抄送
   * 3. 特定部门任务抄送
   */
    public List&lt;String&gt; getCcUsersByRule(
            String processDefinitionId,
            String taskDefinitionKey,
            Map&lt;String, Object&gt; variables) {
      
      List&lt;String&gt; userIds = new ArrayList&lt;&gt;();
      
      // 示例:根据任务节点配置抄送
      if ("approve".equals(taskDefinitionKey)) {
            // 审批节点抄送给部门经理
            String deptId = (String) variables.get("deptId");
            userIds.addAll(getDeptManagers(deptId));
      }
      
      // 示例:根据金额阈值抄送
      Double amount = (Double) variables.get("amount");
      if (amount != null &amp;&amp; amount &gt; 10000) {
            userIds.addAll(getFinanceUsers());
      }
      
      return userIds.stream().distinct().collect(Collectors.toList());
    }
}</pre></div>
<p class="maodian"></p><h3>4.4、 应用配置文件</h3>
<div class="jb51code"><pre class="brush:yaml;"># application.yml
activiti:
cc:
    enabled: true
    # 是否启用邮件通知
    email-notify: true
    # 是否启用站内信
    message-notify: true
    # 默认抄送人(角色)
    default-cc-roles: ROLE_DEPT_MANAGER,ROLE_ADMIN</pre></div>
<p class="maodian"></p><h3>4.5、&nbsp;流程定义中的抄送配置</h3>
<div class="jb51code"><pre class="brush:xml;">&lt;!-- 在BPMN文件中添加抄送配置 --&gt;
&lt;userTask id="approveTask" name="审批任务"&gt;
&lt;extensionElements&gt;
    &lt;activiti:taskListener event="create"
      class="com.xxx.listener.AutoCcTaskListener"/&gt;
    &lt;activiti:formProperty id="ccUsers"
      name="抄送人" type="users"/&gt;
&lt;/extensionElements&gt;
&lt;/userTask&gt;</pre></div>
<p class="maodian"></p><h2>5、总结</h2>
<p>抄送功能的实现要点:</p>
<ul><li><strong>数据持久化</strong>:设计抄送表记录抄送信息</li><li><strong>业务逻辑</strong>:提供抄送CRUD服务</li><li><strong>流程集成</strong>:通过监听器自动触发抄送</li><li><strong>用户通知</strong>:集成多种通知方式(站内信、邮件、推送)</li><li><strong>权限控制</strong>:确保用户只能操作自己的抄送记录</li><li><strong>配置灵活</strong>:支持规则引擎和动态配置</li></ul>
<p>这种实现方式既保持了工作流引擎的纯净性,又通过扩展实现了业务需要的抄送功能。</p>
<p>到此这篇关于SpringBoot整合Activiti的项目中实现抄送功能的文章就介绍到这了,更多相关SpringBoot Activiti抄送内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>SpringBoot整合Activiti7的实现代码</li><li>解决Springboot2.1.x配置Activiti7单独数据源问题</li><li>SpringBoot 集成 activiti的示例代码</li><li>使用springboot activiti关闭验证自动部署方式</li><li>Springboot整合Activiti操作详解</li><li>基于springboot activiti 配置项解析</li><li>SpringBoot整合Activiti工作流框架的使用</li><li>springboot集成activiti全过程</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: SpringBoot整合Activiti的项目中实现抄送功能