diff --git a/youchain-common/src/main/java/com/youchain/exception/handler/ApiResult.java b/youchain-common/src/main/java/com/youchain/exception/handler/ApiResult.java index 6184dc0..569361f 100644 --- a/youchain-common/src/main/java/com/youchain/exception/handler/ApiResult.java +++ b/youchain-common/src/main/java/com/youchain/exception/handler/ApiResult.java @@ -14,7 +14,7 @@ public class ApiResult { } public static ApiResult fail(String msg) { - return result(400, msg, null); + return result(400, msg == null ? "操作失败!" : msg, null); } public static ApiResult success() { diff --git a/youchain-system/src/main/java/com/youchain/appupdate/rest/NioF3AppController.java b/youchain-system/src/main/java/com/youchain/appupdate/rest/NioF3AppController.java index 9871145..52a2be2 100644 --- a/youchain-system/src/main/java/com/youchain/appupdate/rest/NioF3AppController.java +++ b/youchain-system/src/main/java/com/youchain/appupdate/rest/NioF3AppController.java @@ -94,7 +94,7 @@ public class NioF3AppController { @AnonymousAccess public ResponseEntity updateTuggerTrailerInfo(@RequestBody UpdateTuggerTrailerInfo updateTuggerTrailerInfo) { try { - kmReService.sendAgvTaskToContainer(UrlApi.updateTuggerTrailerInfo(),kmReService.updateTuggerTrailerInfo(updateTuggerTrailerInfo)); + kmReService.sendAgvTaskToContainer(UrlApi.updateTuggerTrailerInfo(), kmReService.updateTuggerTrailerInfo(updateTuggerTrailerInfo)); return new ResponseEntity<>(ApiResult.success(), HttpStatus.OK); } catch (Exception e) { return new ResponseEntity<>(ApiResult.fail(e.getMessage()), HttpStatus.BAD_REQUEST); diff --git a/youchain-system/src/main/java/com/youchain/appupdate/service/impl/NioF3AppServiceImpl.java b/youchain-system/src/main/java/com/youchain/appupdate/service/impl/NioF3AppServiceImpl.java index 480895e..51d0685 100644 --- a/youchain-system/src/main/java/com/youchain/appupdate/service/impl/NioF3AppServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/appupdate/service/impl/NioF3AppServiceImpl.java @@ -15,7 +15,6 @@ import com.youchain.appupdate.response.LesTask; import com.youchain.businessdata.service.LesService; import com.youchain.exception.BadRequestException; import com.youchain.utils.BizStatus; -import com.youchain.utils.UrlApi; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -23,6 +22,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Slf4j @@ -35,6 +35,12 @@ public class NioF3AppServiceImpl implements NioF3AppService { private final AgvTaskService agvTaskService; private final KMReService kmReService; + private static final ConcurrentHashMap LOCK_MAP = new ConcurrentHashMap<>(); + + private String getLockKey(String srcPositionCode) { + return LOCK_MAP.computeIfAbsent(srcPositionCode, k -> k); + } + @Override @Transactional(rollbackFor = Exception.class) @@ -48,15 +54,10 @@ public class NioF3AppServiceImpl implements NioF3AppService { // 获取停靠点 String beatCode = getBeatCode(lesList); - AgvTask agvTask; - synchronized (bindSmall.getSrcPositionCode().intern()) { - // 验证起点是否有Agv任务 - validateAgvTask(bindSmall.getSrcPositionCode()); - // 生成任务 - agvTask = agvTaskService.createAgvTask(BizStatus.OPEN, null, bindSmall.getSrcPositionCode(), beatCode, "TUGGER"); - // 绑定任务 - bindLesAgvTask(agvTask.getId(), lesIds); - } + + //创建任务 + AgvTask agvTask=createAgvTask(bindSmall.getSrcPositionCode(), lesIds, beatCode); + // 下发任务 kmReService.sendAgvTask(agvTask, kmReService.sendAgvTaskQYCJson(agvTask, bindSmall.getShooter(), null)); } @@ -136,20 +137,27 @@ public class NioF3AppServiceImpl implements NioF3AppService { //获取目标点位 String beatCode = getBeatCode(lesList); - AgvTask agvTask; - synchronized (bindLarge.getSrcPositionCode().intern()) { - // 验证起点是否有Agv任务 - validateAgvTask(bindLarge.getSrcPositionCode()); - // 生成任务 - agvTask = agvTaskService.createAgvTask(BizStatus.OPEN, null, bindLarge.getSrcPositionCode(), beatCode, "TUGGER"); - // 绑定任务 - bindLesAgvTask(agvTask.getId(), lesIds); - } + //创建任务 + AgvTask agvTask = createAgvTask(bindLarge.getSrcPositionCode(), lesIds, beatCode); //下发任务 kmReService.sendAgvTask(agvTask, kmReService.sendAgvTaskQYCJson(agvTask, boxNos.size(), dollyList)); } + + public AgvTask createAgvTask(String srcPositionCode, List lesIds, String beatCode) { + String lockKey = getLockKey(srcPositionCode); + synchronized (lockKey) { + // 验证起点是否有Agv任务 + validateAgvTask(srcPositionCode); + // 生成任务 + AgvTask agvTask = agvTaskService.createAgvTask(BizStatus.OPEN, null, srcPositionCode, beatCode, "TUGGER"); + // 绑定任务 + bindLesAgvTask(agvTask.getId(), lesIds); + return agvTask; + } + } + /** * 验证参数 * @@ -223,7 +231,7 @@ public class NioF3AppServiceImpl implements NioF3AppService { public List findByLinePoint(String dstPositionCode) { List lesList = lesRepository.findByLinePoint(dstPositionCode); if (lesList.isEmpty()) { - throw new BadRequestException(dstPositionCode+"停靠点无任务"); + throw new BadRequestException(dstPositionCode + "停靠点无任务"); } return lesList; } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/repository/LesRepository.java b/youchain-system/src/main/java/com/youchain/businessdata/repository/LesRepository.java index 5fbbf8e..5ab7d65 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/repository/LesRepository.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/repository/LesRepository.java @@ -3,6 +3,7 @@ package com.youchain.businessdata.repository; import com.youchain.businessdata.domain.Les; import com.youchain.appupdate.response.LesTask; import org.springframework.data.jpa.repository.*; + import java.util.List; public interface LesRepository extends JpaRepository, JpaSpecificationExecutor { @@ -13,11 +14,11 @@ public interface LesRepository extends JpaRepository, JpaSpecificatio @Query(value = "from Les les where les.srcPositionCode=:srcPositionCode and les.onlineNo=:onlineNo and les.agvTaskId is null and les.status='OPEN' ") List findByOnlineNo(String srcPositionCode, String onlineNo); - @Query(value = "from Les les where les.agvTaskId=:agvTaskId and les.beatCode=:beatCode and les.status='OPEN' ") + @Query(value = "from Les les where les.agvTaskId=:agvTaskId and les.beatCode=:beatCode and les.status ='OPEN' ") List findByAgvTaskId(Long agvTaskId, String beatCode); @Query(value = "from Les les where les.srcPositionCode=:srcPositionCode and les.boxNo in (:boxNos) and les.agvTaskId is null and les.status='OPEN' ") - List findByBoxNoAndPoint(String srcPositionCode, List boxNos); + List findByBoxNoAndPoint(String srcPositionCode, List boxNos); @Query(value = "select " + "new com.youchain.appupdate.response.LesTask(les.id,les.onlineNo,les.createTime," + @@ -30,10 +31,10 @@ public interface LesRepository extends JpaRepository, JpaSpecificatio @Modifying @Query("update Les set agvTaskId = :agvTaskId where id in :ids") - void batchUpdateAgvTaskId(Long agvTaskId,List ids); + void batchUpdateAgvTaskId(Long agvTaskId, List ids); @Modifying @Query("update Les set status = :status,arrivedTime=now() where id in :lesIds") - void batchUpdateStatus(String status,List lesIds); + void batchUpdateStatus(String status, List lesIds); } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/LesServiceImpl.java b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/LesServiceImpl.java index 5654b72..19a5071 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/LesServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/LesServiceImpl.java @@ -20,7 +20,7 @@ import com.youchain.modules.system.repository.DictRepository; import com.youchain.utils.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -28,7 +28,6 @@ import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.sql.SQLIntegrityConstraintViolationException; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.*; @@ -110,7 +109,6 @@ public class LesServiceImpl implements LesService { } @Override - @Transactional(rollbackFor = Exception.class) public void genAgvSchedulingTask(LesRequest lesRequest) { //验证参数有效性 validateParams(lesRequest); @@ -128,8 +126,11 @@ public class LesServiceImpl implements LesService { if (StringUtils.isNotEmpty(materialCode)) { try { createLes(lesRequest, dstPoint); - } catch (Exception e) { + } catch (DataIntegrityViolationException e) { + // 数据库唯一约束冲突 throw new BadRequestException(taskCode + "任务号系统已接收,请勿重复操作"); + } catch (Exception e) { + throw new BadRequestException("创建任务失败:" + e.getMessage()); } } else { //直接转发给AGV @@ -198,7 +199,7 @@ public class LesServiceImpl implements LesService { String appId = jsonObject.getString("appId"); String appSecret = jsonObject.getString("appSecret"); - //json参数 + //jsonBody参数 String jsonBody = this.lesCallBackJson(les.getDstPositionCode(), les.getTaskCode()); //生成签名; diff --git a/youchain-system/src/main/java/com/youchain/utils/PostRequestSigner.java b/youchain-system/src/main/java/com/youchain/utils/PostRequestSigner.java index 750b6fc..7d65394 100644 --- a/youchain-system/src/main/java/com/youchain/utils/PostRequestSigner.java +++ b/youchain-system/src/main/java/com/youchain/utils/PostRequestSigner.java @@ -22,44 +22,41 @@ public class PostRequestSigner { * @param appSecret 应用密钥 * @return 生成的签名字符串(小写) */ - public static String generateSign(String host, String path, - String jsonBody, String appSecret) { + public static String generateSign(String host, String path, String jsonBody, String appSecret) { try { - // 1. 准备所有需要参与签名的参数 - Map allParams = new TreeMap<>(); // TreeMap会自动按key升序排序 - - // 添加JSON Body参数 - if (StringUtils.isNotBlank(jsonBody)) { - allParams.put("jsonBody", jsonBody); - } - - // 2. 拼接参数部分(key=value&key=value形式) - StringBuilder paramsStr = new StringBuilder(); - for (Map.Entry entry : allParams.entrySet()) { - if (paramsStr.length() > 0) { - paramsStr.append("&"); - } - paramsStr.append(entry.getKey()).append("=").append(entry.getValue()); - } - - // 3. 构建完整的签名字符串 - StringBuilder signSource = new StringBuilder(); - signSource.append(path) // PATH - .append("POST") // HTTP方法(大写) - .append(host) // Host - .append("?").append(paramsStr.toString()) // 参数部分 - .append(appSecret); // appSecret - - + // 1. 构建签名源字符串 + String signSource = buildSignSource(host, path, jsonBody, appSecret); log.info("签名生成: {}", signSource); - // 4. 计算SHA256哈希并转为小写字符串 - return sha256(signSource.toString()); + + // 2. 计算SHA256哈希 + return sha256(signSource); } catch (Exception e) { throw new BadRequestException("生成签名失败: " + e.getMessage()); } } + /** + * 构建签名源字符串 + */ + private static String buildSignSource(String host, String path, String jsonBody, String appSecret) { + + StringBuilder signSource = new StringBuilder(); + + signSource.append(path) + .append("POST") + .append(host); + + // 只有当jsonBody不为空时才添加参数部分 + if (StringUtils.isNotBlank(jsonBody)) { + signSource.append("?jsonBody=").append(jsonBody); + } + + signSource.append(appSecret); + + return signSource.toString(); + } + /** * 计算字符串的SHA256哈希值 *