当前位置: 首页 > news >正文

Spring Boot整合Activiti工作流详解

1. 概述

Spring Boot与Activiti的整合可以大大简化工作流应用的开发。Spring Boot提供了自动配置和依赖管理,而Activiti则提供了强大的工作流功能。通过整合,我们可以快速构建基于工作流的业务系统。

本文将详细介绍Spring Boot与Activiti的整合方法,并通过一个请假流程的例子来演示整合的效果。

2. 环境准备

2.1 开发环境

  • JDK 1.8+
  • Maven 3.5+
  • Spring Boot 2.3.x (兼容Activiti 7.x)
  • Activiti 7.x
  • MySQL 5.7+
  • IDE(IntelliJ IDEA或Eclipse)

2.2 Maven依赖

创建一个Spring Boot项目,在pom.xml中添加以下依赖:

<!-- Activiti -->
<dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter</artifactId><version>7.1.0.M6</version>
</dependency>

2.3 配置文件

src/main/resources目录下创建application.yml文件:

  # Activiti配置(与Swagger冲突,两者只能开启一个)activiti:# 这里使用create_drop确保表被创建database-schema-update: create_dropdb-history-used: truehistory-level: fullcheck-process-definitions: true# 明确指定流程定义位置process-definition-location-prefix: classpath:/processes/

2.4 安全配置

由于Activiti 7与Spring Security集成,需要创建一个安全配置类:

package com.example.testlogin.config;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
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.InMemoryUserDetailsManager;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().configurationSource(corsConfigurationSource())  // 使用配置的CORS策略.and().csrf().disable()  // 禁用CSRF保护.authorizeRequests().antMatchers("/api/login").permitAll().antMatchers("/api/excel/upload").permitAll().antMatchers("/api/excel/export").permitAll().antMatchers("/api/test/select").permitAll().antMatchers("/api/test/delete").permitAll().antMatchers("/api/test/upload").permitAll().antMatchers("/api/test/download").permitAll().antMatchers("/api/test/exportFile").permitAll().antMatchers("/api/test/importFile").permitAll().antMatchers("/api/test/importSheetFile").permitAll().antMatchers("/api/test/exportSheetFile").permitAll().antMatchers("/api/test/fillFile").permitAll().antMatchers("/api/test/fillFileList").permitAll().antMatchers("/api/test/fillFileSheetList").permitAll().antMatchers("/api/test/downloadFile").permitAll().antMatchers("/api/message/send").permitAll().antMatchers("/api/modbus/holdingRegisters").permitAll().antMatchers("/time/count").permitAll().antMatchers("/pic/**").permitAll().antMatchers("/files/**").permitAll().antMatchers("/swagger-ui/**", "/swagger-resources/**", "/v3/api-docs/**", "/v2/api-docs/**", "/webjars/**").permitAll()// 允许访问swagger.antMatchers("/webSocket/image").permitAll()// 允许未认证用户访问.antMatchers("/chat").permitAll()  // 允许访问WebSocket的chat端点.antMatchers("/chat/*").permitAll()  // 允许访问WebSocket的chat端点// 重要修改:保护Activiti相关资源,要求认证.antMatchers("/activiti/**", "/leave/**", "/process/**", "/task/**").authenticated()// 静态资源可以公开访问.antMatchers("/css/**", "/js/**", "/images/**").permitAll()// 主页和其他公共页面.antMatchers("/", "/index", "/home").permitAll()// 其他请求需要认证.anyRequest().authenticated().and()// 使用默认登录页面 - 移除loginPage配置.formLogin().defaultSuccessUrl("/index").permitAll().and().logout().logoutSuccessUrl("/login?logout").permitAll();// 允许HTTP基本认证(Activiti Rest API可能需要)http.httpBasic();// 允许iframe嵌入,用于Activiti表单和流程设计器http.headers().frameOptions().sameOrigin();}@Beanpublic UserDetailsService userDetailsService() {// 创建用户InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();// 添加用户:员工String[][] usersGroupsAndRoles = {{"jack", "password", "ROLE_ACTIVITI_USER", "GROUP_employees"},{"rose", "password", "ROLE_ACTIVITI_USER", "GROUP_employees"},{"tom", "password", "ROLE_ACTIVITI_USER", "GROUP_employees"},{"jerry", "password", "ROLE_ACTIVITI_USER", "GROUP_employees"},{"manager", "password", "ROLE_ACTIVITI_USER", "GROUP_managers"},{"hr", "password", "ROLE_ACTIVITI_USER", "GROUP_hr"},{"admin", "password", "ROLE_ACTIVITI_ADMIN", "ROLE_ACTIVITI_USER"},};for (String[] user : usersGroupsAndRoles) {List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));inMemoryUserDetailsManager.createUser(new User(user[0],passwordEncoder().encode(user[1]),authoritiesStrings.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())));}// 添加匿名用户inMemoryUserDetailsManager.createUser(User.withUsername("anonymousUser").password("") // 空密码.authorities("ROLE_ANONYMOUS").build());return inMemoryUserDetailsManager;}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}

2.5 启动类配置

创建Spring Boot启动类:

package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ActivitiSpringBootDemoApplication {public static void main(String[] args) {SpringApplication.run(ActivitiSpringBootDemoApplication.class, args);}
}

3. 业务模型设计

3.1 请假实体类

创建一个请假实体类:

package com.example.testlogin.entity;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class LeaveRequest implements Serializable {private static final long serialVersionUID = 1L;private Long id;private String userId;private String userName;private Date startDate;private Date endDate;private Integer days;private String reason;private String leaveType;// 请假类型:年假、病假、事假等private String status; // 状态:草稿、提交、审批中、已批准、已拒绝private String processInstanceId; // 流程实例ID
}

3.2 数据访问层

创建请假数据访问接口:

package com.example.testlogin.repository;
import com.example.testlogin.entity.LeaveRequest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;@Repository
public class LeaveRequestRepository {private final JdbcTemplate jdbcTemplate;public LeaveRequestRepository(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}// 创建请假表public void createTable() {jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS leave_request (" +"id BIGINT AUTO_INCREMENT PRIMARY KEY," +"user_id VARCHAR(100) NOT NULL," +"user_name VARCHAR(100) NOT NULL," +"start_date DATE NOT NULL," +"end_date DATE NOT NULL," +"days INT NOT NULL," +"leave_type DATE NOT NULL," +"reason VARCHAR(500)," +"status VARCHAR(50) NOT NULL," +"process_instance_id VARCHAR(100)" +")");}// 保存请假申请public void save(LeaveRequest leaveRequest) {try {System.out.println("保存请假申请: ID=" + leaveRequest.getId() +", 申请人=" + leaveRequest.getUserName() +", 状态=" + leaveRequest.getStatus());if (leaveRequest.getId() == null) {String sql = "INSERT INTO leave_request (user_id, user_name, start_date, end_date,leave_type, days, reason, status, process_instance_id) " +"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";System.out.println("执行SQL: " + sql);System.out.println("参数: [" +leaveRequest.getUserId() + ", " +leaveRequest.getUserName() + ", " +leaveRequest.getStartDate() + ", " +leaveRequest.getEndDate() + ", " +leaveRequest.getLeaveType() + ", " +leaveRequest.getDays() + ", " +leaveRequest.getReason() + ", " +leaveRequest.getStatus() + ", " +leaveRequest.getProcessInstanceId() + "]");jdbcTemplate.update(sql,leaveRequest.getUserId(),leaveRequest.getUserName(),leaveRequest.getStartDate(),leaveRequest.getEndDate(),leaveRequest.getLeaveType(),leaveRequest.getDays(),leaveRequest.getReason(),leaveRequest.getStatus(),leaveRequest.getProcessInstanceId());System.out.println("插入请假申请成功");} else {String sql = "UPDATE leave_request SET user_id=?, user_name=?, start_date=?, end_date=?, leave_type=?, days=?, reason=?, status=?, process_instance_id=? " +"WHERE id=?";System.out.println("执行SQL: " + sql);System.out.println("参数: [" +leaveRequest.getUserId() + ", " +leaveRequest.getUserName() + ", " +leaveRequest.getStartDate() + ", " +leaveRequest.getEndDate() + ", " +leaveRequest.getLeaveType() + ", " +leaveRequest.getDays() + ", " +leaveRequest.getReason() + ", " +leaveRequest.getStatus() + ", " +leaveRequest.getProcessInstanceId() + ", " +leaveRequest.getId() + "]");int rowsAffected = jdbcTemplate.update(sql,leaveRequest.getUserId(),leaveRequest.getUserName(),

http://www.mrgr.cn/news/95786.html

相关文章:

  • 【Redis实战专题】「技术提升系列」​RedisJSON核心机制与实战应用解析(入门基础篇)
  • 调语音类大模型必备-音频录制小妙招-自制工具-借助浏览器录一段单声道16000采样率wav格式音频
  • 华为OD机试 - 核酸最快检测效率 - 动态规划、背包问题(Java 2024 E卷 200分)
  • 【学习记录】大模型微调之使用 LLaMA-Factory 微调 Qwen系列大模型,可以用自己的数据训练
  • How to share files with Linux mint 22 via samba in Windows
  • Sql Server 索引性能优化 分析以及分表
  • _DISPATCHER_HEADER结构中的WaitListHead和_KWAIT_BLOCK的关系
  • Linux的SPI子系统的原理和结构详解【SPI控制器(spi_master)、SPI总线(device-driver-match匹配机制)、SPI设备、SPI万能驱动`spidev.c`】
  • Unity 实现一个简易可拓展性的对话系统
  • 深度解读DeepSeek:开源周(Open Source Week)技术解读
  • 从零开始的LeetCode刷题日记:128. 最长连续序列
  • Spring Boot 整合 Nacos 注册中心终极指南
  • CentOS 7 更换 yum 源(阿里云)+ 扩展 epel 源
  • Jackson实现JSON数据的合并
  • vivo 湖仓架构的性能提升之旅
  • AI本地部署之dify
  • Redis 服务搭建
  • DeepSeek面试——模型架构和主要创新点
  • 《TCP/IP网络编程》学习笔记 | Chapter 21:异步通知 I/O 模型
  • springboot使用netty做TCP客户端