电子标签调试

This commit is contained in:
liuhanqing
2025-08-01 15:36:55 +08:00
parent 7885c45461
commit fd4f8f5521
12 changed files with 164 additions and 298 deletions

View File

@@ -279,12 +279,13 @@ public class MydoJobServiceImpl implements IMydoJobService {
outExceptionRecordParam.setWarehouseId(job.getWarehouseId());
List<OutExceptionRecord> outExceptionRecords = outExceptionRecordService.selectOutExceptionRecordList(outExceptionRecordParam);
for (MydoJobDetail mydoJobDetail : mydoJobDetails) {
//修改单据实际数量 物料入库 高架库入库
String inOrOutDId = mydoJobDetail.getInOrOutDId();
InStockinDetail inStockinDetail = inStockinDetailService.selectInStockinDetailByStockinDetailId(inOrOutDId);
inStockinDetail.setAssignNum(Convert.toStr(Convert.toBigDecimal(inStockinDetail.getAssignNum()).add(Convert.toBigDecimal(mydoJobDetail.getInQuantity()))));
inStockinDetailService.updateInStockinDetail(inStockinDetail);
if (job.getJobId().startsWith("RK")){
//修改单据实际数量 物料入库 高架库入库
String inOrOutDId = mydoJobDetail.getInOrOutDId();
InStockinDetail inStockinDetail = inStockinDetailService.selectInStockinDetailByStockinDetailId(inOrOutDId);
inStockinDetail.setAssignNum(Convert.toStr(Convert.toBigDecimal(inStockinDetail.getAssignNum()).add(Convert.toBigDecimal(mydoJobDetail.getInQuantity()))));
inStockinDetailService.updateInStockinDetail(inStockinDetail);
}
Optional<OutExceptionRecord> first = outExceptionRecords.stream().filter(x -> x.getTrayCode().equals(job.getTrayCode()) && x.getProductId().equals(mydoJobDetail.getProductId())).findFirst();
if (first.isPresent()) {

View File

@@ -69,4 +69,6 @@ public interface IOutStockoutService
public String updateOutStockoutStatus(String[] stockoutIds, String status,String newStatus,String exitId);
AjaxResult autoAllot(String stockoutId);
List<OutStockout> selectOutStockoutListApi(OutStockout outStockoutParam);
}

View File

@@ -187,4 +187,9 @@ public class OutStockoutServiceImpl implements IOutStockoutService
}
return AjaxResult.success();
}
@Override
public List<OutStockout> selectOutStockoutListApi(OutStockout outStockout) {
return outStockoutMapper.selectOutStockoutList(outStockout);
}
}

View File

@@ -1,5 +1,6 @@
package com.ruoyi.out.tagTask.controller;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
@@ -107,8 +108,8 @@ public class TagTaskController extends BaseController
/**
* 传入电子标签信息
*/
//@Scheduled(fixedDelay = 2000)
public void tagOutManager(){
@Scheduled(fixedDelay = 2000)
public void tagOutManager() throws IOException {
tagTaskService.tagOutManager();
}

View File

@@ -1,187 +0,0 @@
package com.ruoyi.out.tagTask.domain;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.ruoyi.out.tagTask.service.impl.TagTaskServiceImpl.byteArrayToHexString;
public class ExecuteSocket {
private Logger logger = LoggerFactory.getLogger(ExecuteSocket.class);
/**
* socket对象
*/
private Socket socket;
/**
* 连接超时时间,默认是10s
*/
private int connectTimeout = 10_000;
/**
* 接收数据超时时间,默认是10s
*/
private int receiveTimeout = 10_000;
/**
* socket的地址
*/
private InetSocketAddress socketAddress;
/**
* socket是否发生错误
*/
private AtomicBoolean socketError;
private String ip;
public ExecuteSocket(String ip, int port) {
this.socketError = new AtomicBoolean(false);//无并发,可用boolean代替
this.socketAddress = new InetSocketAddress(ip, port);
this.ip=ip;
logger.info("------------链接开始!------------");
}
// public ExecuteSocket() {
// this("127.0.0.1",3003);
// }
//连接校验
private boolean checkConnected() {
boolean b = !this.socketError.get() && this.socket != null && (socket.isConnected() && !socket.isClosed());
return b;
}
//关闭连接
public void close() {
try {
if (this.socket != null) {
//System.out.println("stock"+socket);
this.socket.close();
this.socket = null;
}
} catch (IOException e) {
//throw new SocketRuntimeException(e);
}
}
//获取连接,异常直接抛出
public Socket getAvailableSocket() throws Exception {
// 已连接的直接返回socket
if (this.checkConnected()) {
// System.out.println("长连接是否支持?"+this.socket.getKeepAlive());
return this.socket;
}
// 未连接,表示已断开,需要手动关闭socket,创建新的socket
this.close();
// 重新创建对象,并连接
this.socket = new Socket();
this.socket.setSoTimeout(1000);//6s
this.socket.connect(this.socketAddress, this.connectTimeout);
this.socketError.set(false);
//this.doAfterConnected();
logger.info("-------------ip:"+this.socketAddress+"重新连接--------------");
return socket;
}
/*
* 心跳
* */
public boolean writeHeart(String heartStr){
Socket socket = null;
try {
socket = this.getAvailableSocket();
} catch (Exception e) {
e.printStackTrace();
return false;
}
if(StringUtils.isBlank(heartStr)){
return false;
}
try {
OutputStream os = socket.getOutputStream();
os.write(heartStr.getBytes());
os.flush();
return true;
} catch (IOException e) {
e.printStackTrace();
logger.info("-------IP"+ip+"发送心跳异常---,["+e.getMessage()+"]---");
return false;
}
}
/*
* 写入数据
* */
public boolean writeData(byte[] bytes){
Socket socket = null;
try {
socket = this.getAvailableSocket();
} catch (Exception e) {
e.printStackTrace();
logger.info("-------写入数据异常,原因获取连接失败,【"+e.getMessage()+"】------");
return false;
}
try {
OutputStream os = socket.getOutputStream();
os.write(bytes);
os.flush();
return true;
} catch (IOException e) {
e.printStackTrace();
logger.info("-------写入数据异常-,【"+e.getMessage()+"】-----");
return false;
}
}
/*
* 读取
* */
public String readData() throws IOException {
Socket socket;
try {
socket = this.getAvailableSocket();//连接超时,抛异常
} catch (Exception e) {
//e.printStackTrace();
logger.info("-------IP"+ip+"获取连接失败---,【"+e.getMessage()+"】---");
return "";
}
InputStream is = null;
try {
is = socket.getInputStream();
int size = is.available();
byte[] bytes = new byte[size];
is.read(bytes);
String content = byteArrayToHexString(bytes, size);
return content;
} catch (IOException e) {
e.printStackTrace();
is.close();
return "";
}
}
}

View File

@@ -1,5 +1,6 @@
package com.ruoyi.out.tagTask.service;
import java.io.IOException;
import java.util.List;
import com.ruoyi.out.tagTask.domain.TagTask;
@@ -62,7 +63,7 @@ public interface ITagTaskService
/**
* 电子标签管理
*/
void tagOutManager();
void tagOutManager() throws IOException;
void tagInManager();
}

View File

