Commit c33186569d1b848bad4680c707ac9a5aaa9eb1db

Authored by YunaiV
1 parent 5d6308e4

优化 mp 账号的刷新机制,使用 Job 轮询,替换 MQ 广播

Showing 14 changed files with 62 additions and 115 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
@@ -164,7 +164,7 @@ public class CollectionUtils { @@ -164,7 +164,7 @@ public class CollectionUtils {
164 return from.stream().filter(predicate).findFirst().orElse(null); 164 return from.stream().filter(predicate).findFirst().orElse(null);
165 } 165 }
166 166
167 - public static <T, V extends Comparable<? super V>> V getMaxValue(List<T> from, Function<T, V> valueFunc) { 167 + public static <T, V extends Comparable<? super V>> V getMaxValue(Collection<T> from, Function<T, V> valueFunc) {
168 if (CollUtil.isEmpty(from)) { 168 if (CollUtil.isEmpty(from)) {
169 return null; 169 return null;
170 } 170 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessInstanceServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.service.definition; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource private BpmMessageService messageService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult<BpmProcessInstanceExtDO> pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List<String> processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); } @Override public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(variables)); return instance.getId(); } }
0 \ No newline at end of file 2 \ No newline at end of file
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java
@@ -15,8 +15,8 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert; @@ -15,8 +15,8 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert;
15 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; 15 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
16 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; 16 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
17 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; 17 import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
18 -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;  
19 import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; 18 import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants;
  19 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum;
20 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; 20 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript;
21 import cn.iocoder.yudao.module.system.api.dept.DeptApi; 21 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
22 import cn.iocoder.yudao.module.system.api.dept.PostApi; 22 import cn.iocoder.yudao.module.system.api.dept.PostApi;
@@ -89,7 +89,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -89,7 +89,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
89 89
90 @Override 90 @Override
91 public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, 91 public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId,
92 - String taskDefinitionKey) { 92 + String taskDefinitionKey) {
93 return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey); 93 return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);
94 } 94 }
95 95
@@ -128,14 +128,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -128,14 +128,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
128 validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions()); 128 validTaskAssignRuleOptions(reqVO.getType(), reqVO.getOptions());
129 // 校验是否已经配置 129 // 校验是否已经配置
130 BpmTaskAssignRuleDO existRule = 130 BpmTaskAssignRuleDO existRule =
131 - taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey()); 131 + taskRuleMapper.selectListByModelIdAndTaskDefinitionKey(reqVO.getModelId(), reqVO.getTaskDefinitionKey());
132 if (existRule != null) { 132 if (existRule != null) {
133 throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey()); 133 throw exception(TASK_ASSIGN_RULE_EXISTS, reqVO.getModelId(), reqVO.getTaskDefinitionKey());
134 } 134 }
135 135
136 // 存储 136 // 存储
137 BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO) 137 BpmTaskAssignRuleDO rule = BpmTaskAssignRuleConvert.INSTANCE.convert(reqVO)
138 - .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建 138 + .setProcessDefinitionId(BpmTaskAssignRuleDO.PROCESS_DEFINITION_ID_NULL); // 只有流程模型,才允许新建
139 taskRuleMapper.insert(rule); 139 taskRuleMapper.insert(rule);
140 return rule.getId(); 140 return rule.getId();
141 } 141 }
@@ -169,14 +169,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -169,14 +169,14 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
169 169
170 // 遍历,匹配对应的规则 170 // 遍历,匹配对应的规则
171 Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap = 171 Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap =
172 - CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey); 172 + CollectionUtils.convertMap(processInstanceRules, BpmTaskAssignRuleRespVO::getTaskDefinitionKey);
173 for (BpmTaskAssignRuleRespVO modelRule : modelRules) { 173 for (BpmTaskAssignRuleRespVO modelRule : modelRules) {
174 BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey()); 174 BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey());
175 if (processInstanceRule == null) { 175 if (processInstanceRule == null) {
176 return false; 176 return false;
177 } 177 }
178 if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal( 178 if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType()) || !ObjectUtil.equal(
179 - modelRule.getOptions(), processInstanceRule.getOptions())) { 179 + modelRule.getOptions(), processInstanceRule.getOptions())) {
180 return false; 180 return false;
181 } 181 }
182 } 182 }
@@ -192,7 +192,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -192,7 +192,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
192 // 开始复制 192 // 开始复制
193 List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules); 193 List<BpmTaskAssignRuleDO> newRules = BpmTaskAssignRuleConvert.INSTANCE.convertList2(rules);
194 newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null) 194 newRules.forEach(rule -> rule.setProcessDefinitionId(toProcessDefinitionId).setId(null).setCreateTime(null)
195 - .setUpdateTime(null)); 195 + .setUpdateTime(null));
196 taskRuleMapper.insertBatch(newRules); 196 taskRuleMapper.insertBatch(newRules);
197 } 197 }
198 198
@@ -215,7 +215,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -215,7 +215,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
215 if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) { 215 if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) {
216 roleApi.validRoleList(options); 216 roleApi.validRoleList(options);
217 } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), 217 } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(),
218 - BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) { 218 + BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) {
219 deptApi.validateDeptList(options); 219 deptApi.validateDeptList(options);
220 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) { 220 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) {
221 postApi.validPostList(options); 221 postApi.validPostList(options);
@@ -225,7 +225,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { @@ -225,7 +225,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
225 userGroupService.validUserGroups(options); 225 userGroupService.validUserGroups(options);
226 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) { 226 } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) {
227 dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT, 227 dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT,
228 - CollectionUtils.convertSet(options, String::valueOf)); 228 + CollectionUtils.convertSet(options, String::valueOf));
229 } else { 229 } else {
230 throw new IllegalArgumentException(format("未知的规则类型({})", type)); 230 throw new IllegalArgumentException(format("未知的规则类型({})", type));
231 } 231 }
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java
@@ -40,6 +40,8 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { @@ -40,6 +40,8 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
40 // mock 方法(startUser) 40 // mock 方法(startUser)
41 AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); 41 AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L));
42 when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); 42 when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
  43 + // mock 方法(getStartUserDept)没有部门
  44 + when(deptApi.getDept(eq(10L))).thenReturn(null);
