From d923f6e0078192549f4b0fdfc62fa0befe4ec3a3 Mon Sep 17 00:00:00 2001 From: "HUOJIN\\92525" Date: Sat, 30 Aug 2025 09:52:23 +0800 Subject: [PATCH] no message --- .../service/impl/NioF3AppServiceImpl.java | 4 +- .../repository/AgvTaskRepository.java | 3 + .../businessdata/service/AgvTaskService.java | 7 + .../businessdata/service/LesService.java | 9 ++ .../service/impl/AgvTaskServiceImpl.java | 5 + .../service/impl/KMReServiceImpl.java | 31 ++-- .../service/impl/LesServiceImpl.java | 13 +- .../com/youchain/utils/PostRequestSigner.java | 144 ++++++++++++++++++ .../main/java/com/youchain/utils/UrlApi.java | 8 + .../EladminSystemApplicationTests.java | 54 +++++-- 10 files changed, 245 insertions(+), 33 deletions(-) create mode 100644 youchain-system/src/main/java/com/youchain/utils/PostRequestSigner.java 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 5bbcdbe..016d283 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,6 +15,7 @@ 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; @@ -245,7 +246,8 @@ public class NioF3AppServiceImpl implements NioF3AppService { } //回传LES - lesService.lesCallBack(les, lesService.lesCallBackJson(les.getDstPositionCode(), les.getTaskCode())); + String signe=""; + lesService.lesCallBack(les, lesService.lesSigneJson(UrlApi.app_id, signe)); } /** diff --git a/youchain-system/src/main/java/com/youchain/businessdata/repository/AgvTaskRepository.java b/youchain-system/src/main/java/com/youchain/businessdata/repository/AgvTaskRepository.java index a070a46..d9f78f8 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/repository/AgvTaskRepository.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/repository/AgvTaskRepository.java @@ -43,4 +43,7 @@ public interface AgvTaskRepository extends JpaRepository, JpaSpec @Query(value = "select count(agv.id) from AgvTask agv where agv.endSlotCode=:endSlotCode and agv.type=:type and agv.jobType=:jobType and agv.status in ('OPEN','ATCALL','UP_CONTAINER') ") Long findByEndSlotCode(String endSlotCode, String type, String jobType); + + @Query(value = "from AgvTask agv where agv.slotCode=:slotCode and agv.type='MOVE' and agv.jobType='TUGGER' and agv.status='ARRIVED' ") + AgvTask findBySlotCode(String slotCode); } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/AgvTaskService.java b/youchain-system/src/main/java/com/youchain/businessdata/service/AgvTaskService.java index 4c9b68c..6698cf6 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/AgvTaskService.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/AgvTaskService.java @@ -126,4 +126,11 @@ public interface AgvTaskService { */ Boolean findByEndSlotCode(String endSlotCode, String type, String jobType); + /** + * 根据途径点找到对应任务 + * @param slotCode 途径点 + * @return + */ + AgvTask findBySlotCode(String slotCode); + } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/LesService.java b/youchain-system/src/main/java/com/youchain/businessdata/service/LesService.java index bfec603..e2a8496 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/LesService.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/LesService.java @@ -83,6 +83,15 @@ public interface LesService { */ String lesCallBackJson(String currentPositionCode,String taskCode); + /** + * 签名json + * @param app_id 每个application或者service都会有一对app id 和 secret. + * @param signe 签名 + * @return json + */ + String lesSigneJson(String app_id, String signe); + + /** * LES任务回调 * @param les les diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AgvTaskServiceImpl.java b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AgvTaskServiceImpl.java index 3cae0a8..3521bdd 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AgvTaskServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/AgvTaskServiceImpl.java @@ -153,4 +153,9 @@ public class AgvTaskServiceImpl implements AgvTaskService { return agvTaskRepository.findByEndSlotCode(endSlotCode, type, jobType)>0; } + @Override + public AgvTask findBySlotCode(String slotCode) { + return agvTaskRepository.findBySlotCode(slotCode); + } + } diff --git a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/KMReServiceImpl.java b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/KMReServiceImpl.java index 190adcf..778f7cd 100644 --- a/youchain-system/src/main/java/com/youchain/businessdata/service/impl/KMReServiceImpl.java +++ b/youchain-system/src/main/java/com/youchain/businessdata/service/impl/KMReServiceImpl.java @@ -3,12 +3,14 @@ package com.youchain.businessdata.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.youchain.appupdate.request.BoxAndDolly; import com.youchain.basicdata.domain.Point; import com.youchain.basicdata.domain.Stock; import com.youchain.basicdata.service.PointService; import com.youchain.basicdata.service.StockService; import com.youchain.businessdata.domain.AgvTask; import com.youchain.businessdata.domain.Task; +import com.youchain.businessdata.inputJson.Dolly; import com.youchain.businessdata.inputJson.UpdateTuggerTrailerInfo; import com.youchain.businessdata.service.*; import com.youchain.exception.BadRequestException; @@ -472,18 +474,25 @@ public class KMReServiceImpl implements KMReService { if (CollectionUtils.isEmpty(updateTuggerTrailerInfo.getDollyList())) { throw new BadRequestException("器具必填"); } + //根据点位找到当前到站的AGV任务; + AgvTask agvTask = agvTaskService.findBySlotCode(updateTuggerTrailerInfo.getSrcPositionCode()); + if (agvTask == null) { + throw new BadRequestException(updateTuggerTrailerInfo.getSrcPositionCode() + "点未匹配到任务"); + } JSONObject jsonObject = new JSONObject(true); //请求 id String requestId = String.valueOf(System.currentTimeMillis()); jsonObject.put("requestId", requestId); //当前执行作业id - jsonObject.put("missionCode", requestId); + jsonObject.put("missionCode", agvTask.getId()); //当前执行任务的小车号 jsonObject.put("robotId", ""); //拖挂车数量 jsonObject.put("tugCount", updateTuggerTrailerInfo.getDollyList().size()); //拖挂车类型集 - jsonObject.put("tugModels", updateTuggerTrailerInfo.getDollyList()); + List tugModels = updateTuggerTrailerInfo.getDollyList().stream().map(Dolly::getDolly).collect(Collectors.toList()); + + jsonObject.put("tugModels", tugModels); //是否同步继续(放行)任务 jsonObject.put("resumeMission", true); return jsonObject.toString(); @@ -509,27 +518,11 @@ public class KMReServiceImpl implements KMReService { lesService.arrivedLes(agvTask.getId(), currentPosition); // 更新点位路径 - updateSlotCode(agvTask, currentPosition); + agvTask.setSlotCode(currentPosition); agvTask.setStatus(BizStatus.ARRIVED); agvTaskService.update(agvTask); } - private void updateSlotCode(AgvTask agvTask, String newPosition) { - String currentSlotCode = agvTask.getSlotCode(); - - // 处理空路径情况 - if (StringUtils.isEmpty(currentSlotCode)) { - agvTask.setSlotCode(newPosition); - return; - } - - // 使用 Set 快速检查重复点位 - Set existingPositions = new HashSet<>(Arrays.asList(currentSlotCode.split(","))); - if (!existingPositions.contains(newPosition)) { - agvTask.setSlotCode(currentSlotCode + "," + newPosition); - } - } - /** * 任务完成 * 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 50ad2ec..1a1ff2a 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 @@ -142,7 +142,7 @@ public class LesServiceImpl implements LesService { //请求 id jsonObject.put("guid", guid); //系统标识 - jsonObject.put("appId", "KUKA"); + jsonObject.put("appId", "wcs"); //请求时间 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); jsonObject.put("reqTime", sdf.format(new Date())); @@ -159,12 +159,23 @@ public class LesServiceImpl implements LesService { return jsonObject.toString(); } + @Override + public String lesSigneJson(String app_id, String signe) { + JSONObject jsonObject = new JSONObject(true); + jsonObject.put("app_id", app_id); + jsonObject.put("signe", signe); + jsonObject.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + jsonObject.put("hash_type", "sha256"); + return jsonObject.toString(); + } + @Override @Transactional(rollbackFor = Exception.class) public void lesCallBack(Les les, String json) { Dict dict = dictRepository.findDictByName("OPEN"); String resultJson = ""; if (dict != null) { + String url=""; resultJson = HttpPostUtil.sendPostReq(UrlApi.lesCallBack(), json); if (StringUtils.isEmpty(resultJson)) { throw new BadRequestException("LES返回信息:LES回传接口调用失败!"); diff --git a/youchain-system/src/main/java/com/youchain/utils/PostRequestSigner.java b/youchain-system/src/main/java/com/youchain/utils/PostRequestSigner.java new file mode 100644 index 0000000..bdf1a9c --- /dev/null +++ b/youchain-system/src/main/java/com/youchain/utils/PostRequestSigner.java @@ -0,0 +1,144 @@ +package com.youchain.utils; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; + + +public class PostRequestSigner { + + /** + * 生成POST请求的签名 + * + * @param host 请求域名(不包含端口号) + * @param path 请求路径 + * @param urlParams URL中的参数(不包含signe) + * @param jsonBody 请求体的JSON字符串 + * @param appSecret 应用密钥 + * @param accessToken 访问令牌(可为null) + * @return 生成的签名字符串(小写) + */ + public static String generateSign(String host, String path, Map urlParams, + String jsonBody, String appSecret, String accessToken) { + try { + // 1. 准备所有需要参与签名的参数 + Map allParams = new TreeMap<>(); // TreeMap会自动按key升序排序 + + // 添加URL参数(排除signe) + if (urlParams != null && !urlParams.isEmpty()) { + for (Map.Entry entry : urlParams.entrySet()) { + String key = entry.getKey(); + // 跳过signe参数 + if ("signe".equals(key)) { + continue; + } + allParams.put(key, entry.getValue() != null ? entry.getValue() : ""); + } + } + + // 添加JSON Body参数 + if (jsonBody != null && !jsonBody.isEmpty()) { + 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 + + // 如果有access_token,添加到签名字符串 + if (accessToken != null && !accessToken.isEmpty()) { + signSource.append(accessToken); + } + + // 4. 计算SHA256哈希并转为小写字符串 + return sha256(signSource.toString()); + + } catch (Exception e) { + throw new RuntimeException("生成签名失败: " + e.getMessage(), e); + } + } + + /** + * 计算字符串的SHA256哈希值 + * + * @param input 输入字符串 + * @return SHA256哈希的十六进制字符串(小写) + * @throws NoSuchAlgorithmException 如果SHA256算法不可用 + */ + private static String sha256(String input) throws NoSuchAlgorithmException { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8)); + + // 转为十六进制字符串 + StringBuilder hexString = new StringBuilder(); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + + private static String SignerUrl() { + try { + // 示例参数 + String host = "tsp-dev.nio.com"; + String path = "/api/1/infotainment/weather/now"; + String appId = "test_app_id"; + String appSecret = "test_app_secret"; + long timestamp = System.currentTimeMillis() / 1000; // Unix时间戳(秒) + + // URL参数(不包含signe) + Map urlParams = new HashMap<>(); + urlParams.put("app_id", appId); + urlParams.put("timestamp", String.valueOf(timestamp)); + urlParams.put("hash_type", "sha256"); + + // JSON请求体 + String jsonBody = "{\"location\":\"beijing\",\"language\":\"zh-CN\"}"; + + // 生成签名 + String sign = PostRequestSigner.generateSign(host, path, urlParams, jsonBody, appSecret, null); + System.out.println("生成的签名: " + sign); + + // 可以将签名添加到URL参数中,用于实际请求 + urlParams.put("signe", sign); + + // 构建完整的请求URL示例 + StringBuilder urlBuilder = new StringBuilder(); + urlBuilder.append("https://").append(host).append(path).append("?"); + for (Map.Entry entry : urlParams.entrySet()) { + urlBuilder.append(entry.getKey()).append("=") + .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name())).append("&"); + } + String requestUrl = urlBuilder.toString(); + if (requestUrl.endsWith("&")) { + requestUrl = requestUrl.substring(0, requestUrl.length() - 1); + } + System.out.println("完整请求URL: " + requestUrl); + return requestUrl; + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/youchain-system/src/main/java/com/youchain/utils/UrlApi.java b/youchain-system/src/main/java/com/youchain/utils/UrlApi.java index 1e3f51c..8e7f928 100644 --- a/youchain-system/src/main/java/com/youchain/utils/UrlApi.java +++ b/youchain-system/src/main/java/com/youchain/utils/UrlApi.java @@ -7,6 +7,14 @@ import lombok.extern.slf4j.Slf4j; public class UrlApi { private static final String URL_SUFFIX = "_url"; + public static final String app_id = "2000458"; + + public static final String app_secret_dev = "f65F67a8778b79bE7BcBEf49B3CE1214"; + + public static final String app_secret_prod = "0555d692e9176298D7D832fb10b99EAa"; + + + private static final RedisUtils redisUtils = SpringContextHolder.getBean(RedisUtils.class); private static final ApiDictServiceImpl apiDictServiceImpl = SpringContextHolder.getBean(ApiDictServiceImpl.class); diff --git a/youchain-system/src/test/java/com/youchain/EladminSystemApplicationTests.java b/youchain-system/src/test/java/com/youchain/EladminSystemApplicationTests.java index 0c5e568..043b862 100644 --- a/youchain-system/src/test/java/com/youchain/EladminSystemApplicationTests.java +++ b/youchain-system/src/test/java/com/youchain/EladminSystemApplicationTests.java @@ -2,19 +2,18 @@ package com.youchain; import cn.hutool.core.util.NumberUtil; import com.youchain.businessdata.domain.AgvTask; +import com.youchain.utils.PostRequestSigner; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; +import java.util.*; +import java.net.URLEncoder; +import java.io.UnsupportedEncodingException; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class EladminSystemApplicationTests { @@ -24,14 +23,45 @@ public class EladminSystemApplicationTests { } public static void main(String[] args) { - // 测试数据 - String orderDate1 = "2024/6/11"; - int months1 = 1; + try { + // 示例参数 + String host = "les-f3-api-stg.nioint.com"; + String path = "/api/intg/v1/kuka/task/report"; + String appId = "2000458"; + String appSecret = "f65F67a8778b79bE7BcBEf49B3CE1214"; + long timestamp = System.currentTimeMillis() / 1000; // Unix时间戳(秒) + // URL参数(不包含signe) + Map urlParams = new HashMap<>(); + urlParams.put("app_id", appId); + urlParams.put("timestamp", String.valueOf(timestamp)); + urlParams.put("hash_type", "sha256"); + // JSON请求体 + String jsonBody = "{\"location\":\"beijing\",\"language\":\"zh-CN\"}"; - // 调用方法并打印结果 - boolean isValid1 = isOrderDateValid3(orderDate1, months1); - System.out.println("订单日期 " + orderDate1 + " 是否有效: " + isValid1); + // 生成签名 + String sign = PostRequestSigner.generateSign(host, path, urlParams, jsonBody, appSecret, null); + System.out.println("生成的签名: " + sign); + + // 可以将签名添加到URL参数中,用于实际请求 + urlParams.put("signe", sign); + + // 构建完整的请求URL示例 + StringBuilder urlBuilder = new StringBuilder(); + urlBuilder.append("https://").append(host).append(path).append("?"); + for (Map.Entry entry : urlParams.entrySet()) { + urlBuilder.append(entry.getKey()).append("=") + .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name())).append("&"); + } + String requestUrl = urlBuilder.toString(); + if (requestUrl.endsWith("&")) { + requestUrl = requestUrl.substring(0, requestUrl.length() - 1); + } + System.out.println("完整请求URL: " + requestUrl); + + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } }