diff --git a/mhd_bms/src/main/java/com/mhd/bms/interfaces/facadeApi/ReceiptManageApi.java b/mhd_bms/src/main/java/com/mhd/bms/interfaces/facadeApi/ReceiptManageApi.java index c733bde13..8f6b3b896 100644 --- a/mhd_bms/src/main/java/com/mhd/bms/interfaces/facadeApi/ReceiptManageApi.java +++ b/mhd_bms/src/main/java/com/mhd/bms/interfaces/facadeApi/ReceiptManageApi.java @@ -1,8 +1,10 @@ package com.mhd.bms.interfaces.facadeApi; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -56,6 +58,11 @@ public class ReceiptManageApi extends BaseController{ @Autowired private RedisLock redisLock; + /** + * 排队批量收款-获取账单锁的最大等待时间(秒),等待期内排队获取锁,避免并发收款直接失败 + */ + private static final long QUEUE_COLLECTION_LOCK_WAIT_SECONDS = 30L; + /** * 分页查询收款单管理列表 */ @@ -115,6 +122,79 @@ public class ReceiptManageApi extends BaseController{ } } + /** + * 排队批量收款 + * 接收多个批量收款请求参数集合,按顺序排队依次处理; + * 同一账单分多次收款时前一笔处理完成后才处理下一笔,避免redis锁冲突导致收款失败 + */ + @ApiOperation("排队批量收款") + @RepeatSubmit + @PostMapping("/queueBatchCollection") + public AjaxResult queueBatchCollection(@RequestBody List receiptManageDTOList) + { + if(StringUtils.isEmpty(receiptManageDTOList)){ + throw new ServiceException("收款账单不能为空"); + } + List> collectionResultList = new ArrayList<>(); + for (ReceiptManageDTO receiptManageDTO : receiptManageDTOList) { + collectionResultList.add(handleQueueBatchCollection(receiptManageDTO)); + } + boolean allSuccess = collectionResultList.stream().allMatch(item -> Boolean.TRUE.equals(item.get("success"))); + if (allSuccess) { + return AjaxResult.success("收款成功", collectionResultList); + } + return AjaxResult.error("部分收款失败,请查看收款结果明细", collectionResultList); + } + + /** + * 排队批量收款-处理单个收款请求(排队获取账单锁,每笔收款独立处理,单笔失败不影响后续请求) + */ + private Map handleQueueBatchCollection(ReceiptManageDTO receiptManageDTO) { + Map result = new LinkedHashMap<>(); + result.put("billManageIds", receiptManageDTO.getBillManageIds()); + RedissonMultiLock redissonMultiLock = null; + boolean payInfoDetailLock = false; + try { + if(!StringUtils.isNotEmpty(receiptManageDTO.getBillManageIds())){ + throw new ServiceException("收款账单不能为空"); + } + RedisLockTypeEnum redisLockTypeEnum = RedisLockTypeEnum.BMS; + List locks = new ArrayList<>(); + Set billingSet = Stream.of(receiptManageDTO.getBillManageIds().split(",")).collect(Collectors.toSet()); + billingSet.forEach(x -> { + //获取唯一key值 + String key = redisLockTypeEnum.getUniqueKey(UniqueKeyUtil.getBillingKey(x.toString())); + locks.add(redisLock.getRLock(key)); + }); + redissonMultiLock = new RedissonMultiLock(locks.toArray(new RLock[billingSet.size()])); + //尝试获取锁 等待指定时间内排队获取 持有锁10分钟 + payInfoDetailLock = redissonMultiLock.tryLock(QUEUE_COLLECTION_LOCK_WAIT_SECONDS, 10, TimeUnit.MINUTES); + if (!payInfoDetailLock) { + redissonMultiLock = null; + result.put("success", false); + result.put("message", "账单正在处理,请稍后再试"); + return result; + } + log.info("排队批量收款-生成账单加锁成功"); + //转换实体 + ReceiptManageDO receiptManageDO = new ReceiptManageDO(); + BeanUtils.copyProperties(receiptManageDTO,receiptManageDO); + Boolean flag = receiptManageApplicationService.batchCollection(receiptManageDO); + result.put("success", Boolean.TRUE.equals(flag)); + result.put("message", Boolean.TRUE.equals(flag) ? "收款成功" : "收款失败"); + return result; + }catch (Exception e){ + result.put("success", false); + result.put("message", "收款失败" + e.getMessage()); + return result; + }finally { + if (redissonMultiLock != null && payInfoDetailLock) { + redissonMultiLock.unlock(); + log.info("排队批量收款-生成账单释放了锁"); + } + } + } + /** * 撤销收款 */