43 45
44 // 调用 46 // 调用
45 Set<Long> result = script.calculateTaskCandidateUsers(execution); 47 Set<Long> result = script.calculateTaskCandidateUsers(execution);
@@ -56,7 +58,9 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { @@ -56,7 +58,9 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest {
56 when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); 58 when(adminUserApi.getUser(eq(1L))).thenReturn(startUser);
57 DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) 59 DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L)
58 .setLeaderUserId(20L)); 60 .setLeaderUserId(20L));
  61 + // mock 方法(getDept)
59 when(deptApi.getDept(eq(10L))).thenReturn(startUserDept); 62 when(deptApi.getDept(eq(10L))).thenReturn(startUserDept);
  63 + when(deptApi.getDept(eq(100L))).thenReturn(null);
60 64
61 // 调用 65 // 调用
62 Set<Long> result = script.calculateTaskCandidateUsers(execution); 66 Set<Long> result = script.calculateTaskCandidateUsers(execution);
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/account/MpAccountMapper.java
@@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; 6 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; 7 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
  9 +import org.apache.ibatis.annotations.Select;
  10 +
  11 +import java.time.LocalDateTime;
9 12
10 @Mapper 13 @Mapper
11 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> { 14 public interface MpAccountMapper extends BaseMapperX<MpAccountDO> {
@@ -22,4 +25,7 @@ public interface MpAccountMapper extends BaseMapperX&lt;MpAccountDO&gt; { @@ -22,4 +25,7 @@ public interface MpAccountMapper extends BaseMapperX&lt;MpAccountDO&gt; {
22 return selectOne(MpAccountDO::getAppId, appId); 25 return selectOne(MpAccountDO::getAppId, appId);
23 } 26 }
24 27
  28 + @Select("SELECT COUNT(*) FROM pay_account WHERE update_time > #{maxUpdateTime}")
  29 + Long selectCountByUpdateTimeGt(LocalDateTime maxUpdateTime);
  30 +
25 } 31 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/consumer/MpAccountRefreshConsumer.java deleted
1 -package cn.iocoder.yudao.module.mp.mq.consumer;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;  
4 -import cn.iocoder.yudao.module.mp.mq.message.MpAccountRefreshMessage;  
5 -import cn.iocoder.yudao.module.mp.service.account.MpAccountService;  
6 -import lombok.extern.slf4j.Slf4j;  
7 -import org.springframework.stereotype.Component;  
8 -  
9 -import javax.annotation.Resource;  
10 -  
11 -/**  
12 - * 针对 {@link MpAccountRefreshMessage} 的消费者  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Component  
17 -@Slf4j  
18 -public class MpAccountRefreshConsumer extends AbstractChannelMessageListener<MpAccountRefreshMessage> {  
19 -  
20 - @Resource  
21 - private MpAccountService mpAccountService;  
22 -  
23 - @Override  
24 - public void onMessage(MpAccountRefreshMessage message) {  
25 - log.info("[onMessage][收到 Account 刷新消息]");  
26 - mpAccountService.initLocalCache();  
27 - }  
28 -  
29 -}  
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/message/MpAccountRefreshMessage.java deleted
1 -package cn.iocoder.yudao.module.mp.mq.message;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;  
4 -import lombok.Data;  
5 -import lombok.EqualsAndHashCode;  
6 -  
7 -/**  
8 - * 公众号账号刷新 Message  
9 - *  
10 - * @author 芋道源码  
11 - */  
12 -@Data  
13 -@EqualsAndHashCode(callSuper = true)  
14 -public class MpAccountRefreshMessage extends AbstractChannelMessage {  
15 -  
16 - @Override  
17 - public String getChannel() {  
18 - return "mp.account.refresh";  
19 - }  
20 -  
21 -}  
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/mq/producer/MpAccountProducer.java deleted
1 -package cn.iocoder.yudao.module.mp.mq.producer;  
2 -  
3 -import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;  
4 -import cn.iocoder.yudao.module.mp.mq.message.MpAccountRefreshMessage;  
5 -import org.springframework.stereotype.Component;  
6 -  
7 -import javax.annotation.Resource;  
8 -  
9 -/**  
10 - * 公众号账号 Producer  
11 - *  
12 - * @author 芋道源码  
13 - */  
14 -@Component  
15 -public class MpAccountProducer {  
16 -  
17 - @Resource  
18 - private RedisMQTemplate redisMQTemplate;  
19 -  
20 - /**  
21 - * 发送 {@link MpAccountRefreshMessage} 消息  
22 - */  
23 - public void sendAccountRefreshMessage() {  
24 - MpAccountRefreshMessage message = new MpAccountRefreshMessage();  
25 - redisMQTemplate.send(message);  
26 - }  
27 -  
28 -}  
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/account/MpAccountServiceImpl.java
1 package cn.iocoder.yudao.module.mp.service.account; 1 package cn.iocoder.yudao.module.mp.service.account;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
4 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; 5 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
7 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 7 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
8 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO; 8 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountCreateReqVO;
9 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO; 9 import cn.iocoder.yudao.module.mp.controller.admin.account.vo.MpAccountPageReqVO;
@@ -13,7 +13,6 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; @@ -13,7 +13,6 @@ import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
13 import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper; 13 import cn.iocoder.yudao.module.mp.dal.mysql.account.MpAccountMapper;
14 import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; 14 import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants;
15 import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; 15 import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
16 -import cn.iocoder.yudao.module.mp.mq.producer.MpAccountProducer;  
17 import com.google.common.annotations.VisibleForTesting; 16 import com.google.common.annotations.VisibleForTesting;
18 import lombok.Getter; 17 import lombok.Getter;
19 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
@@ -21,15 +20,20 @@ import me.chanjar.weixin.common.error.WxErrorException; @@ -21,15 +20,20 @@ import me.chanjar.weixin.common.error.WxErrorException;
21 import me.chanjar.weixin.mp.api.WxMpService; 20 import me.chanjar.weixin.mp.api.WxMpService;
22 import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; 21 import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
23 import org.springframework.context.annotation.Lazy; 22 import org.springframework.context.annotation.Lazy;
  23 +import org.springframework.scheduling.annotation.Scheduled;
24 import org.springframework.stereotype.Service; 24 import org.springframework.stereotype.Service;
25 import org.springframework.validation.annotation.Validated; 25 import org.springframework.validation.annotation.Validated;
26 26
27 import javax.annotation.PostConstruct; 27 import javax.annotation.PostConstruct;
28 import javax.annotation.Resource; 28 import javax.annotation.Resource;
  29 +import java.time.LocalDateTime;
29 import java.util.List; 30 import java.util.List;
30 import java.util.Map; 31 import java.util.Map;
  32 +import java.util.concurrent.TimeUnit;
31 33
32 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  36 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
33 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_USERNAME_EXISTS; 37 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_USERNAME_EXISTS;
34 38
35 /** 39 /**
@@ -58,9 +62,6 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -58,9 +62,6 @@ public class MpAccountServiceImpl implements MpAccountService {
58 @Lazy // 延迟加载,解决循环依赖的问题 62 @Lazy // 延迟加载,解决循环依赖的问题
59 private MpServiceFactory mpServiceFactory; 63 private MpServiceFactory mpServiceFactory;
60 64
61 - @Resource  
62 - private MpAccountProducer mpAccountProducer;  
63 -  
64 @Override 65 @Override
65 @PostConstruct 66 @PostConstruct
66 public void initLocalCache() { 67 public void initLocalCache() {
@@ -72,7 +73,30 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -72,7 +73,30 @@ public class MpAccountServiceImpl implements MpAccountService {
72 73
73 // 第二步:构建缓存。创建或更新支付 Client 74 // 第二步:构建缓存。创建或更新支付 Client
74 mpServiceFactory.init(accounts); 75 mpServiceFactory.init(accounts);
75 - accountCache = CollectionUtils.convertMap(accounts, MpAccountDO::getAppId); 76 + accountCache = convertMap(accounts, MpAccountDO::getAppId);
  77 + });
  78 + }
  79 +
  80 + /**
  81 + * 通过定时任务轮询,刷新缓存
  82 + *
  83 + * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新
  84 + */
  85 + @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
  86 + public void refreshLocalCache() {
  87 + // 注意:忽略自动多租户,因为要全局初始化缓存
  88 + TenantUtils.executeIgnore(() -> {
  89 + // 情况一:如果缓存里没有数据,则直接刷新缓存
  90 + if (CollUtil.isEmpty(accountCache)) {
  91 + initLocalCache();
  92 + return;
  93 + }
  94 +
  95 + // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存
  96 + LocalDateTime maxTime = getMaxValue(accountCache.values(), MpAccountDO::getUpdateTime);
  97 + if (mpAccountMapper.selectCountByUpdateTimeGt(maxTime) > 0) {
  98 + initLocalCache();
  99 + }
76 }); 100 });
77 } 101 }
78 102
@@ -85,8 +109,8 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -85,8 +109,8 @@ public class MpAccountServiceImpl implements MpAccountService {
85 MpAccountDO account = MpAccountConvert.INSTANCE.convert(createReqVO); 109 MpAccountDO account = MpAccountConvert.INSTANCE.convert(createReqVO);
86 mpAccountMapper.insert(account); 110 mpAccountMapper.insert(account);
87 111
88 - // 发送刷新消息  
89 - mpAccountProducer.sendAccountRefreshMessage(); 112 + // 刷新缓存
  113 + initLocalCache();
90 return account.getId(); 114 return account.getId();
91 } 115 }
92 116
@@ -101,8 +125,8 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -101,8 +125,8 @@ public class MpAccountServiceImpl implements MpAccountService {
101 MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO); 125 MpAccountDO updateObj = MpAccountConvert.INSTANCE.convert(updateReqVO);
102 mpAccountMapper.updateById(updateObj); 126 mpAccountMapper.updateById(updateObj);
103 127
104 - // 发送刷新消息  
105 - mpAccountProducer.sendAccountRefreshMessage(); 128 + // 刷新缓存
  129 + initLocalCache();
106 } 130 }
107 131
108 @Override 132 @Override
@@ -112,8 +136,8 @@ public class MpAccountServiceImpl implements MpAccountService { @@ -112,8 +136,8 @@ public class MpAccountServiceImpl implements MpAccountService {
112 // 删除 136 // 删除
113 mpAccountMapper.deleteById(id); 137 mpAccountMapper.deleteById(id);
114 138
115 - // 发送刷新消息  
116 - mpAccountProducer.sendAccountRefreshMessage(); 139 + // 刷新缓存
  140 + initLocalCache();
117 } 141 }
118 142
119 private MpAccountDO validateAccountExists(Long id) { 143 private MpAccountDO validateAccountExists(Long id) {
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/order/dto/PayOrderRespDTO.java
@@ -6,8 +6,6 @@ import lombok.Data; @@ -6,8 +6,6 @@ import lombok.Data;
6 /** 6 /**
7 * 支付单信息 Response DTO 7 * 支付单信息 Response DTO
8 * 8 *
9 - * TODO 芋艿:还没定好字段  
10 - *  
11 * @author 芋道源码 9 * @author 芋道源码
12 */ 10 */
13 @Data 11 @Data
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundRespDTO.java
@@ -8,8 +8,6 @@ import java.time.LocalDateTime; @@ -8,8 +8,6 @@ import java.time.LocalDateTime;
8 /** 8 /**
9 * 退款单信息 Response DTO 9 * 退款单信息 Response DTO
10 * 10 *
11 - * TODO 芋艿:还没定好字段  
12 - *  
13 * @author 芋道源码 11 * @author 芋道源码
14 */ 12 */
15 @Data 13 @Data
yudao-module-pay/yudao-module-pay-biz/pom.xml
@@ -61,12 +61,6 @@ @@ -61,12 +61,6 @@
61 <artifactId>yudao-spring-boot-starter-job</artifactId> 61 <artifactId>yudao-spring-boot-starter-job</artifactId>
62 </dependency> 62 </dependency>
63 63
64 - <!-- 消息队列相关 -->  
65 - <dependency>  
66 - <groupId>cn.iocoder.boot</groupId>  
67 - <artifactId>yudao-spring-boot-starter-mq</artifactId>  
68 - </dependency>  
69 -  
70 <!-- Test 测试相关 --> 64 <!-- Test 测试相关 -->
71 <dependency> 65 <dependency>
72 <groupId>cn.iocoder.boot</groupId> 66 <groupId>cn.iocoder.boot</groupId>
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
@@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateR @@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.pay.controller.admin.channel.vo.PayChannelUpdateR
15 import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert; 15 import cn.iocoder.yudao.module.pay.convert.channel.PayChannelConvert;
16 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; 16 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
17 import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper; 17 import cn.iocoder.yudao.module.pay.dal.mysql.channel.PayChannelMapper;
18 -import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;  
19 import lombok.Getter; 18 import lombok.Getter;
20 import lombok.Setter; 19 import lombok.Setter;
21 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
@@ -112,7 +111,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -112,7 +111,7 @@ public class PayChannelServiceImpl implements PayChannelService {
112 channelMapper.insert(channel); 111 channelMapper.insert(channel);
113 112
114 // 刷新缓存 113 // 刷新缓存
115 - refreshLocalCache(); 114 + initLocalCache();
116 return channel.getId(); 115 return channel.getId();
117 } 116 }
118 117
@@ -127,7 +126,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -127,7 +126,7 @@ public class PayChannelServiceImpl implements PayChannelService {
127 channelMapper.updateById(channel); 126 channelMapper.updateById(channel);
128 127
129 // 刷新缓存 128 // 刷新缓存
130 - refreshLocalCache(); 129 + initLocalCache();
131 } 130 }
132 131
133 /** 132 /**
@@ -160,7 +159,7 @@ public class PayChannelServiceImpl implements PayChannelService { @@ -160,7 +159,7 @@ public class PayChannelServiceImpl implements PayChannelService {
160 channelMapper.deleteById(id); 159 channelMapper.deleteById(id);
161 160
162 // 刷新缓存 161 // 刷新缓存
163 - refreshLocalCache(); 162 + initLocalCache();
164 } 163 }
165 164
166 private PayChannelDO validateChannelExists(Long id) { 165 private PayChannelDO validateChannelExists(Long id) {
yudao-server/src/main/resources/application-dev.yaml
@@ -167,7 +167,8 @@ yudao: @@ -167,7 +167,8 @@ yudao:
167 - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求 167 - ${spring.boot.admin.context-path}/** # 不处理 Spring Boot Admin 的请求
168 - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 168 - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
169 pay: 169 pay:
170 - callback-url: http://yunai.natapp1.cc/admin-api/pay/notify/callback 170 + order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址
  171 + refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址
171 demo: true # 开启演示模式 172 demo: true # 开启演示模式
172 173
173 justauth: 174 justauth: