no message
parent
fdf6ff967b
commit
d923f6e007
|
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -43,4 +43,7 @@ public interface AgvTaskRepository extends JpaRepository<AgvTask, Long>, 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,4 +126,11 @@ public interface AgvTaskService {
|
|||
*/
|
||||
Boolean findByEndSlotCode(String endSlotCode, String type, String jobType);
|
||||
|
||||
/**
|
||||
* 根据途径点找到对应任务
|
||||
* @param slotCode 途径点
|
||||
* @return
|
||||
*/
|
||||
AgvTask findBySlotCode(String slotCode);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String> 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<String> existingPositions = new HashSet<>(Arrays.asList(currentSlotCode.split(",")));
|
||||
if (!existingPositions.contains(newPosition)) {
|
||||
agvTask.setSlotCode(currentSlotCode + "," + newPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务完成
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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回传接口调用失败!");
|
||||
|
|
|
|||
|
|
@ -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<String, String> urlParams,
|
||||
String jsonBody, String appSecret, String accessToken) {
|
||||
try {
|
||||
// 1. 准备所有需要参与签名的参数
|
||||
Map<String, String> allParams = new TreeMap<>(); // TreeMap会自动按key升序排序
|
||||
|
||||
// 添加URL参数(排除signe)
|
||||
if (urlParams != null && !urlParams.isEmpty()) {
|
||||
for (Map.Entry<String, String> 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<String, String> 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<String, String> 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<String, String> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String, String> 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<String, String> 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue