扫码重复,单据下载多线程问题,

dev_2.5_csconfilt
yewj 3 months ago
parent 7415b0c02d
commit 17bbaef1d7

@ -29,4 +29,13 @@ public @interface CusRedissonAnnotation {
*/
@Min(value = 0, message = "等待时间最小值为0")
int waitTime() default 1;
/**
* 30030
*
*
* @return
*/
@Min(value = 0, message = "锁的过期时间最小值为0")
int leaseTime() default 1;
}

@ -5,6 +5,7 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.glxp.api.annotation.CusRedissonAnnotation;
import com.glxp.api.exception.JsonException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
@ -25,7 +26,9 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Aspect
@Component
public class RedissonAspect {
@ -39,56 +42,75 @@ public class RedissonAspect {
@Before("@annotation(annotation)")
public void before(JoinPoint joinPoint, CusRedissonAnnotation annotation) throws InterruptedException {
if (StrUtil.isBlank(parseKey(joinPoint, annotation))) {
String key = parseKey(joinPoint, annotation);
if (StrUtil.isBlank(key)) {
throw new RuntimeException("redisson使用的key不能为空");
}
if (StrUtil.isBlank(annotation.timeOutMsg())) {
throw new RuntimeException("redisson的超时信息不能为空");
}
RLock lock = redissonClient.getLock(parseKey(joinPoint, annotation));
RLock lock = redissonClient.getLock(key);
int waitTime = annotation.waitTime();
boolean tryLock = lock.tryLock(waitTime, TimeUnit.SECONDS);
int leaseTime = annotation.leaseTime();
boolean tryLock = lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
if (!tryLock) {
throw new JsonException(500, annotation.timeOutMsg());
}
}
@After("@annotation(cusRedissonAnnotation)")
public void after(JoinPoint joinPoint, CusRedissonAnnotation cusRedissonAnnotation) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
CusRedissonAnnotation annotation = signature.getMethod().getAnnotation(CusRedissonAnnotation.class);
RLock lock = redissonClient.getLock(parseKey(joinPoint, annotation));
String key = parseKey(joinPoint, annotation);
RLock lock = redissonClient.getLock(key);
try {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
private String parseKey(JoinPoint joinPoint, CusRedissonAnnotation annotation) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
String[] paramNames = nameDiscoverer.getParameterNames(method);
List<String> keyValue = new ArrayList<>(annotation.key().length);
for (String s : annotation.key()) {
if (s.contains("#")) {
Expression expression = expressionParser.parseExpression(s);
EvaluationContext context = new StandardEvaluationContext();
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
context.setVariable(paramNames[i], args[i]);
}
if (s.contains("#")) {
keyValue.add(expression.getValue(context, String.class));
Object value = expression.getValue(context);
if (value instanceof List) {
// 如果是List类型将List中的元素用下划线连接
List<?> list = (List<?>) value;
keyValue.add(String.join("_", list.stream()
.map(Object::toString)
.collect(Collectors.toList())));
} else {
keyValue.add(s);
keyValue.add(value != null ? value.toString() : "");
}
} else {
keyValue.add(s);
}
return String.format("%s:%s", annotation.cacheName(), ArrayUtil.join(keyValue.toArray(), "_"));
}
String finalKey = String.format("%s:%s", annotation.cacheName(), ArrayUtil.join(keyValue.toArray(), "_"));
log.info("redisson分布式锁的key为:{}", finalKey);
return finalKey;
}
}

@ -69,4 +69,21 @@ public interface RedissonCacheKey {
String XLSX_UPLOAD = "xlsx_upload";
/**
*
*/
String PRESCRIBE_BATCH_CODE = "prescribe_batch_code";
/**
*
*/
String PRESCRIBE_ADD_CODE = "prescribe_add_code";
/**
*
*/
String ENTER_CODE_VAIL = "enter_code_vail";
}

@ -3,9 +3,11 @@ package com.glxp.api.controller.collect;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageInfo;
import com.glxp.api.annotation.CusRedissonAnnotation;
import com.glxp.api.common.enums.ResultEnum;
import com.glxp.api.common.res.BaseResponse;
import com.glxp.api.common.util.ResultVOUtils;
import com.glxp.api.constant.RedissonCacheKey;
import com.glxp.api.controller.BaseController;
import com.glxp.api.entity.collect.IoCollectOrder;
import com.glxp.api.entity.collect.IoCollectOrderBiz;
@ -74,6 +76,7 @@ public class IoCollectOrderCodeManController extends BaseController {
* @return
*/
@PostMapping("/udiwms/ioSplit/collect/order/tagCode")
@CusRedissonAnnotation(cacheName = RedissonCacheKey.PRESCRIBE_ADD_CODE, key = {"#addTagCodeReqeust.billNo", "#addTagCodeReqeust.code"},waitTime = 1,leaseTime = 5, timeOutMsg = "扫码重复提交")
public BaseResponse prescribeTagCode(@RequestBody @Valid AddTagCodeReqeust addTagCodeReqeust,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
@ -130,6 +133,7 @@ public class IoCollectOrderCodeManController extends BaseController {
* @return
*/
@PostMapping("/udiwms/ioSplit/collect/order/batchAddCode")
@CusRedissonAnnotation(cacheName = RedissonCacheKey.PRESCRIBE_BATCH_CODE, key = {"#addTagCodeReqeust.prescribeNum", "#addTagCodeReqeust.codeList", "#addTagCodeReqeust.code"}, timeOutMsg = "重复扫码")
public BaseResponse batchAddCode(@RequestBody @Valid AddTagCodeReqeust addTagCodeReqeust,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
@ -182,8 +186,6 @@ public class IoCollectOrderCodeManController extends BaseController {
addTagCodeReqeust.setCode(code);
collectOrderCodeManService.prescribeTagCode(addTagCodeReqeust);
}
}
return ResultVOUtils.success(vailTagResultResponse);
}

@ -59,6 +59,7 @@ import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
@ -191,6 +192,9 @@ public class IoCodeTempController extends BaseController {
return ResultVOUtils.error(500, "单据号不能为空!");
}
String code = addEnterCodeRequest.getCode();
if (code.endsWith(";")) {
code = code.replace(";", "");
}
//先判断是否已完成
IoCollectOrderBackup byBillNo = ioCollectOrderBackupService.getByBillNo(code);
@ -363,10 +367,10 @@ public class IoCodeTempController extends BaseController {
return addEnterCodeResponse;
}
@AuthRuleAnnotation("")
@CusRedissonAnnotation(cacheName = RedissonCacheKey.ENTER_CODE_VAIL, key = { "#addEnterCodeRequest.codeList"}, timeOutMsg = "重复扫码")
@PostMapping("warehouse/inout/batchVailCode")
public BaseResponse batchVailCode(@RequestBody AddEnterCodeRequest addEnterCodeRequest) {
public BaseResponse batchVailCode(@RequestBody @Valid AddEnterCodeRequest addEnterCodeRequest) {
List<String> codeList = addEnterCodeRequest.getCodeList();
if (CollUtil.isEmpty(codeList)) return ResultVOUtils.error(500, "追溯码不能为空");
codeList = codeList.stream().distinct().collect(Collectors.toList());
@ -448,8 +452,7 @@ public class IoCodeTempController extends BaseController {
@RepeatSubmit()
@AuthRuleAnnotation("")
@PostMapping("warehouse/inout/batchAddCode")
// @CusRedissonAnnotation(cacheName = RedissonCacheKey.WEB_ADD_CODE, key = {"#addOrderCodeRequest.corpOrderId", "#addOrderCodeRequest.codeList", "#addOrderCodeRequest.code"}, timeOutMsg = "重复扫码")
@Log(title = "单据管理", businessType = BusinessType.INSERT)
@CusRedissonAnnotation(cacheName = RedissonCacheKey.WEB_ADD_CODE, key = {"#addOrderCodeRequest.corpOrderId", "#addOrderCodeRequest.codeList", "#addOrderCodeRequest.code"}, timeOutMsg = "重复扫码11111")
public BaseResponse batchAddCode(@RequestBody AddOrderCodeRequest addOrderCodeRequest, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {

@ -529,10 +529,6 @@ public class UdiProductService extends ServiceImpl<UdiProductDao, UdiProductEnti
udiProductDao.insert(udiProductEntity1);
}
updateLevelCount(udiRelevanceEntity);
// if (IntUtil.value(udiProductEntity1.getPackLevel()) == 1) {
// calculateDistCount(udiProductEntity1, udiRelevanceEntity);
// calculateUseCount(udiProductEntity1, udiRelevanceEntity);
// }
} else {
UdiProductEntity udiProductEntity1 = udiProductDao.findByNameCode(updateLevelDrugRequest.getNameCode());
if (udiProductEntity1 != null) {

@ -136,7 +136,7 @@ public class IoCollectOrderCodeManService extends ServiceImpl<IoCollectOrderCode
@Resource
IoCollectSetService collectSetService;
@Transactional(rollbackFor = Exception.class)
// @Transactional(rollbackFor = Exception.class)
public IoCollectOrder prescribeTagCode(AddTagCodeReqeust addTagCodeReqeust) {
Long userId = customerService.getUserId();
String userIds = customerService.getUserId() + "";
@ -151,7 +151,11 @@ public class IoCollectOrderCodeManService extends ServiceImpl<IoCollectOrderCode
SysWorkplaceDocumentEntity sysWorkplaceDocumentEntity = sysWorkplaceDocumentService.findByWorkplaceCode(workPlace.getWorkplaceId(), addTagCodeReqeust.getBusType());
IoCollectOrderBiz collectOrderBiz = null;
IoCollectOrder collectOrder = null;
try {
Thread.sleep(3*1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//1.校验UDI码完整性
String code = addTagCodeReqeust.getCode();
if (StringUtils.isBlank(code)) throw new JsonException(ResultEnum.DATA_ERROR.getMessage());

@ -67,6 +67,7 @@ import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Service
@ -463,12 +464,22 @@ public class IoCollectOrderService extends ServiceImpl<IoCollectOrderMapper, IoC
}
// 添加一个用于同步的Map存储正在处理的单号
private static final Map<String, Object> BILL_LOCKS = new ConcurrentHashMap<>();
public void importPrescribe(List<BasicSkPrescribeEntity> basicSkPrescribeEntities) {
//下载处方
if (CollUtil.isEmpty(basicSkPrescribeEntities)) basicSkPrescribeEntities = basicSkPrescribeService.list();
List<SysWorkplaceResponse> allWorksList = new ArrayList<>();
for (BasicSkPrescribeEntity basicSkPrescribeEntity : basicSkPrescribeEntities) {
if (collectOrderMapper.exists(new LambdaQueryWrapper<IoCollectOrder>().eq(IoCollectOrder::getBillNo, basicSkPrescribeEntity.getCode()))) {
// 获取单号
String billNo = basicSkPrescribeEntity.getCode();
// 为每个单号创建一个锁对象,如果已存在则使用现有的
Object billLock = BILL_LOCKS.computeIfAbsent(billNo, k -> new Object());
// 使用同步块确保同一单号的处理是同步的
synchronized (billLock) {
try {
if (collectOrderMapper.exists(new LambdaQueryWrapper<IoCollectOrder>().eq(IoCollectOrder::getBillNo, billNo))) {
continue;
}
SysWorkplaceDocumentEntity sysWorkplaceDocumentEntity = sysWorkplaceDocumentService.findByBusType(basicSkPrescribeEntity.getAddr());
@ -497,14 +508,12 @@ public class IoCollectOrderService extends ServiceImpl<IoCollectOrderMapper, IoC
}
}
}
IoCollectOrder collectOrder = IoCollectOrder.builder().billNo(basicSkPrescribeEntity.getCode()).busType(sysWorkplaceDocumentEntity.getDocumentTypeCode()).fromType("HIS系统").fromCorp(basicSkPrescribeEntity.getSickerCode()).workPlaceCode(defaultWorkplace[0]).billTime(MsDateUtil.localToDate(basicSkPrescribeEntity.getPrescribeDate())).createTime(new Date()).createUser(basicSkPrescribeEntity.getCreateUser()).backupOrderRemark1(basicSkPrescribeEntity.getStooutNo()).updateTime(new Date()).orderCirType(sysWorkplaceDocumentEntity.getOrderCirType()).splitStatus(0).tagStatus(0).remark(basicSkPrescribeEntity.getRemark()).build();
IoCollectOrder collectOrder = IoCollectOrder.builder().billNo(billNo).busType(sysWorkplaceDocumentEntity.getDocumentTypeCode()).fromType("HIS系统").fromCorp(basicSkPrescribeEntity.getSickerCode()).workPlaceCode(defaultWorkplace[0]).billTime(MsDateUtil.localToDate(basicSkPrescribeEntity.getPrescribeDate())).createTime(new Date()).createUser(basicSkPrescribeEntity.getCreateUser()).backupOrderRemark1(basicSkPrescribeEntity.getStooutNo()).updateTime(new Date()).orderCirType(sysWorkplaceDocumentEntity.getOrderCirType()).splitStatus(0).tagStatus(0).remark(basicSkPrescribeEntity.getRemark()).build();
if (collectOrder.getWorkPlaceCode() != null) {
collectOrder.setTagStatus(1);
}
save(collectOrder);
List<BasicSkPrescribeItemEntity> basicSkPrescribeItemEntities = basicSkPrescirbeDetailService.findByPrescribeNum(basicSkPrescribeEntity.getCode());
List<BasicSkPrescribeItemEntity> basicSkPrescribeItemEntities = basicSkPrescirbeDetailService.findByPrescribeNum(billNo);
List<IoCollectOrderBiz> collectOrderBizs = new ArrayList<>();
for (BasicSkPrescribeItemEntity bizEntity : basicSkPrescribeItemEntities) {
UdiRelevanceResponse udiRelevanceResponse = udiRelevanceService.selectByRelId(bizEntity.getRelId() + "");
@ -517,12 +526,15 @@ public class IoCollectOrderService extends ServiceImpl<IoCollectOrderMapper, IoC
collectOrderBizs.add(collectOrderBiz);
}
if (CollUtil.isNotEmpty(collectOrderBizs)) collectOrderBizService.saveBatch(collectOrderBizs);
allWorksList.addAll(sysWorkplaces);
if (IntUtil.value(sysWorkplaceDocumentEntity.getAutoTag()) == 1 && IntUtil.value(collectOrder.getTagStatus()) == 1) {
splitFifoCodeService.lockInventoryByOrder(collectOrder.getBillNo(), 1);
splitFifoCodeService.lockInventoryByOrder(billNo, 1);
}
} finally {
// 处理完成后,移除锁对象,释放内存
BILL_LOCKS.remove(billNo);
}
}
}
}
@ -540,11 +552,17 @@ public class IoCollectOrderService extends ServiceImpl<IoCollectOrderMapper, IoC
public void importPrescribe(List<IoCollectOrder> ioCollectOrderList, CollectOrderRequest collectOrderRequest) {
String addr = collectOrderRequest.getBusType();
if (CollUtil.isNotEmpty(ioCollectOrderList)) {
//是否自动转成待处理单据
IoCollectSet collectSet = collectSetService.getSet();
for (IoCollectOrder collectOrder : ioCollectOrderList) {
// 获取单号
String billNo = collectOrder.getBillNo();
// 为每个单号创建一个锁对象,如果已存在则使用现有的
Object billLock = BILL_LOCKS.computeIfAbsent(billNo, k -> new Object());
// 使用同步块确保同一单号的处理是同步的
synchronized (billLock) {
try {
IoCollectOrderOrigin ioCollectOrderOrigin = new IoCollectOrderOrigin();
if (collectOrderMapper.exists(new LambdaQueryWrapper<IoCollectOrder>().eq(IoCollectOrder::getBillNo, collectOrder.getBillNo()))) {
continue;
@ -561,9 +579,6 @@ public class IoCollectOrderService extends ServiceImpl<IoCollectOrderMapper, IoC
List<IoCollectOrderBiz> bizList = collectOrder.getBizList();
if (CollUtil.isNotEmpty(bizList)) {
//先清空 原来的biz
String billNo = collectOrder.getBillNo();
collectOrderBizOriginService.remove(new LambdaUpdateWrapper<IoCollectOrderBizOrigin>().eq(IoCollectOrderBizOrigin::getOrderIdFk, billNo));
for (IoCollectOrderBiz collectOrderBiz : bizList) {
if (collectOrderBiz.getRelId() != null) {
UdiRelevanceResponse udiRelevanceResponse = udiRelevanceService.selectByRelId(collectOrderBiz.getRelId() + "");
@ -578,6 +593,7 @@ public class IoCollectOrderService extends ServiceImpl<IoCollectOrderMapper, IoC
}
}
List<IoCollectOrderBizOrigin> ioCollectOrderBizOrigins = BeanCopyUtils.copyList(bizList, IoCollectOrderBizOrigin.class);
collectOrderBizOriginService.remove(new LambdaUpdateWrapper<IoCollectOrderBizOrigin>().eq(IoCollectOrderBizOrigin::getOrderIdFk, billNo));
collectOrderBizOriginService.saveBatch(ioCollectOrderBizOrigins);
}
@ -589,6 +605,11 @@ public class IoCollectOrderService extends ServiceImpl<IoCollectOrderMapper, IoC
collectOrderBizService.saveBatch(bizList);
}
}
} finally {
// 处理完成后,移除锁对象,释放内存
BILL_LOCKS.remove(billNo);
}
}
}
@ -820,7 +841,7 @@ public class IoCollectOrderService extends ServiceImpl<IoCollectOrderMapper, IoC
}
public Boolean decideOrder(CollectOrderRequest request, Long userId) {
//判断当前用户是否已经绑定工位
//判断当前用户是否已经绑定工位
SysWorkplace workplace = sysWorkplaceService.getWorkplaceByUser(request, userId);
if (workplace == null) {
throw new JsonException(500, "当前用户未绑定该工位");

@ -28,7 +28,7 @@ public class SyncHeartService {
//查询数据同步设置
pushData();
pushOrder();
pullData();
// pullData();
}
public void pushData() {

@ -4,9 +4,9 @@ server:
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
jdbc-url: jdbc:p6spy:mysql://192.168.0.206:3306/udiwms81?allowMultiQueries=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
jdbc-url: jdbc:p6spy:mysql://127.0.0.1:3306/udi_wms_ct?allowMultiQueries=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: Glxp@6066
password: 123456
hikari:
connection-timeout: 60000
maximum-pool-size: 20

Loading…
Cancel
Save