@@ -1,10 +1,7 @@
package com.ruoyi.out.tagTask.service.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
@@ -20,7 +17,7 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.job.mydojob.domain.MydoJob;
import com.ruoyi.job.mydojob.service.IMydoJobService;
import com.ruoyi.out.tagTask.domain.ExecuteSocket;
import com.ruoyi.out.tagTask.util.ElectronicTagClient;
import com.ruoyi.pda.domain.TrayCodeMakeSure;
import com.ruoyi.pda.domain.TrayCodeMsg;
import com.ruoyi.pda.service.PdaService;
@@ -51,7 +48,7 @@ public class TagTaskServiceImpl implements ITagTaskService {
@Autowired
private IMydoJobService mydoJobService;
private HashMap<String, ExecuteSocket> tagSockteMap = new HashMap<>();
private HashMap<String, Socket> tagSockteMap = new HashMap<>();
/**
* 查询电子标签任务
@@ -120,7 +117,7 @@ public class TagTaskServiceImpl implements ITagTaskService {
}
@Override
public void tagOutManager() {
public void tagOutManager() throws IOException {
//查询所有的电子标签任务
TagTask tagTaskParam = new TagTask();
//tagTaskParam.setStatus("0");
@@ -161,7 +158,7 @@ public class TagTaskServiceImpl implements ITagTaskService {
TagTask tagTask = tagTaskList.get(0);
try {
boolean b = sendMsgDzbq(basTag,tagTask);
log.info("下发电子标签:ip:{},id:{}数量:{}", basTag.getIp(), basTag.getId(), basTag.getCurNum());
log.info("下发电子标签:ip:{},id:{}数量:{}", basTag.getIp(), basTag.getId(), tagTask.getNum());
if (b) {
basTag.setSendCompleted("1");
basTagService.updateBasTag(basTag);
@@ -170,7 +167,6 @@ public class TagTaskServiceImpl implements ITagTaskService {
log.info("下发电子标签:ip:" + basTag.getIp() + ",id:" + basTag.getId() + "数量:" + basTag.getCurNum());
} else {
sendMsgDzbq(basTag,tagTask);
//sendMsgDzbq( Integer.parseInt("1"), 0x02, 0x80, Integer.parseInt(tagTask.getFloor()), Integer.parseInt(tagTask.getNum()));
}
} catch (Exception e) {
log.info(e.getMessage(), e.getMessage());
@@ -193,13 +189,13 @@ public class TagTaskServiceImpl implements ITagTaskService {
Socket socket = getSocket(basTag);
try {
/** 接收电子标签指令 */
String content = readData(socket);//读取值
String content = ElectronicTagClient.receiveHexData(socket,3000);//读取值
if (!content.isEmpty()) {
log.info("读取电子标签值:" + content);
}
for (TagTask tagTask : tagGroup.get(tagId)) {
//将拍灯指令整理成数组
String[] split = content.split("5a");
String[] split = content.split("5A");
for (String s : split) {
if (s.length() == 10) {
String type = s.substring(4, 6);//指令类型 01是下发成功反馈 12是拍灭绿灯指令
@@ -235,7 +231,7 @@ public class TagTaskServiceImpl implements ITagTaskService {
Socket socket = getSocket(basTag);
try {
/** 接收电子标签指令 */
String content = readData(socket);//读取值
String content = null;//receiveResponse(socket);//读取值
if (!content.isEmpty()) {
log.info("读取电子标签值:" + content);
}
@@ -280,20 +276,11 @@ public class TagTaskServiceImpl implements ITagTaskService {
*/
private Socket getSocket(BasTag basTag) {
try {
if (tagSockteMap.containsKey(basTag.getPickAdd())) {
ExecuteSocket executeSocket = tagSockteMap.get(basTag.getPickAdd());
return executeSocket.getAvailableSocket();
} else {
ExecuteSocket executeSocket = new ExecuteSocket(basTag.getIp(), 0);
tagSockteMap.put(basTag.getPickAdd(), executeSocket);
return executeSocket.getAvailableSocket();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new RuntimeException("获取socket异常");
return new Socket(basTag.getIp(), 20108);
}catch (Exception e){
log.error(e.getMessage(),e);
}
return null;
}
/**
@@ -301,11 +288,11 @@ public class TagTaskServiceImpl implements ITagTaskService {
*
* @param basTag
*/
public boolean sendDzbqOff(BasTag basTag) {
public boolean sendDzbqOff(BasTag basTag) throws IOException {
int address = Convert.toInt(basTag.getId());
Socket socket = getSocket(basTag);
int x7 = (address + 0x10 + 0x03 + 0xe8 + 0x03 + 0xe8) % 256;//累加 校验
return sendMsgSocket( socket,"FA " + String.format("%02x", address) + " 10 00 03 e8 03 e8 " + String.format("%02x", x7) + " AF");
return ElectronicTagClient.sendHexData( socket,"FA " + String.format("%02x", address) + " 10 00 03 e8 03 e8 " + String.format("%02x", x7) + " AF");
}
@@ -315,79 +302,32 @@ public class TagTaskServiceImpl implements ITagTaskService {
* @param tagTask
* @return
*/
public boolean sendMsgDzbq( BasTag basTag ,TagTask tagTask) {
String green = String.format("%04x", Convert.toInt(tagTask.getNum()));
String red = String.format("%04x", 0);
String greenFirst2 = green.substring(0, 2);
String greenLast2 = green.substring(2);
String redFirst2 = red.substring(0, 2);
String redLast2 = red.substring(2);
Integer sid = Convert.toInt(basTag.getId());
int x3 = Integer.parseInt(greenFirst2, 16);//绿色数值
int x4 = Integer.parseInt(greenLast2, 16);//绿色数值
int x5 = Integer.parseInt(redFirst2, 16);//红色数值
int x6 = Integer.parseInt(redLast2, 16);//红色数值
int x7 = (sid + 0x02+0x80 + x3 + x4 + x5 + x6) % 256;//累加 校验
String value = "FA" + String.format("%02x", sid) + String.format("%02x", 0x02) + String.format("%02x", 0x80) + greenFirst2 +
greenLast2 + redFirst2 + redLast2 + String.format("%02x", x7) + "AF";
//boolean b = sendMsgSocket(getSocket(basTag), value);
log.info("电子标签{},发送指令{}",basTag.getId(), value);
return true;
public boolean sendMsgDzbq( BasTag basTag ,TagTask tagTask) throws IOException {
try (Socket socket = new Socket(basTag.getIp(), 20108)
){
socket.setSoTimeout(5000);
String green = String.format("%04x", Convert.toInt(tagTask.getNum()));
String red = String.format("%04x", 0);
String greenFirst2 = green.substring(0, 2);
String greenLast2 = green.substring(2);
String redFirst2 = red.substring(0, 2);
String redLast2 = red.substring(2);
Integer sid = Convert.toInt(basTag.getId());
int x3 = Integer.parseInt(greenFirst2, 16);//绿色数值
int x4 = Integer.parseInt(greenLast2, 16);//绿色数值
int x5 = Integer.parseInt(redFirst2, 16);//红色数值
int x6 = Integer.parseInt(redLast2, 16);//红色数值
int x7 = (sid + 0x02+0x80 + x3 + x4 + x5 + x6) % 256;//累加 校验
String value = "FA" + String.format("%02x", sid) + String.format("%02x", 0x02) + String.format("%02x", 0x80) + greenFirst2 +
greenLast2 + redFirst2 + redLast2 + String.format("%02x", x7) + "AF";
return ElectronicTagClient.sendHexData( socket,value);
}catch (Exception e){
log.error(e.getMessage(),e);
}
return false;
}
//todo 待调试 发送消息
public boolean sendMsgSocket(Socket socket,String msg) {
byte[] bytes = hexStringToByteArray(msg);
try(OutputStream os = socket.getOutputStream()) {
os.write(bytes);
os.flush();
return true;
} catch (IOException e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 16进制表示的字符串转换为字节数组
*
* @param hexString 16进制表示的字符串
* @return byte[] 字节数组
*/
public static byte[] hexStringToByteArray(String hexString) {
hexString = hexString.replaceAll(" ", "");
int len = hexString.length();
byte[] bytes = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
// 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个字节
bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character
.digit(hexString.charAt(i + 1), 16));
}
return bytes;
}
public static String byteArrayToHexString(byte b[], int len) {
StringBuilder resultSb = new StringBuilder();
for (int i = 0; i < len; i++) {
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}
/*
* 读取
* */
public String readData(Socket socket){
try (InputStream is = socket.getInputStream()){
int size = is.available();
byte[] bytes = new byte[size];
is.read(bytes);
return byteArrayToHexString(bytes, size);
} catch (IOException e) {
log.error(e.getMessage(), e);
return "";
}
}
}

View File

@@ -0,0 +1,95 @@
package com.ruoyi.out.tagTask.util;
import java.io.*;
import java.net.*;
import java.util.Arrays;
import java.util.HexFormat;
public class ElectronicTagClient {
public static void main(String[] args) {
final String SERVER_IP = "192.168.0.7";
final int SERVER_PORT = 20108;
final String hexData = "FA0111000001000114AF";
try (Socket socket = new Socket(SERVER_IP, SERVER_PORT)) {
System.out.println("成功连接到电子标签服务器: " + SERVER_IP + ":" + SERVER_PORT);
// 发送数据
sendHexData(socket, hexData);
// 接收响应(30秒超时)
String response = receiveHexData(socket, 30000);
System.out.println("收到响应: " + response);
} catch (SocketTimeoutException e) {
System.err.println("接收响应超时: " + e.getMessage());
} catch (IOException e) {
System.err.println("通信错误: " + e.getMessage());
} finally {
System.out.println("连接已关闭");
}
}
/**
* 发送16进制数据
* @param socket 已建立的Socket连接
* @param hexData 要发送的16进制字符串
* @throws IOException 如果发生I/O错误
*/
public static boolean sendHexData(Socket socket, String hexData) throws IOException {
hexData = hexData.replace(" ", "");
// 验证并处理奇数长度
if (hexData.length() % 2 != 0) {
System.out.println("警告:16进制字符串长度为奇数(" + hexData.length() + "),将在前面补0");
hexData = "0" + hexData;
}
byte[] sendBytes = hexStringToByteArray(hexData);
System.out.println("发送字节: " + Arrays.toString(sendBytes));
OutputStream output = socket.getOutputStream();
output.write(sendBytes);
output.flush();
return true;
}
/**
* 接收16进制响应数据
* @param socket 已建立的Socket连接
* @param timeoutMillis 超时时间(毫秒)
* @return 接收到的16进制字符串
* @throws IOException 如果发生I/O错误或超时
*/
public static String receiveHexData(Socket socket, int timeoutMillis) throws IOException {
socket.setSoTimeout(timeoutMillis);
InputStream input = socket.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] temp = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(temp)) != -1) {
buffer.write(temp, 0, bytesRead);
if (input.available() == 0) {
break; // 没有更多数据可读
}
}
byte[] responseBytes = buffer.toByteArray();
if (responseBytes.length == 0) {
return "无响应数据";
}
return byteArrayToHexString(responseBytes);
}
// 16进制字符串转字节数组
public static byte[] hexStringToByteArray(String hexString) {
return HexFormat.of().parseHex(hexString);
}
// 字节数组转16进制字符串
private static String byteArrayToHexString(byte[] bytes) {
return HexFormat.of().formatHex(bytes).toUpperCase();
}
}

View File

@@ -244,7 +244,7 @@ public class PdaServiceImp implements PdaService {
MydoJob mydoJobParam = new MydoJob();
mydoJobParam.setTrayCode(trayCodeMakeSure.getTrayCode());
// mydoJobParam.setStatus("3");
List<MydoJob> mydoJobList = mydoJobService.selectMydoJobList(mydoJobParam);
List<MydoJob> mydoJobList = mydoJobService.selectMydoJobListApi(mydoJobParam);
if (CollUtil.isEmpty(mydoJobList)) {
return AjaxResult.warn(MessageUtils.message("warn.message1"));
}
@@ -264,7 +264,7 @@ public class PdaServiceImp implements PdaService {
//获取单据类型
OutStockout outStockoutParam = new OutStockout();
outStockoutParam.setStockoutId(mydoJobDetails.get(0).getInOrOutId());
List<OutStockout> outStockouts = outStockoutService.selectOutStockoutList(outStockoutParam);
List<OutStockout> outStockouts = outStockoutService.selectOutStockoutListApi(outStockoutParam);
if (CollUtil.isEmpty(outStockouts)) {
return AjaxResult.warn(MessageUtils.message("warn.message4"));
}

View File

@@ -4,7 +4,7 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.pda.mapper.PdaMapper">
<select id="outMakeSure" parameterType="java.util.Map" statementType="CALLABLE">
{call proc_out_masksure(
{call proc_out_makesure(
#{v_tray_code,mode=IN,jdbcType=VARCHAR},
#{v_type,mode=IN,jdbcType=VARCHAR},
#{v_result,mode=OUT,jdbcType=INTEGER},
@@ -69,14 +69,14 @@
)}
</select>
<select id="checkMakeSure" parameterType="java.util.Map" statementType="CALLABLE">
{call proc_check_masksure(
{call proc_check_makesure(
#{v_tray_code,mode=IN,jdbcType=VARCHAR},
#{v_result,mode=OUT,jdbcType=INTEGER},
#{v_resultmsg,mode=OUT,jdbcType=VARCHAR}
)}
</select>
<select id="outMakeSureException" parameterType="java.util.Map" statementType="CALLABLE">
{call proc_out_masksure_exception(
{call proc_out_makesure_exception(
#{v_tray_code,mode=IN,jdbcType=VARCHAR},
#{v_type,mode=IN,jdbcType=VARCHAR},
#{v_result,mode=OUT,jdbcType=INTEGER},