优化
This commit is contained in:
@@ -23,11 +23,10 @@ public class SimpleRequestMatcher {
|
|||||||
public String waitForResponse(int timeoutSeconds) {
|
public String waitForResponse(int timeoutSeconds) {
|
||||||
isWaiting = true;
|
isWaiting = true;
|
||||||
try {
|
try {
|
||||||
log.info("等待响应, 超时={}秒", timeoutSeconds);
|
|
||||||
// 从队列取响应,最多等待timeoutSeconds秒
|
// 从队列取响应,最多等待timeoutSeconds秒
|
||||||
String response = responseQueue.poll(timeoutSeconds, TimeUnit.SECONDS);
|
String response = responseQueue.poll(timeoutSeconds, TimeUnit.SECONDS);
|
||||||
|
log.info("waitForResponse-收到响应: {}", response);
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
log.info("收到响应: {}", response);
|
|
||||||
return response;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
log.error("等待响应超时");
|
log.error("等待响应超时");
|
||||||
@@ -46,10 +45,15 @@ public class SimpleRequestMatcher {
|
|||||||
*/
|
*/
|
||||||
public void handleResponse(String response) {
|
public void handleResponse(String response) {
|
||||||
try {
|
try {
|
||||||
|
log.info("开始处理响应: {}", response);
|
||||||
// 如果有请求在等待,把响应放入队列
|
// 如果有请求在等待,把响应放入队列
|
||||||
if (isWaiting) {
|
if (isWaiting) {
|
||||||
responseQueue.offer(response);
|
boolean offer = responseQueue.offer(response);
|
||||||
log.info("响应接收成功: {}", response);
|
if (offer) {
|
||||||
|
log.info("响应接收成功: {}", response);
|
||||||
|
} else {
|
||||||
|
log.error("响应队列已满, 响应被丢弃: {}", response);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn("没有正在等待的请求, 响应被丢弃: {}", response);
|
log.warn("没有正在等待的请求, 响应被丢弃: {}", response);
|
||||||
}
|
}
|
||||||
@@ -66,4 +70,4 @@ public class SimpleRequestMatcher {
|
|||||||
isWaiting = false;
|
isWaiting = false;
|
||||||
log.info("请求匹配器已清空");
|
log.info("请求匹配器已清空");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,14 +15,30 @@ public class TcpServerHandler extends SimpleChannelInboundHandler<String> {
|
|||||||
|
|
||||||
private ChannelManager getChannelManager() {
|
private ChannelManager getChannelManager() {
|
||||||
if (channelManager == null) {
|
if (channelManager == null) {
|
||||||
channelManager = SpringContextUtil.getBean(ChannelManager.class);
|
try {
|
||||||
|
channelManager = SpringContextUtil.getBean(ChannelManager.class);
|
||||||
|
log.info("ChannelManager获取成功: {}", channelManager);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("ChannelManager获取失败: ", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("ChannelManager已存在: {}", channelManager);
|
||||||
}
|
}
|
||||||
return channelManager;
|
return channelManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SimpleRequestMatcher getRequestMatcher() {
|
private SimpleRequestMatcher getRequestMatcher() {
|
||||||
if (requestMatcher == null) {
|
if (requestMatcher == null) {
|
||||||
requestMatcher = SpringContextUtil.getBean(SimpleRequestMatcher.class);
|
try {
|
||||||
|
requestMatcher = SpringContextUtil.getBean(SimpleRequestMatcher.class);
|
||||||
|
log.info("SimpleRequestMatcher获取成功: {}", requestMatcher);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("SimpleRequestMatcher获取失败:", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("SimpleRequestMatcher已存在: {}", requestMatcher);
|
||||||
}
|
}
|
||||||
return requestMatcher;
|
return requestMatcher;
|
||||||
}
|
}
|
||||||
@@ -34,21 +50,33 @@ public class TcpServerHandler extends SimpleChannelInboundHandler<String> {
|
|||||||
@Override
|
@Override
|
||||||
public void channelActive(ChannelHandlerContext ctx) {
|
public void channelActive(ChannelHandlerContext ctx) {
|
||||||
String clientId = getClientId(ctx);
|
String clientId = getClientId(ctx);
|
||||||
getChannelManager().addChannel(clientId, ctx.channel());
|
try {
|
||||||
log.info("✅ VM客户端连接成功: {}", clientId);
|
// 清空缓冲区,避免之前的消息残留
|
||||||
|
ctx.channel().read();
|
||||||
|
|
||||||
|
getChannelManager().addChannel(clientId, ctx.channel());
|
||||||
|
log.info("VM客户端连接成功: {}", clientId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理客户端连接失败: ", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) {
|
public void channelInactive(ChannelHandlerContext ctx) {
|
||||||
String clientId = getClientId(ctx);
|
String clientId = getClientId(ctx);
|
||||||
getChannelManager().removeChannel(clientId);
|
try {
|
||||||
log.info("❌ VM客户端断开连接: {}", clientId);
|
ChannelManager manager = getChannelManager();
|
||||||
|
manager.removeChannel(clientId);
|
||||||
|
log.info("VM客户端断开连接: {}", clientId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理客户端断开连接失败:", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
|
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
|
||||||
String clientId = getClientId(ctx);
|
String clientId = getClientId(ctx);
|
||||||
log.info("📥 收到VM数据 [{}]: {}", clientId, msg);
|
log.info("收到VM数据 [{}]: {}", clientId, msg);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 直接把收到的消息交给匹配器(不解析,不匹配)
|
// 直接把收到的消息交给匹配器(不解析,不匹配)
|
||||||
@@ -64,4 +92,4 @@ public class TcpServerHandler extends SimpleChannelInboundHandler<String> {
|
|||||||
log.error("连接异常: {}", cause.getMessage());
|
log.error("连接异常: {}", cause.getMessage());
|
||||||
ctx.close();
|
ctx.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,10 +60,11 @@ public class CommandService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ChannelManager channelManager;
|
private ChannelManager channelManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 001流程是执行保存图片到本地
|
||||||
|
*/
|
||||||
// @Scheduled(cron = "*/1 * * * * ?")
|
// @Scheduled(cron = "*/1 * * * * ?")
|
||||||
public void sendAndWait() {
|
public void sendAndWait() {
|
||||||
// 1. 检查连接
|
|
||||||
log.info("查询时间========");
|
|
||||||
Channel channel = channelManager.getFirstChannel();
|
Channel channel = channelManager.getFirstChannel();
|
||||||
channel.writeAndFlush("001");
|
channel.writeAndFlush("001");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,14 @@
|
|||||||
package top.wms.admin.controller.vm;
|
package top.wms.admin.controller.vm;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.x.file.storage.core.FileInfo;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.mock.web.MockMultipartFile;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import top.continew.starter.core.validation.CheckUtils;
|
import top.continew.starter.core.validation.CheckUtils;
|
||||||
import top.wms.admin.controller.tcp.config.SimpleRequestMatcher;
|
import top.wms.admin.controller.tcp.config.SimpleRequestMatcher;
|
||||||
import top.wms.admin.controller.tcp.manager.ChannelManager;
|
import top.wms.admin.controller.tcp.manager.ChannelManager;
|
||||||
import top.wms.admin.system.service.FileService;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@@ -34,128 +21,25 @@ public class VmCommandController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SimpleRequestMatcher requestMatcher;
|
private SimpleRequestMatcher requestMatcher;
|
||||||
|
|
||||||
@Autowired
|
@PostMapping("/send")
|
||||||
private FileService fileService;
|
public String sendAndWait(@RequestBody JSONObject js) {
|
||||||
|
String msg = js.getString("msg");
|
||||||
|
log.info("开始比对: {}", msg);
|
||||||
|
|
||||||
@GetMapping("/send")
|
|
||||||
public String sendAndWait(@RequestParam String msg) {
|
|
||||||
// 1. 检查连接
|
// 1. 检查连接
|
||||||
Channel channel = channelManager.getFirstChannel();
|
Channel channel = channelManager.getFirstChannel();
|
||||||
if (channel == null) {
|
if (channel == null) {
|
||||||
return "ERROR: VM未连接";
|
return "ERROR: VM未连接";
|
||||||
}
|
}
|
||||||
String sendMsg = msg;
|
// 2. 清空之前的响应队列,避免影响当前请求
|
||||||
channel.writeAndFlush(sendMsg);
|
requestMatcher.clear();
|
||||||
log.info("发送指令: {}", sendMsg);
|
channel.writeAndFlush(msg);
|
||||||
// 3. 等待响应
|
// 3. 等待响应
|
||||||
String response = requestMatcher.waitForResponse(20);
|
String response = requestMatcher.waitForResponse(20);
|
||||||
|
log.info("sendAndWait-收到响应: {}", response);
|
||||||
CheckUtils.throwIf("TIMEOUT".equals(response), "响应超时,请重试");
|
CheckUtils.throwIf("TIMEOUT".equals(response), "响应超时,请重试");
|
||||||
if (StrUtil.equals(response, "success") || StrUtil.equals(response, "failed")) {
|
CheckUtils.throwIf("ERROR".equals(response), "设备连接异常!");
|
||||||
return response;
|
return response;
|
||||||
}
|
|
||||||
if (StrUtil.equals(response, msg)) {
|
|
||||||
response = "success";
|
|
||||||
} else {
|
|
||||||
response = "failed";
|
|
||||||
}
|
|
||||||
// 4. 返回结果
|
|
||||||
return response; // 直接返回VM的响应
|
|
||||||
}
|
|
||||||
|
|
||||||
// 基础路径
|
|
||||||
private static final String BASE_PATH = "C:/Users/14725/Desktop/material";
|
|
||||||
|
|
||||||
// 固定照片名称
|
|
||||||
private static final String PHOTO_NAME = "001.bmp";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取最新的001.bmp照片
|
|
||||||
*
|
|
||||||
* @return 图片文件
|
|
||||||
*/
|
|
||||||
/*@GetMapping("/latest-photo")
|
|
||||||
public ResponseEntity<byte[]> getLatestPhoto() {
|
|
||||||
try {
|
|
||||||
// 获取当前日期
|
|
||||||
LocalDate now = LocalDate.now();
|
|
||||||
String yearMonth = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
|
|
||||||
String day = now.format(DateTimeFormatter.ofPattern("dd"));
|
|
||||||
|
|
||||||
// 构建完整的文件路径
|
|
||||||
// 格式: C:/Users/14725/Desktop/material/202603/20260312/001.bmp
|
|
||||||
String filePath = String.format("%s/%s/%s%s/%s", BASE_PATH, yearMonth, yearMonth, day, PHOTO_NAME);
|
|
||||||
|
|
||||||
// 读取图片文件
|
|
||||||
Path imagePath = Paths.get(filePath);
|
|
||||||
|
|
||||||
// 检查文件是否存在
|
|
||||||
if (!Files.exists(imagePath)) {
|
|
||||||
return ResponseEntity.notFound().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取文件字节
|
|
||||||
byte[] imageBytes = Files.readAllBytes(imagePath);
|
|
||||||
|
|
||||||
// 设置响应头
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.setContentType(MediaType.valueOf("image/bmp"));
|
|
||||||
headers.setContentLength(imageBytes.length);
|
|
||||||
|
|
||||||
// 返回图片
|
|
||||||
return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
@GetMapping("/latest-photo")
|
|
||||||
public String getLatestPhoto() {
|
|
||||||
try {
|
|
||||||
// 获取当前日期
|
|
||||||
LocalDate now = LocalDate.now();
|
|
||||||
String yearMonth = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
|
|
||||||
String day = now.format(DateTimeFormatter.ofPattern("dd"));
|
|
||||||
|
|
||||||
// 构建完整的本地文件路径
|
|
||||||
// 格式: C:/Users/14725/Desktop/material/202603/20260312/001.bmp
|
|
||||||
String filePath = String.format("%s/%s/%s%s/%s", BASE_PATH, yearMonth, yearMonth, day, PHOTO_NAME);
|
|
||||||
|
|
||||||
// 读取图片文件
|
|
||||||
Path imagePath = Paths.get(filePath);
|
|
||||||
|
|
||||||
// 检查文件是否存在
|
|
||||||
if (!Files.exists(imagePath)) {
|
|
||||||
return null; // 或者抛出异常,根据业务需求决定
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将文件转换为MultipartFile
|
|
||||||
File file = imagePath.toFile();
|
|
||||||
FileInputStream input = new FileInputStream(file);
|
|
||||||
MultipartFile multipartFile = new MockMultipartFile(file.getName(), // 文件名
|
|
||||||
file.getName(), // 原始文件名
|
|
||||||
"image/bmp", // 内容类型
|
|
||||||
input // 文件输入流
|
|
||||||
);
|
|
||||||
|
|
||||||
// 构建MinIO存储路径
|
|
||||||
String photoStoragePath = "catch" + DateUtil.today() + "/";
|
|
||||||
|
|
||||||
// 使用现有的fileService上传到MinIO
|
|
||||||
FileInfo fileInfo = fileService.upload(multipartFile, photoStoragePath, null, true, true);
|
|
||||||
|
|
||||||
// 检查上传结果
|
|
||||||
CheckUtils.throwIfNull(fileInfo, "照片上传失败");
|
|
||||||
|
|
||||||
// 关闭输入流
|
|
||||||
input.close();
|
|
||||||
return fileInfo.getUrl();
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException("处理图片失败: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user