??最近新項目要用工作流,查了幾天資料,主要集中在 Activiti7、Flowable、Camunda 三個,同是 jbpm 框架發展而來,各有優劣。最終選擇了Activiti7,原因無他,僅是手頭參與的其他項目用這個,方便盡快上手,下個項目應該會試試另外兩個。
??本次項目采用 RuoYi-Vue-v3.8 開發,使用的 Springboot 版本為v2.5.8。記錄一下接入使用過程及踩坑信息,便于自己以后查看,如果對其他人有一些幫助也算意外之喜吧。以下內容主要針對于本次項目,可能一些說明不準確或解決方式不完善的地方,能力有限,只能留有遺憾了。
SpringBoot項目、在 pom 文件中添加 Activiti 相關依賴:
<dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter</artifactId><version>7.1.0.M4</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>org.activiti.dependencies</groupId><artifactId>activiti-dependencies</artifactId><version>7.1.0.M4</version><type>pom</type>
</dependency>
<!-- Activiti生成流程圖 -->
<dependency><groupId>org.activiti</groupId><artifactId>activiti-image-generator</artifactId><version>7.1.0.M4</version>
</dependency>
項目使用 Mysql 數據庫,已引入驅動,因此這里不再添加。Activiti 默認使用 H2 數據庫,如項目未使用數據庫,應引入數據庫驅動。
修改 application.yml 配置文件,添加內容如下:
spring:
...# 工作流
activiti:deployment-mode: never-fail # 關閉 SpringAutoDeploymentcheck-process-definitions: false #自動部署驗證設置:true-開啟(默認)、false-關閉database-schema-update: true #true表示對數據庫中所有表進行更新操作。如果表不存在,則自動創建。history-level: full #full表示全部記錄歷史,方便繪制流程圖db-history-used: true #true表示使用歷史表
main:allow-bean-definition-overriding: true #不同配置文件中存在id或者name相同的bean定義,后面加載的bean定義會覆蓋前面的bean定義
踩坑1:不明白別人的項目為什么要加 “allow-bean-definition-overriding“ 屬性,所以沒加。結果很快就明白為什么要加了,項目啟動出現如下錯誤(錯誤信息還給出了解決提醒,我真搞笑):
Description:
The bean 'methodSecurityInterceptor', defined in class path resource [org/activiti/spring/boot/MethodSecurityConfig.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class] and overriding is disabled.Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
springboot,踩坑2:在上述步驟之后,重新運行項目,然后又出現了如下錯誤:
16:46:33.758 [restartedMain] INFO o.a.e.i.c.ProcessEngineConfigurationImpl - [configuratorsAfterInit,1571] - Executing configure() of class org.activiti.spring.process.conf.ProcessExtensionsConfiguratorAutoConfiguration$$EnhancerBySpringCGLIB$$3d85fc52 (priority:10000)
16:46:33.893 [restartedMain] ERROR o.a.e.i.i.CommandContext - [logException,149] - Error while closing command context
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table 'zhhq.act_ge_property' doesn't exist
### The error may exist in org/activiti/db/mapping/entity/Property.xml
### The error may involve org.activiti.engine.impl.persistence.entity.PropertyEntityImpl.selectProperty-Inline
### The error occurred while setting parameters
### SQL: select * from ACT_GE_PROPERTY where NAME_ = ?
### Cause: java.sql.SQLSyntaxErrorException: Table 'zhhq.act_ge_property' doesn't exist
// 原來的 url
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
// 修改后 url,添加了 &nullCatalogMeansCurrent=true
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
public String login(String username, String password, String code, String uuid){boolean captchaOnOff = configService.selectCaptchaOnOff();// 驗證碼開關if (captchaOnOff){validateCaptcha(username, code, uuid);}// 用戶驗證Authentication authentication = null;try{// 該方法會去調用UserDetailsServiceImpl.loadUserByUsernameauthentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));}catch (Exception e){if (e instanceof BadCredentialsException){AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));throw new UserPasswordNotMatchException();}else{AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));throw new ServiceException(e.getMessage());}}AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));LoginUser loginUser = (LoginUser) authentication.getPrincipal();recordLoginInfo(loginUser.getUserId());// 生成tokenreturn tokenService.createToken(loginUser);}
@Service
public class UserDetailsServiceImpl implements UserDetailsService
{private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);@Autowiredprivate ISysUserService userService;@Autowiredprivate SysPermissionService permissionService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{SysUser user = userService.selectUserByUserName(username);if (StringUtils.isNull(user)){log.info("登錄用戶:{} 不存在.", username);throw new ServiceException("登錄用戶:" + username + " 不存在");}else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())){log.info("登錄用戶:{} 已被刪除.", username);throw new ServiceException("對不起,您的賬號:" + username + " 已被刪除");}else if (UserStatus.DISABLE.getCode().equals(user.getStatus())){log.info("登錄用戶:{} 已被停用.", username);throw new ServiceException("對不起,您的賬號:" + username + " 已停用");}return createLoginUser(user);}public UserDetails createLoginUser(SysUser user){return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));}
}
// 有變更的方法,在原來的用戶信息類中加入了需要的權限信息
public UserDetails createLoginUser(SysUser user) {Set<String> postCode = sysPostService.selectPostCodeByUserId(user.getUserId());postCode = postCode.parallelStream().map(s -> "GROUP_" + s).collect(Collectors.toSet());postCode.add("ROLE_ACTIVITI_USER");List<SimpleGrantedAuthority> collect = postCode.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList());return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user), collect);
}
public class LoginUser implements UserDetails
{private static final long serialVersionUID = 1L;/*** 用戶ID*/private Long userId;/*** 部門ID*/private Long deptId;/*** 用戶唯一標識*/private String token;/*** 登錄時間*/private Long loginTime;/*** 過期時間*/private Long expireTime;/*** 登錄IP地址*/private String ipaddr;/*** 登錄地點*/private String loginLocation;/*** 瀏覽器類型*/private String browser;/*** 操作系統*/private String os;/*** 權限列表*/private Set<String> permissions;/*** 用戶信息*/private SysUser user;// 省去 set/get 方法@Overridepublic Collection<? extends GrantedAuthority> getAuthorities(){return null;}
}
public class LoginUser implements UserDetails
{// 去掉不變的代碼// +++++private List<SimpleGrantedAuthority> authorities;// +++++public void setAuthorities(List<SimpleGrantedAuthority> authorities) {this.authorities = authorities;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities(){return authorities; // 變更}
}
@SpringBootTest()public class ActivitiTest {@Autowiredprivate RepositoryService repositoryService;@Testpublic void deployTest() {Deployment deployment = repositoryService.createDeployment().addClasspathResource("leave.bpmn").name("測試流程").deploy();System.out.println("部署ID:" + deployment.getId());}}
### SQL: insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, KEY_, TENANT_ID_, DEPLOY_TIME_, ENGINE_VERSION_, VERSION_, PROJECT_RELEASE_VERSION_) values(?, ?, ?, ?, ?, ?, ?, ?, ?)
### Cause: java.sql.SQLSyntaxErrorException: Unknown column 'VERSION_' in 'field list'
-- 修復Activiti7的M4版本缺失字段Bug
alter table ACT_RE_DEPLOYMENT add column PROJECT_RELEASE_VERSION_ varchar(255) DEFAULT NULL;
alter table ACT_RE_DEPLOYMENT add column VERSION_ varchar(255) DEFAULT NULL;
15:59:08.035 [main] INFO o.a.e.i.b.d.BpmnDeployer - [dispatchProcessDefinitionEntityInitializedEvent,234] - Process deployed: {id: leave:1:f67ecd7e-a047-11ec-a9cd-d45d64273150, key: leave, name: 請假流程-普通表單 }
@Test
public void startProcessTest() {ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder.start().withProcessDefinitionKey("test").withName("請假測試").build());System.out.println("實例ID:" + processInstance.getId());
}
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
@PreAuthorize("hasRole('ACTIVITI_USER')")
public class ProcessRuntimeImpl implements ProcessRuntime {}
@Test
public void startProcessTest() {Map<String, Object> paramMap = new HashMap<>();paramMap.put("deptLeader", "test01");ProcessInstance pi = runtimeService.startProcessInstanceByKey("leave", "測試請假", paramMap);System.out.println("實例ID:" + pi.getId());
}
??很基礎的一些東西,算是項目使用工作流的第一步吧。接下來,就是在前端項目中接入流程設計器了,然后是實際使用中一些處理和技巧,一步步來吧。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态